Program synthesis with Jennisys
310 likes | 444 Views
Program synthesis with Jennisys. K. Rustan M. Leino Research in Software Engineering ( RiSE ), Microsoft Research, Redmond Aleksandar Milicevic MIT. IFIP Working Group 2.3 meeting Winchester, UK 22 September 2011. Post-mortem verification. Forward-looking design. Verification. Test.
Program synthesis with Jennisys
E N D
Presentation Transcript
Program synthesis with Jennisys K. Rustan M. Leino Research in Software Engineering (RiSE), Microsoft Research, Redmond Aleksandar Milicevic MIT IFIP Working Group 2.3 meeting Winchester, UK 22 September 2011
Post-mortem verification Forward-looking design Verification Test Code Idea Timeline Ouch! Need specifications
More help during software design • More expressive languages • Refinement • Synthesis • …
Jennisys This is where programs begin
Jennisys programs • Each type has: • Public interface • Data model • Code
Example: Public interface interfaceExtensibleArray[T] { varContents:seq[T] constructorInit() Contents := [] method Get(i) returns (t) requires0 <= i && i < |Contents| t := Contents[i] method Set(i, t) requires0 <= i && i < |Contents| Contents := Contents[i := t] methodAppend(t) Contents := Contents + [t] }
ExtensibleArray data structure Append( ) Extensible-Array[T] .elements
ExtensibleArray data structure Append( ) Extensible-Array[T] .elements
ExtensibleArray data structure Append( ) Extensible-Array[T] .elements
ExtensibleArray data structure Append( ) Extensible-Array[T] .elements .more
ExtensibleArray data structure Extensible-Array[T] .elements .more ExtensibleArray[array[T]]
Example: Data structure design datamodelExtensibleArray[T] { varelements: array[T] varmore: ExtensibleArray[array[T]] frame elements, more, more.Contents[*] invariant elements.Length = 256 256 < |Contents| ==> more != null more.Contents[*].Length = 256 val M = if more = nullthen0else256 * |more.Contents| Contents[i] = elements[i – M] where i in M <= i Contents[i] = more.Contents[i / 256][i % 256] whereiini < M }
Example: Data structure design Can all operations be implemented with this design? datamodelExtensibleArray<T> { varelements: array<T> varmore: ExtensibleArray<array<T>>? frame elements, more, more.Contents[*] invariant elements.Length = 256 256 < |Contents| ==> more != null more.Contents[*].Length = 256 val M = ifmore = nullthen0else256 * |more.Contents| Contents[i] = elements[i – M] where i in M <= i Contents[i] = more.Contents[i / 256][i % 256] whereiini < M }
Example: Data structure design datamodelExtensibleArray<T> { varelements: array<T> varmore: ExtensibleArray<array<T>>? frame elements, more, more.Contents[*] invariant elements.Length = 256 256 < |Contents| ==> more != null more.Contents[*].Length = 256 val M = if more = nullthen0else256 * |more.Contents| Contents[i] = elements[i – M] where i in M <= i Contents[i] = more.Contents[i / 256][i % 256] whereiini < M } Is this good? |Contents| = 5 more ≠ null |more.Contents| = 100
Example: Implementation Code is generated from public interface and data model codeExtensibleArray[T] { } • Code generated automatically • Programmer supplies hints • E.g., “loop n”, “e[n] := t” • Programmer uses sketches, holes[Bodik, Solar-Lezama, …] • As last resort, code is written manually
Jennisys, abstractly interface T { var a constructorInit() S(a) } datamodel T { var c invariant R(a, c) }
Jennisys, abstractly interface T { var a constructorInit() a := E } datamodel T { var c invariant R(a, c) }
Synthesis basics:Constraint solving interface T { var a constructorInit() a := E } var a, c a := E c :[ R(a, c) ] datamodel T { var c invariant R(a, c) } constraint solve to find feasible a,c here
Synthesis basics:Constraint solving interface T { var a constructorInit() a := E } var a, c a := E assume R(a, c) assert false datamodel T { var c invariant R(a, c) } attempt to verify and look at resulting counterexample model
Demo a := 0 with a = c a := 0 with a = c+d
Extrapolation interface T { var a constructorInit(p) a := E(p) } Constraint solving gives possible values for a,p,c From this, we want to extrapolate a value for c in terms of p datamodel T { var c invariant R(a, c) }
Extrapolation: Example interface T { var a constructorInit(p) a := p } Sample values:a=7, p=7, c=7 Match up c with p datamodel T { var c invariant a = c }
Custom spec evaluation interface T { var a constructorInit(p,q) a := {p + q} } Partially evaluate spec with the sample values for non-parameters Match things up datamodel T { var c invariant a = {c} } a={7}, p=3, q=4, c=7 {7} = {p+q}, {7} = {7}
Demo a := p+q with a = c a := {p+q} with a = {c}
Program extrapolation, so far • Constraint solving: get sample values • Partial evaluation: simplify spec using samples values • Unification: match things up • What if it doesn’t work?
Inferring branch structure • Program extrapolation • Attempt to verify • If resulting program does not verify: • Infer the needed guard using custom spec evaluation • Repeat synthesis for remaining cases
Branch structure: Example interface T { var a constructorInit(p,q) a := {p, q} } a={7}, p=3, q=4, c=3, d=4 Match c,d with p,q if (p≤q) { c,d := p,q } else { c,d := q,p } datamodel T { var c, d invariant a = {c,d} c ≤ d } Works only if p≤q Generate if Repeat assuming ¬(p≤q)
Objects • Each interface denotes an instantiable type, that is, a class of objects • A data model can also make use of objects
Demo SimpleCell
Delegation • An interface has model fields • part of the specification • not part of compiled code • If type X uses objects of type Y, its code should: • not set Y’s model fields directly, but • use Y’s interface to call constructors and methods to achieve the desired result
Conclusions • Synthesis by combination of: • Constraint solving • Symbolic/concrete evaluation • Unification • More to do: • Methods • Formalization, better understand the technique • … • Reflection:Is this how we should be programming?