Synthesis with the Sketch System DAY 1 Armando Solar-Lezama The Challenge Computer should help make programming easier Problem Programming requires insight and experience Computers are not that smart Interaction between programmers and tools is key The sketching approach Let the programmer control the implementation strategy Focus the synthesizer on the low-level details Key design principle: Exploit familiar programming concepts Example •You want to partition N elements over P procs How many elements should a processor get? N = 18 P=5 •Obvious answer is N/P •Obvious answer is wrong! Synthesizing a partition function •What do we know? The interface to the function we want Not all processors will get the same # of elements The kind of expressions we expect void partition(int if(p< {$ p, P, iend = {$ ibeg = {$ }else{ iend = {$ ibeg = {$ } } p, N, p, p, int P, int N, ref int ibeg, ref int iend){ N/P, N%P : *, + $} ){ P, N, N/P, N%P : *, + $}; P, N, N/P, P N%P : *, + N%P $}; N p, P, N,* N/P, + N%P : *, + $}; p N/P p, P, N, N/P, N%P : *, + $}; Synthesizing a partition function •How does the system know what a partition is? harness void testPartition(int p, int N, int P){ if(p>=P || P < 1){ return; } Partitions should be int ibeg, iend; balanced partition(p, P, N, ibeg, iend); assert iend - ibeg < (N/P) + 2; Adjacent partitions if(p+1 < P){ should match int ibeg2, iend2; partition(p+1, P, N, ibeg2, iend2); assert iend == ibeg2; } if(p==0){ assert ibeg == 0; } First and last if(p==P-1){ assert iend == N; } partition should go all the way to the ends } DEMO Solution void partition(int p, int P, int N, ref int ibeg, ref int iend){ if(p < (N % P)){ iend = ((N / P) + 1) * (1 + p); ibeg = p + ((N / P) * p); }else{ iend = ((N / P) * p) + ((N / P) + (N % P)); ibeg = (N % P) + ((N / P) * p); } } THE SKETCH LANGUAGE Sketch language basics •Sketches are programs with holes write what you know use holes for the rest Specifications •Idea: Programmers know how to write those •Two Use unit tests as specification mechanisms assertions assert x > y; function equivalence blockedMatMul(Mat a, Mat b) implements matMul Holes •Holes are placeholders for the synthesizer synthesizer replaces hole with concrete code fragment fragment must come from a set defined by the user Defining sets of code fragments is the key to Sketching effectively Language Design Strategy Extend base language with one construct Constant hole: ?? int bar (int x) { int t = x * ??; assert t == x + x; return t; } int bar (int x) { int t = x * 2; assert t == x + x; return t; } Synthesizer replaces ?? with a constant High-level constructs defined in terms of ?? Integer Holes Sets of Expressions •Expressions with ?? == sets of expressions linear expressions polynomials sets of variables x*?? + y*?? x*x*?? + x*?? + ?? ?? ? x : y Integer Holes Sets of Expressions •Example: Least Significant 0010 0101 0000 0010 Zero Bit int W = 32; bit[W] isolate0 (bit[W] x) { // W: word size bit[W] ret = 0; for (int i = 0; i < W; i++) if (!x[i]) { ret[i] = 1; return ret; } } •Trick: Adding 1 to a string of ones turns the next zero to a 1 i.e. 000111 + 1 = 001000 !(x + ??) & (x + ??) !(x + 1) & (x + 0) !(x + 1) & (x + 0xFFFF) !(x + 0) & (x + 1) !(x + 0xFFFF) & (x + 1) Integer Holes Sets of Expressions •Example: Least Significant Zero Bit 0010 0101 0000 0010 int W = 32; bit[W] isolate0 (bit[W] x) { // W: word size bit[W] ret = 0; for (int i = 0; i < W; i++) if (!x[i]) { ret[i] = 1; return ret; } bit[W] isolateSk (bit[W] x) implements isolate0 { return !(x + ??) & (x + ??) ; } } Integer Holes Sets of Expressions •Expressions linear expressions polynomials sets of variables •Semantically with ?? == sets of expressions x*?? + y*?? x*x*?? + x*?? + ?? ?? ? x : y powerful but syntactically clunky Regular Expressions are a more convenient Regular Expression Generators •{| RegExp |} •RegExp can be used arbitrarily within an expression - to select operands {| (x | y | z) + 1 |} - to select operators {| x (+ | -) y |} - to select fields {| n(.prev | .next)? |} - to select arguments {| foo( x | y, z) |} •Set supports choice ‘|’ and optional ‘?’ must respect the type system all expressions in the set must type-check all must be of the same type Sets of statements •Statements •Higher with holes = sets of statements level constructs for Statements too repeat bit[W] tmp=0; repeat(3){ {| x | tmp |} = {| (!)?((x | tmp) (& | +) (x | tmp | ??)) |}; } return tmp; repeat •Avoid copying and pasting repeat(n){ s} s;s;…s; n each of the n copies may resolve to a distinct stmt n can be a hole too. bit[W] tmp=0; repeat(??){ {| x | tmp |} = {| (!)?((x | tmp) (& | +) (x | tmp | ??)) |}; } return tmp; GENERATORS User defined generators •Mechanism •They to define sets of code fragments look like functions But with a few caveats Key features of generators •Different dynamic invocations different code • •Recursive generators = grammar of expressions generator bit[W] gen(bit[W] x, int bnd){ assert bnd > 0; if(??) return x; if(??) return ??; if(??) return ~gen(x, bnd-1); if(??){ return {| gen(x, bnd-1) (+ | & | ^) gen(x, bnd-1) |}; } } bit[W] isolate0sk (bit[W] x) return gen(x, 3); } implements isolate0 { CONSTRAINT BASED SYNTHESIS PRIMER Synthesis problem at the high level •Game theoretic view of synthesis For every move of the environment Synthesized program makes a counter move The challenge of synthesis •For functions, the environment controls the inputs i.e. whatever we synthesize must work for all inputs •Modeled with a doubly quantified constraint ∃ 𝑃 ∀ 𝑖𝑛 𝑖𝑛, 𝑃 ⊨ 𝑆𝑝𝑒𝑐 What does it mean to quantify over programs? Quantifying over programs •Synthesis as curve fitting we want a function that satisfies some properties •It’s hard to do curve fitting with arbitrary curves Instead, people use parameterized families of curves Quantify over parameters instead of over functions •A sketch is just a way of describing these families ∃ 𝑐 ∀ 𝑖𝑛 𝑖𝑛, 𝑆𝑘(𝑐) ⊨ 𝑆𝑝𝑒𝑐 ∃𝑐 ∀𝑖𝑛 𝑃(𝑖𝑛, 𝑐) Insight Sketches are not arbitrary constraint systems They express the high level structure of a program A small number of inputs can be enough focus on corner cases ∃𝑐 ∀𝑖𝑛 ∈ 𝐸 𝑄(𝑖𝑛, 𝑐) where E = {x1, x2, …, xk} This is an inductive synthesis problem ! 31 CEGIS Synthesize 𝒄 Insert your favorite ∃𝒊𝒏 𝒔. 𝒕. ¬𝑪𝒐𝒓𝒓𝒆𝒄𝒕(𝑷𝒄 , 𝒊𝒏𝒊 ) checker here ∃𝒄 𝒔. 𝒕. 𝑪𝒐𝒓𝒓𝒆𝒄𝒕(𝑷𝒄 , 𝒊𝒏𝒊 ) {𝒊𝒏𝒊 } Check 𝒊𝒏 CEGIS Synthesize 𝒄 Insert your favorite checker here ∃𝒄 𝒔. 𝒕. 𝑪𝒐𝒓𝒓𝒆𝒄𝒕(𝑷𝒄 , 𝒊𝒏𝒊 ) {𝒊𝒏𝒊 } •Constraints Check 𝒊𝒏 for each 𝒊𝒏𝒊 follow from semantics Loops handled through simple unrolling