program synthesis with sketching rastislav bodik uc berkeley

74
Program Synthesis with Sketching Rastislav Bodik UC Berkeley

Upload: virgil-richardson

Post on 28-Dec-2015

221 views

Category:

Documents


2 download

TRANSCRIPT

Program Synthesis with Sketching

Rastislav Bodik UC Berkeley

2

3

From Verification to Synthesis

Insight ImplementationMechanics

Validation

Done

Fix the mechanics

Fix the Insight

Synthesis

Two key problems

4

How to communicate insight?

How to synthesize the mechanics?

Our vision

What: Give the synthesis directly to programmersnot just to algorithm designers and compiler writers

How: Divide programming into insight and mechanicsHamming: People should think. Machines should work.

Corollaries:– Automatic: heed lessons from model checking vs.

deductive verification– Don’t rely too much on axiomatizing a domain:

algorithmic rather than deductive

5

Synthesis with Sketching

6

7

Key Observation

Insight and mechanics are both reflected in the source code, and can often be distinguished.

With sketching, the programmer ideally – writes only the code corresponding to insight– synthesizer produces the mechanics

int[] mergeSort (int[] input, int n) {if ( n == 1 ) return input;return merge( mergeSort (input[0:n/2-1]),

mergeSort (input[n/2:n-1]), n);}int[] merge (int[] a, int b[], int n) { int j=0; int k=0; for (int i = 0; i < n; i++) if ( a[j] < b[k] ) result[i] = a[j++]; else result[i] = b[k++]; return result;}

8

Merge sort: first, by hand

looks simple to code, but there is a bug

9

Merge sort: corrected, by handint[] mergeSort (int[] input, int n) {

if ( n == 1 ) return input;return merge( mergeSort (input[0:n/2-1]),

mergeSort (input[n/2:n-1]), n);}int[] merge (int[] a, int b[], int n) { int j=0; int k=0; for (int i = 0; i < n; i++) if ( j<n/2 && ( !(k<n-n/2) || a[j]<b[k]) ) result[i] = a[j++]; else result[i] = b[k++]; return result;}

10

Merge sort: sketchedint[] mergeSort (int[] input, int n) {

if ( n == 1 ) return input;return merge( mergeSort (input[0:n/2-1]),

mergeSort (input[n/2:n-1]), n);}int[] merge (int[] a, int b[], int n) { int j=0; int k=0; for (int i = 0; i < n; i++) if ( j<n/2 && ( !(k<n-n/2) || a[j]<b[k]) ) result[i] = a[j++]; else result[i] = b[k++]; return result;}

hole

11

The sketching experience

sketch implementation (completed sketch)

spec

specification

+

1212

Sketching synthesis is constraint solving

sketch(H) spec

13

int[] sort (int[] input, int n) { for (int i=0; i<n; ++i) for (int j=i+1; j<n; ++j) if (input[j] < input[i]) swap(input, j, i); return input;}

The spec: bubble sort

int[] mergeSort (int[] input, int n) {if ( n == 1 ) return input;return merge( mergeSort (input[0:n/2-1]),

mergeSort (input[n/2:n-1]), n);}int[] merge (int[] a, int b[], int n) { int j=0; int k=0; for (int i = 0; i < n; i++) if ( expr(<,&&,||,!,-,[])(a, b, j, k, n, n/2

) ) result[i] = a[j++]; else result[i] = b[k++]; return result;}

14

Merge sort: sketched

hole

and can help scalabilityand can help scalability

programmer controls the synthesized codeprogrammer controls the synthesized code

15

Merge sort: synthesizedint[] mergeSort (int[] input, int n) {

if ( n == 1 ) return input;return merge( mergeSort (input[0:n/2-1]),

mergeSort (input[n/2:n-1]), n);}int[] merge (int[] a, int b[], int n) { int j=0; int k=0; for (int i = 0; i < n; i++) if ( j<n/2 && ( !(k<n-n/2) || a[j]<b[k]) ) result[i] = a[j++]; else result[i] = b[k++]; return result;}

16

Deductive synthesis vs. Sketching

Spec

Spec

Axioms, Theorems, Rewrite rules

Deductive Synthesis [Burstall & Darlington ’76, … ]

Sketching

Implementation

=

Automated Validation

SketchImplementation

17

Example 2: a concurrent list data structure

The data structure:– linked list of Nodes– sorted by Node.key– with sentries at head and tail

The problem: implement a concurrent remove() method

c-∞ +∞ba

18

Thinking about the problem

Sequential remove ():

• Insight 1: for efficiency, use fine-grain locking– lock individual Nodes rather than the whole list

• Insight 2: Maintain a sliding window with two locks

c-∞ +∞ba

19

On to mechanics … ?

c-∞ +∞ba

20

Capture the insight in a sketch

#define comp {| ((cur|prev)(.next)? | null) (== | !=) ((cur|prev)(.next)? | null) |}#define loc {| {cur | prev | tprev) (.next)? |}

void Remove(int in){ Node cur = this.head, prev = null; lock({| cur(.next)? |}); while( cur.val < in){ Node tprev = prev; reorder { if(comp) lock( loc ); if(comp) unlock( loc ); prev = cur; cur = cur.next; } } if( cur.val == in ){ prev.next = cur.next; } unlock( {| cur(.next)? |} ); unlock( {| prev(.next)? |} );}

Under some conditions, lock and/or unlock memory locations.

And advance the sliding window.

And order the operations correctly.

Plausible conditions: equality/inequality of

“interesting” variables

Plausible memory locations:

“interesting” variables and fields

[Regular-expression generators: restricted regular

grammar of expression language]

21

SKETCH generates a correct program

void Remove(int in){ Node cur = this.head, prev = null; lock( cur ); while( cur.val < in){ Node tprev = prev; if(prev != null){ unlock(prev); } prev = cur; cur = cur.next; lock(cur); } if( cur.val == in ){ prev.next = cur.next; } unlock( cur ); unlock( prev );}

SKETCH finds correct conditionsand expressions

SKETCH ordersthese statements

correctly

The SKETCH Language

22

23

Language design goals

23

LearnableEmbed without confusion into an existing language

ExpressiveAllow programmer to express a range of insights about

holes

Induces a simple synthesis problemIdeally, permitting domain-independent synthesizers

24

SKETCH: two simple constructs

24

spec:

int foo (int x) { return x + x;}

sketch:

int bar (int x) implements foo { return x << ??;} result:

int bar (int x) implements foo { return x << 1;}

Assertions can also be used to state safety properties

2828

Beyond synthesis of constants

Sometimes the insight is “I want to complete the hole with an of particular syntactic form.”

– Array index expressions: A[ ??*i+??*j+?? ]

– Polynomial of degree 2 over x: ??*x*x + ??*x + ??

Primitive holes can be used synthesize arbitrary expressions, statements, …– we also can make these “generators” reusable

2929

Reusable expression generators

Following function synthesizes to one of a, b, a+b, a-b, a+b+a, …, a-a+b-b, …

inline int expr(int a, int b){ // generator

switch(??) {case 0: return a;case 1: return b;case 2: return expr(a,b) + expr(a,b);case 3: return expr(a,b) - expr(a,b);

} }

3030

Synthesizing polynomials

int spec (int x) {return 2*x*x*x*x + 3*x*x*x + 7*x*x + 10;

}

int p (int x) implements spec {return (x+1)*(x+2)*poly(3,x);

}

inline int poly(int n, int x) {if (n==0) return ??; else return x * poly(n-1, x) + ??;

}Here, SKETCH performs polynomial division. Result of division is what

poly(3,x) is synthesized into.

Notice the absence of

any meta-variables. The

generator poly() is an

ordinary function.

31

More Synthesis Constructs

Easy to add new constructs as syntactic sugar

reorder{ s1; s2; … ; sn; }

x = {| ( a | b | c )(.next)? |}

32

Counterexample-Guided Inductive Synthesis(CEGIS)

33

Candidate space

A sketch syntactically describes a set of candidate programs.– The ?? operator is modeled as a special input, called control:

Our goal is to find suitable control parameters – Can’t search naively as the candidate spaces are too large– 1sec/validation searching through 108 elements takes 3

years– our spaces are sometimes 10800

int f(int x) {… ?? … ?? …

}

int f(int x, int c1, c2) { … c1 … c2 …}

34

Sketch synthesis is constraint satisfaction

Synthesis reduces to solving this satisfiability problem – synthesized program is determined by c

Quantifier alternation is challenging. Our idea is to turn to inductive synthesis

34

spec(x) = sketch(x, c)c. x.

A E

37

CounterExample –Guided Inductive Synthesis

Inductive Synthesizer

buggy

candidate implementation

add a (bounded) counterexample input

succeed

fail

fail

observation set E

okverifier/checker

Your verifier/checker goes here

compute candidate implementation from concrete inputs.

The CEGIS algorithm:

Inductive synthesis step implemented with a SAT solver

Number of counterexample vs. log(C)

43

C = size of candidate space = exp(bits of controls)

4444log(C)

Number of counterexample vs. log(C)C = size of candidate space = exp(bits of controls)

C = 102400C = 102400

46

Selected benchmarks

Benchmark control bits solution time

AES 32769 bits 15 min

SSE Matrix Transpose 24 ints + 64 bits 20 min

CRC 8192 bits 13.5 min

Doubly Linked List Remove

60 bits < 1 sec

Enqueue 271 int & bit 1 min

16 bit Morton Numbers 332 int & bit 20 min

32 bit fast parity 45 bits 11 sec

Sort (bounded) 363 int & bit 3.5 min

Synthesis for Infinite Programs [PLDI 2007]

By default, synthesizer finitizes the sketch, reducing to SAT– unrolls loops, recursion, and turns programs into circuits

For a class of non-finite programs, we use semantic reduction– both spec and sketch are reduced into bounded SKETCH programs

f(int[N]):int[N] f(int, int[4]):int

– the reduction computes a symbolic slice of the program – without loss of precision: all holes are preserved; complete, sound

Case study: stencils (structured grid computations)– synthesized complex 3D stencil kernels [PLDI 2007]

Admittedly, the reduction is a domain theory– but it’s a simple procedure, works for a whole class of programs– it embeds no insight about implementation tricks

Plus, the reduction itself might be sketchable

47

48

Synthesis of concurrent programs [PLDI 2008]

Counterexamples are multi-threaded traces, not inputs

Problem: a trace is relevant only to the program it came from

Solution: Trace Projection tP ⊳ P’

Desired property:– if P’ shares the bug exposed in P by tp

then tp ⊳ P’ should expose that bug too

– allows inductive synthesis through constraint solving

Trace on program P

Trace on program P’

49

Inductive Synthesis from TracesSequential programs

Concurrent programs

safe( Sk[c](xi) )c. xi in E.

A E

where E = {x1, x2, …, xk}

safe( tci ⊳ (Sk[c]) )c. tci in T.

A E

where T = {tc1, tc2, …, tck}

safe( (tci ⊳ Sk)[c] )c. tci in T.

A E

where T = {tc1, tc2, …, tck}

Bibliography

PLDI 2005: bitvector streaming programs– deductive synthesis with sketching in rewrite rules

ASPLOS 2006: bounded programs (crypto etc)– algorithmic synthesis

PLDI 2007: stencils (aka structured grids)– full behavioral verification– via reduction from unbounded domain to an bounded one

PLDI 2008: concurrent programs– safety properties, bounded checking (bounded ops, threads)– using the SPIN model checker

50

Summary

Programming the synthesizer: domain theory vs. sketch– hypothesis: insight is syntactic, exists in the program– sketch is a syntactic description of candidate space

Algorithmic synthesis vs. deductive synthesis – akin to model checking vs. deductive verification– applies to: finite and finitized programs; programs with domain

reductions

CEGIS: counterexample-guided inductive synthesis – inductive synthesis simplifies the exists/forall problem– CEGIS takes advantage of efficient decision procedures,

in both inductive synthesis and in counterexample generation51

52

Credits

Students– Gilad Arnold– Chris Jones (Mozilla)– Joel Galenson– Lexin Shan– Liviu Tancau (Google)– Armando Solar-Lezama

(MIT)

Professors– Bob Brayton– Koushik Sen– Sanjit Seshia

Other Collaborators– Satish Chandra (IBM)– Kemal Ebcioglu (IBM)– Alan Mischenko (UCB)– Rodric Rabbah (IBM)– Mooly Sagiv (Tel Aviv)– Vijay Saraswat (IBM)– Vivek Sarkar (Rice)– Martin Vechev (IBM)– Eran Yahav (IBM)

Some History: Deductive SynthesisTwo kinds. In both, synthesis is a search for a suitable

derivation.

Transformational: domain theory transforms a specification program with a sequence of transformations, producing an optimized program. Ex: FFTW, Spiral, Denali.

Prover-based: specification is a theorem; the synthesized program is obtained from the (constructive) proof of the theorem. Ex: KIDS, NuPrl, Manna-Waldinger.

Notable industrial successes: FFTW, SPIRAL, KIDS

54

Domain Theory

Communicates to synthesizer the human insight about the domain. It must say enough to enable derivation of the program. Its development requires expertise and time.

Examples of domain theory fragments:

SPIRAL Cooley/Tukey FFT:

DFT4 = (DFT2 I2) T42 (I2 DFT2) L4

2

KIDS divide and conquer:

Dec(x0,x1,x2) O(x1,z1) O(x2,z2) Compose(z0,z1,z2) O(x0,z0)55

Some challenges in deductive synthesis

Domain theory – debugging: is the theory correct, complete?– generality: can it generate programs of interest?– accessibility to programmers: can one

broaden the theory?

Control over synthesized code– how to coax the synthesizer to include a particular

trick?

56

Algorithmic Synthesis?

Instead of deriving a program, can we search for a correct program in a space of candidate programs?

This is analogous to the model checking approach to verification: rather than obtaining a proof of correctness, model checking algorithmically explores the state space.

All we need is a checker of program correctness and a description of the candidate space.

In situations that mirror model checking (finite state; domain reductions), we sidestep the need for a domain theory.

58

59

A stencil: spec

void sten1d (float[4,N] X) { for (int t=1; t<4; ++t) for (int i=1; i<N-1; ++i) X[t, i] = X[t-1, i-1] + X[t-1, i+1];}

it

60

Fast implementation

void sten1dSK (float[4,N] X) { assume ( N >= 3 ) for (int i= 0; i<4 ; ++i) for (int t=1; t<i ; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=4; i<N; ++i) for (int t=1; t<4; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=N; i<N+4; ++i) for (int t=i-N+2; t<4; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];}

it

61

void sten1dSK (float[4,N] X) { assume ( N >= 3 ); for (int i= 0; i<4 ; ++i) for (int t=1; t<i ; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=4; i<N; ++i) for (int t=1; t<4; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=N; i<N+4; ++i) for (int t=i-N+2; t<4; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];}

What are the hard fragments?

it

62

void sten1dSK (float[4,N] X) { assume ( N >= 3 ); for (int i= ; i<4 ; ++i) for (int t=; t< ; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=; i<; ++i) for (int t=; t<; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=; i<4; ++i) for (int t=i; t<; ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];}

Sketch the hard fragments

it

63

The final sketch

void sten1dSK (float[4,N] X) implements sten1d { assume ( N >= 3 ); for (int i=linexpG(N, 4); i<linexpG(N, 4); ++i) for (int t=linexpG(N, 4, i); t<linexpG(N, 4, i); ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=linexpG(N, 4); i<linexpG(N, 4); ++i) for (int t=linexpG(N, 4, i); t<linexpG(N, 4, i); ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];

for (int i=linexpG(N, 4); i<linexpG(N, 4); ++i) for (int t=linexpG(N, 4, i); t<linexpG(N, 4, i); ++t) X[t, i-t] = X[t-1, i-1-t] + X[t-1, i+1-t];}

66

Concurrent synthesis

Counterexamples are multi-threaded traces not inputs

Problem: a trace is relevant only to the program it came from

Solution: Trace Projection tp ⊳ P’

Desired property:– if P’ shares the bug exposed in P by tp

then tp ⊳ P’ should expose that bug too

– allows inductive synthesis through constraint solving

Trace on program P

Trace on program P’

67

Inductive Synthesis from TracesSequentially

Concurrently

safe( Sk[c](xi) )c. xi in E.

A E

where E = {x1, x2, …, xk}

safe( tci ⊳ (Sk[c]) )c. tci in T.

A E

where T = {tc1, tc2, …, tck}

safe( (tci ⊳ Sk)[c] )c. tci in T.

A E

where T = {tc1, tc2, …, tck}

Bibliography

PLDI 2005: bitvector streaming programs– deductive synthesis with sketching in rewrite rules

ASPLOS 2006: bounded programs (crypto etc)– algorithmic synthesis

PLDI 2007: stencils (aka structured grids)– full behavioral verification– via reduction from unbounded domain to an bounded one

PLDI 2008: concurrent programs– safety properties, bounded checking (bounded ops, threads)– using the SPIN model checker

69

Summary

Algorithmic synthesis vs. deductive synthesis – akin to model checking vs. deductive verification– applies to: finite and finitized programs; unbounded programs

with domain reductions

Programming the synthesizer: domain theory vs. sketch– hypothesis: insight is syntactic, exists in the program– sketch is a syntactic description of candidate space

CEGIS: counterexample-guided inductive synthesis – inductive synthesis simplifies the exists/forall problem– CEGIS takes advantage of efficient decision procedures,

in both inductive synthesis and in counterexample creation

70

The two key problems, still open

How to communicate insight to a synthesizer

How to use a verifier/checker for synthesis

71

72

Concurrency

What is sketchin

g SKETCH Synthesis Algorithm

SKETCH Language Concurren

cyFuture Work

73

class Queue { QueueEntry prevHead = new QueueEntry(null); QueueEntry tail = prevHead;

void Enqueue(Object newobject) { Node tmp = null; newEntry = new QueueEntry(newobject); reorder{ tmp.next = newEntry ; tmp = AtomicSwap(tail , newEntry ); } }}

Works for concurrent programs tooEx: Concurrent Enqueue

using AtomicSwap

Object AtomicSwap(ref Object loc, Object entry) atomic { Object old = loc; loc = entry; return old;}

class Queue { QueueEntry prevHead = new QueueEntry(null); QueueEntry tail = prevHead;

void Enqueue(Object newobject) { Node tmp = null; newEntry = new QueueEntry(newobject);

tmp = AtomicSwap(tail , newEntry ); tmp.next = newEntry ;

}}

Concurrency (PLDI 2008)

How to use traces (schedules) as observations?

For effective pruning, counterexample should apply to all candidates as much as possible

But candidates have different set of atomic statements

Solution: program representation that preserves ordering of statements common to a trace (or aborts the trace)

74

Summary

ASPLOS 2006: bounded programs (crypto etc)– full behavioral verification

PLDI 2007: stencils (aka structured grids)– full behavioral verification– via reduction from unbounded domain to an

bounded one

PLDI 2008: concurrent programs– safety properties, bounded checking (bounded ops,

threads)– using SPIN

75

Future work

• Dynamic synthesis– CUTE as checker– a new dynamic synthesizer

• Replace counterexample-guided inductive synthesis with abstract interpreter– sketching and synthesis of abstractions?

76

77

class Queue { QueueEntry prevHead = new QueueEntry(null); QueueEntry tail = prevHead;

void Enqueue(Object newobject) { Node tmp = null; newEntry = new QueueEntry(newobject); reorder{ tmp.next = newEntry ; tmp = AtomicSwap(tail , newEntry ); } }}

Concurrent programs

Ex: Concurrent Enqueue using AtomicSwap

Object AtomicSwap(ref Object loc, Object entry) atomic { Object old = loc; loc = entry; return old;}

class Queue { QueueEntry prevHead = new QueueEntry(null); QueueEntry tail = prevHead;

void Enqueue(Object newobject) { Node tmp = null; newEntry = new QueueEntry(newobject);

tmp = AtomicSwap(tail , newEntry ); tmp.next = newEntry ;

}}

prevHead tail newEntrytmp newEntrytailprevHead newEntry

78

Generalization to Parallelism

Output now dependent on thread interleaving– Make interleaving schedule part of the

observations– Most verifiers can provide a counterexample

trace

Using the observations becomes harder– Schedule generated as witness for a given

candidate– How do we use it to rule out other incorrect

candidates?

79

Representation pitfalls

x = 5;fork(2, i){ if(??) t = 5; int l = x; x = l + 1; if(?? && i == 0){ l = x; x = x + 1; }}assert x = x + 1 || x = x+2;

x = 5;fork(2, i){

int l = x; x = l + 1; if(i == 0){ l = x; x = l + 1; }}assert x = x + 1 || x = x+2;

s0:s1:s2:

s3:s4:

s1: l=x

s2: x=l + 1

s3: l=x

s4: x=l + 1

s1: l=x

s2: x=l + 1

Thread i=1 Thread i=2

1

1

2

2

1

1

80

Representation pitfalls

x = 5;fork(2, i){ if(??) t = 5; int l = x; x = l + 1; if(?? && i == 0){ l = x; x = x + 1; }}assert x = x + 1 || x = x+2;

s0:s1:s2:

s3:s4:

x = 5;fork(2, i){ t = 5; int l = x; x = l + 1; if( i == 0){ l = x; x = l + 1; }}assert x = x + 1 || x = x+2;

s0: t=5

s0: t=5

s1: l=x

s2: x=l + 1

s3: l=x

s4: x=l + 1

s1: l=x

s2: x=l + 1

Thread i=1 Thread i=2

1

1

2

2

1

1

81

Define observation in terms of dataflowObservation must eliminate all candidates with

the same bug

Identify dataflow that lead to assertion failure– the dataflow defines the bug

Observation defined in terms of buggy dataflow

82

We have synthesized…

Benchmark Observations

Solution Time

Lock Free linked list enqueue

2 540 sec.

Lock Free linked list dequeue

2 194 sec.

Herlihy’s hand-over-hand set remove()

5 325 sec.

doubly linked list add()

2 245 sec.

– Most of the time was spent on the final verification.– Expect these numbers to be much better in the final PLDI

paper.

83

Future Work

What is sketchin

g SKETCH Synthesis Algorithm

SKETCH Language Concurren

cyFuture Work

84

Domain Specific Insight

Sketching allows users to provide their own insight– insight is specific to individual program

What if we have general insight about a specific domain– can we incorporate it into the solver– maintain the ability to write sketches

sketch => instance specific insightspecialized synthesizer => domain specific insight

We’ve done this already for the domain of Stencils (PLDI 07)

85

Specialization through problem reduction

Encode Domain specific insight as a transformation

Such that– T[spec] = T[sketch](c) spec = sketch(c) for all c– T[spec] = T[sketch](c) is a simpler problem to solve

• for stencils T[spec] and T[sketc] don’t have loops• they are easier to handle by the SAT based verifier

The key idea

spec = sketch(c)

T : (f: in out) (f’: in out)

86

Future work: Generalize

Reduction Strategy worked great for stencils

Can we generalize it to other domains– sketches for advanced architectures (CELL,

GPU)– more scientific computation

Can we make it more flexible– can we sketch these reductions– need a formal framework for reasoning about

them

87

Programmer Feedback

We haven’t solved the problem of programmer feedback– What happens when the insight is wrong– Can’t debug like a regular program

We are left with– Set of witnesses– An UNSAT core

Spec(x) = Sk(x,c)c. x in E.A E

where E = {x1, x2, …, xk}

88

Programmer Feedback

Can we minimize the set of witnesses?

Can we use the UNSAT core to explain error to the human?

What kind of feedback would be more useful for a human?

89

Sketching for a 1,000,000 line programScenario:

“ You have a 1M line program, and there is one routine that modifies the heap and which you

have to rewrite so its more efficient, but the program must still work”

Can we sketch such modifications

How do we derive the right specification

How do we handle the rest of the program without analyzing all of it

Questions?