Download presentation
Presentation is loading. Please wait.
Published byDomenic Bryan Modified over 9 years ago
1
Synthesis using Variable Elimination Viktor Kuncak EPF Lausanne http://lara.epfl.ch/w/impro
2
Implicit Programming at All Levels Opportunities for implicit programming in Development within an IDE – InSynth tool Compilation – Comfusy and RegSy tools Execution – Scala ^ Z3, UDITA, Kaplan
3
a. pre(a) pre(a) precondition: constraint (relation): P(a,x) between inputs and outputs function: x = f(a) from inputs to outputs P(a,f(a))
4
def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = choose((h: Int, m: Int, s: Int) ⇒ ( h * 3600 + m * 60 + s == totalSeconds && h ≥ 0 && m ≥ 0 && m < 60 && s ≥ 0 && s < 60 )) Compilation in Comfusy def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = val t1 = val t2 = val t3 = val t4 = (t1, t3, t4) Ruzica Piskac Philippe Suter, PLDI’10 Mikaël Mayer ?
5
Todays Approach:
6
Equations Use one equation to reduce the number of variables by one: choose((h: Int, m: Int, s: Int) ⇒ ( h * 3600 + m * 60 + s == totalSeconds && h ≥ 0 && m ≥ 0 && m < 60 && s ≥ 0 && s < 60 ))
7
One equation where no coefficient is 1 choose((x,y) =>10 x + 14 y == a) Find one possible pair x,y, as a function of a.
8
Constructive (Extended) Euclid’s Algorithm: gcd(10,14) 10 14 10 4 6 4 2 4 2 2 0 10 x + 14 y == 10 x + 14 y == a
9
Result of Synthesis for one Equation choose((x,y) =>10 x + 14 y == a) assert ( ) val x = val y = check the solution: Change in requirements! Customer also wants: x < y does our solution work for e.g. a=2
10
Idea: Eliminate Variables x = 3/2 a + c 1 z y = -a + c 2 z choose((x,y) =>10 x + 14 y == a&& x < y) Cannot easily eliminate one of the x,y. Eliminate both x,y, get one free - z Find general form, characterize all solutions, parametric solution c 1 = ? c 2 = ?
11
Idea: Eliminate Variables x = 3/2 a + c 1 z y = -a + c 2 z choose((x,y) =>10 x + 14 y == a&& x < y) c 1 = ? c 2 = ? 10 x 0 + 14 y 0 + (10 c 1 + 14 c 2 ) == a 10 c 1 + 14 c 2 == 0
12
x = 3/2 a + 5 z y = -a - 7 z choose((x,y) =>10 x + 14 y == a&& x < y)
13
I forgot to say, we also wish: 0 < x choose((x,y) =>10 x + 14 y == a && 0 < x && x < y)
14
def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = choose((h: Int, m: Int, s: Int) ⇒ ( h * 3600 + m * 60 + s == totalSeconds && h ≥ 0 && m ≥ 0 && m < 60 && s ≥ 0 && s < 60 )) Compilation in Comfusy def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = val t1 = val t2 = val t3 = val t4 = (t1, t3, t4) Ruzica Piskac Philippe Suter, PLDI’10 Mikaël Mayer ?
15
Synthesis Procedure on Example process every equality: take an equality E i, compute a parametric description of the solution set and insert those values in the rest of formula 15 CODE: val h = lambda val m = mu val s = (-3600) * lambda + (-60) * mu + totalSeconds
16
Synthesis Procedure by Example process every equality: take an equality E i, compute a parametric description of the solution set and insert those values in the rest of formula 16 Formula (remain specification): 0 ≤ λ, 0 ≤ μ, μ ≤ 59, 0 ≤ totalSeconds – 3600λ - 60μ, totalSeconds – 3600λ - 60μ ≤ 59 0 ≤ λ, 0 ≤ μ, μ ≤ 59, 0 ≤ totalSeconds – 3600λ - 60μ, totalSeconds – 3600λ - 60μ ≤ 59
17
Processing Inequalities expressing constraints as bounds on μ process output variables one by one 0 ≤ λ, 0 ≤ μ, μ ≤ 59, 0 ≤ totalSeconds – 3600λ - 60μ, totalSeconds – 3600λ - 60μ ≤ 59 0 ≤ λ, 0 ≤ μ, μ ≤ 59, 0 ≤ totalSeconds – 3600λ - 60μ, totalSeconds – 3600λ - 60μ ≤ 59 0 ≤ λ, 0 ≤ μ, μ ≤ 59, μ ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ μ 0 ≤ λ, 0 ≤ μ, μ ≤ 59, μ ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ μ Code: val mu = min(59, (totalSeconds -3600* lambda) div 60)
18
Fourier-Motzkin-Style Elimination combine each lower and upper bound basic simplifications Code: val lambda = totalSeconds div 3600 Preconditions: 0 ≤ totalSeconds 0 ≤ λ, 0 ≤ μ, μ ≤ 59, μ ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ μ 0 ≤ λ, 0 ≤ μ, μ ≤ 59, μ ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ μ 0 ≤ λ, 0 ≤ 59, 0 ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ 59 0 ≤ λ, 0 ≤ 59, 0 ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ ⌊ (totalSeconds – 3600λ)/60 ⌋, ⌈ (totalSeconds – 3600λ – 59)/60 ⌉ ≤ 59 0 ≤ λ, 60λ ≤ ⌊ totalSeconds /60 ⌋, ⌈ (totalSeconds –59)/60 ⌉ – 59 ≤ 60λ 0 ≤ λ, 60λ ≤ ⌊ totalSeconds /60 ⌋, ⌈ (totalSeconds –59)/60 ⌉ – 59 ≤ 60λ
19
def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = choose((h: Int, m: Int, s: Int) ⇒ ( h * 3600 + m * 60 + s == totalSeconds && h ≥ 0 && m ≥ 0 && m < 60 && s ≥ 0 && s < 60 )) Compilation in Comfusy def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = val t1 = totalSeconds div 3600 val t2 = totalSeconds -3600 * t1 val t3 = t2 div 60 val t4 = totalSeconds - 3600 * t1 - 60 * t3 (t1, t3, t4) Ruzica Piskac Philippe Suter, PLDI’10 Mikaël Mayer
20
Handling of Inequalities Solve for one by one variable: – separate inequalities depending on polarity of x: A i ≤ α i x β j x ≤ B j – define values a = max i ⌈ A i /α i ⌉ and b = min j ⌈ B j / β j ⌉ if b is defined, return x = b else return x = a further continue with the conjunction of all formulas ⌈ A i /α i ⌉ ≤ ⌈ B j / β j ⌉ 20
21
2y − b − a ≤ 3x ∧ 2x ≤ 4y + a + b 4y − 2b − 2a ≤ 6x ≤ 12y + 3a + 3b (4y − 2b − 2a) / 6 ≤ x ≤ (12y + 3a + 3b) / 6 (4y − 2b − 2a) / 6 ≤ ⌊ (12y + 3a + 3b) / 6 ⌋ two extra variables: (4y − 2b − 2a) / 6 ≤ l ∧ 12y + 3a + 3b = 6 ∗ l + k ∧ 0 ≤ k ≤ 5 4y − 2b − 2a ≤ 6 * l ∧ 12y + 3a + 3b = 6 ∗ l + k ∧ 0 ≤ k ≤ 5 pre: 6|3a + 3b − k 4y − 2b − 2a ≤ 12y + 3a + 3b – k − 5b − 5a +k ≤ 8y y = ⌈ (k − 5a − 5b)/8 ⌉ 2y − b ≤ 3x + a ∧ 2x − a ≤ 4y + b 21
22
Generated Code Contains Loops val (x1, y1) = choose(x: Int, y: Int => 2*y − b =< 3*x + a && 2*x − a =< 4*y + b) val (x1, y1) = choose(x: Int, y: Int => 2*y − b =< 3*x + a && 2*x − a =< 4*y + b) val kFound = false for k = 0 to 5 do { val v1 = 3 * a + 3 * b − k if (v1 mod 6 == 0) { val alpha = ((k − 5 * a − 5 * b)/8).ceiling val l = (v1 / 6) + 2 * alpha val y = alpha val kFound = true break } } if (kFound) val x = ((4 * y + a + b)/2).floor else throw new Exception(”No solution exists”) val kFound = false for k = 0 to 5 do { val v1 = 3 * a + 3 * b − k if (v1 mod 6 == 0) { val alpha = ((k − 5 * a − 5 * b)/8).ceiling val l = (v1 / 6) + 2 * alpha val y = alpha val kFound = true break } } if (kFound) val x = ((4 * y + a + b)/2).floor else throw new Exception(”No solution exists”) 22
23
NP-Hard Constructs Divisibility combined with inequalities: – corresponding to big disjunction in q.e., we will generate a for loop with constant bounds (could be expanded if we wish) Disjunctions – Synthesis of a formula computes program and exact precondition of when output exists – Given disjunctive normal form, use preconditions to generate if-then-else expressions (try one by one)
24
Synthesis for Disjunctions
25
General Form of Synthesized Functions for Presburger Arithmetic choose x such that F(x,a) x = t(a) Result t(a) is expressed in terms of +, -, C*, /C, if Need arithmetic for solving equations Need conditionals for – disjunctions in input formula – divisibility and inequalities (find a witness meeting bounds and divisibility by constants) t(a) = if P 1 (a) t 1 (a) elseif … elseif P n (a) t n (a) else error(“No solution exists for input”,a)
26
Methodology QE Synthesis Each quantifier elimination ‘trick’ we found corresponds to a synthesis trick Find the corresponding terms Key techniques: – one point rule immediately gives a term – change variables, using a computable function – strengthen formula while preserving realizability – recursively eliminate variables one-by one Example use – transform formula into disjunction – strengthen each disjunct using equality – apply one-point rule
27
Synthesis for non-linear arithmetic def decomposeOffset(offset: Int, dimension: Int) : (Int, Int) = choose((x: Int, y: Int) ⇒ ( offset == x + dimension * y && 0 ≤ x && x < dimension )) The predicate becomes linear at run-time Synthesized program must do case analysis on the sign of the input variables Some coefficients are computed at run-time
28
Generated Code May Contain Loops val (x1, y1) = choose(x: Int, y: Int => 2*y − b =< 3*x + a && 2*x − a =< 4*y + b) val (x1, y1) = choose(x: Int, y: Int => 2*y − b =< 3*x + a && 2*x − a =< 4*y + b) val kFound = false for k = 0 to 5 do { val v1 = 3 * a + 3 * b − k if (v1 mod 6 == 0) { val alpha = ((k − 5 * a − 5 * b)/8).ceiling val l = (v1 / 6) + 2 * alpha val y = alpha val kFound = true break } } if (kFound) val x = ((4 * y + a + b)/2).floor else throw new Exception(”No solution exists”) val kFound = false for k = 0 to 5 do { val v1 = 3 * a + 3 * b − k if (v1 mod 6 == 0) { val alpha = ((k − 5 * a − 5 * b)/8).ceiling val l = (v1 / 6) + 2 * alpha val y = alpha val kFound = true break } } if (kFound) val x = ((4 * y + a + b)/2).floor else throw new Exception(”No solution exists”)
29
Basic Compile-Time Analysis
30
Compile-time warnings def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = choose((h: Int, m: Int, s: Int) ⇒ ( h * 3600 + m * 60 + s == totalSeconds && h ≥ 0 && h < 24 && m ≥ 0 && m < 60 && s ≥ 0 && s < 60 )) Warning: Synthesis predicate is not satisfiable for variable assignment: totalSeconds = 86400
31
Compile-time warnings def secondsToTime(totalSeconds: Int) : (Int, Int, Int) = choose((h: Int, m: Int, s: Int) ⇒ ( h * 3600 + m * 60 + s == totalSeconds && h ≥ 0 && m ≥ 0 && m ≤ 60 && s ≥ 0 && s < 60 )) Warning: Synthesis predicate has multiple solutions for variable assignment: totalSeconds = 60 Solution 1: h = 0, m = 0, s = 60 Solution 2: h = 0, m = 1, s = 0
32
Handling Data Structures
33
Synthesis for sets def splitBalanced[T](s: Set[T]) : (Set[T], Set[T]) = choose((a: Set[T], b: Set[T]) ⇒ ( a union b == s && a intersect b == empty && a.size – b.size ≤ 1 && b.size – a.size ≤ 1 )) def splitBalanced[T](s: Set[T]) : (Set[T], Set[T]) = val k = ((s.size + 1)/2).floor val t1 = k val t2 = s.size – k val s1 = take(t1, s) val s2 = take(t2, s minus s1) (s1, s2) a b s
34
From Data Structures to Numbers Observation: – Reasoning about collections reduces to reasoning about linear integer arithmetic! 34 a.size == b.size && a union b == bigSet && a intersect b == empty a b bigSet
35
From Data Structures to Numbers Observation: – Reasoning about collections reduces to reasoning about linear integer arithmetic! 35 a.size == b.size && a union b == bigSet && a intersect b == empty a b bigSet
36
From Data Structures to Numbers Observation: – Reasoning about collections reduces to reasoning about linear integer arithmetic! 36 a.size == b.size && a union b == bigSet && a intersect b == empty a b bigSet
37
From Data Structures to Numbers Observation: – Reasoning about collections reduces to reasoning about linear integer arithmetic! 37 a.size == b.size && a union b == bigSet && a intersect b == empty a b bigSet New specification: kA = kB New specification: kA = kB
38
From Data Structures to Numbers Observation: – Reasoning about collections reduces to reasoning about linear integer arithmetic! 38 a.size == b.size && a union b == bigSet && a intersect b == empty a b bigSet New specification: kA = kB && kA +kB = |bigSet| New specification: kA = kB && kA +kB = |bigSet|
41
Experience with Comfusy Works well for examples we encountered – Needed: synthesis for more expressive logics, to handle more examples – seems ideal for domain-specific languages Efficient for conjunctions of equations (could be made polynomial) Extends to synthesis with parametric coefficients Extends to logics that reduce to Presburger arithmetic (implemented for BAPA)
42
Comfusy for Arithmetic Limitations of Comfusy for arithmetic: – Naïve handling of disjunctions – Blowup in elimination, divisibility constraints – Complexity of running synthesized code (from QE): doubly exponential in formula size – Not tested on modular arithmetic, or on synthesis with optimization objectives – Arbitrary-precision arithmetic with multiple operations generates time-inefficient code – Cannot do bitwise operations (not in PA)
43
Arithmetic Synthesis using Automata
44
RegSy Synthesis for regular specifications over unbounded domains J. Hamza, B. Jobstmann, V. Kuncak FMCAD 2010
45
Automata-Based Synthesis Disjunctions not a problem Result not depends on the syntax of input formula Complexity of running synthesized code: ALWAYS LINEAR IN THE NUMBER OF BITS Modular arithmetic and bitwise operators: synthesize bit tricks for – unbounded number of bits, uniformly – without skeletons Supports quantified constraints – including optimization constraints
46
Expressiveness of Spec Language Non-negative integer constants and variables Boolean operators Linear arithmetic operator Bitwise operators Quantifiers over numbers and bit positions PAbit = Presburger arithmetic with bitwise operators WS1S= weak monadic second-order logic of one successor
48
Basic Idea View integers as finite (unbounded) bit-streams (binary representation starting with LSB) Specification in WS1S (PAbit) Synthesis approach: – Step 1: Compile specification to automaton over combined input/output alphabet (automaton specifying relation) – Step 2: Use automaton to generate efficient function from inputs to outputs realizing relation
49
Inefficient but Correct Method Run over a deterministic automaton over inputs and outputs Becomes run of a non-deterministic if we look only at outputs Simulate all branches until the end of input Successful branches indicate outputs that work
50
WS1S spec WS1S spec Mona Synthesis: 1.Det. automaton for spec over joint alphabet 2.Project, determinize, extract lookup table Synthesis: 1.Det. automaton for spec over joint alphabet 2.Project, determinize, extract lookup table Execution: 1.Run A on input w and record trace 2.Use table to run backwards and output Execution: 1.Run A on input w and record trace 2.Use table to run backwards and output Our Approach: Precompute Synthesized program: Automaton + lookup table Synthesized program: Automaton + lookup table Input word Output word without losing backward information
51
Experiments Linear scaling observed in length of input NoExampleMONA (ms)Syn (ms)|A||A’|512b1024b2048b4096b 1addition3181324950999519673978 2approx719670273547093218213641 3company8291130658177608131223914930 4parity3461084533667013102572 5mod-6341242232746091717653567 63-weights- min 26963640221343887516883391 74-weights27071537551945890317813605 8smooth-4b5157819501781955637127125054942 9smooth-f-2b569331736753198919903905 10smooth-b-2b5691241733421693476281304 116-3n+183410072337955695318824022 In 3 seconds solve constraint, minimizing the output; Inputs and outputs are of order 2 4000
52
Thought: A quantifier not to forget Automatically synthesized and only automatically tested code is great – But probably even less likely to be correct Synthesizing programs that are guaranteed to be correct by construction will remain important.
53
Implicit Programming at All Levels Opportunities for implicit programming in Development within an IDE – InSynth tool Compilation – Comfusy and RegSy tools Execution – Scala ^ Z3 and UDITA tools requirements def f(x : Int) = { choose y st... } iload_0 iconst_1 call Z3 42
54
Example tool all : SequenceInputStream =
55
Program point Max steps Create clauses: - encode in FOL - assign weights Find all visible symbols Resolution algorithm with weights ………………………… ………………………… ………………………… ………………………… ………………………… ………………………… ………………………… ………………………… …………… Code snippets Code Synthesis inside IDE
56
Curry-Howard Correspondence def map[A,B](x : List[T], f : A -> B) : List[B] = {...}
57
InSynth - Interactive Synthesis of Code Snippets def map[A,B](f:A => B, l:List[A]): List[B] = {... } def stringConcat(lst : List[String]): String = {... }... def printInts(intList:List[Int], prn: Int => String): String = def map[A,B](f:A => B, l:List[A]): List[B] = {... } def stringConcat(lst : List[String]): String = {... }... def printInts(intList:List[Int], prn: Int => String): String = Returned value: stringConcat(map (prn, intList)) Returned value: stringConcat(map (prn, intList)) Is there a term of given type in given environment? Monorphic: decidable. Polymorphic: undecidable joint work with: Tihomir Gvero, Ruzica Piskac
58
Features Parametric polymorphism Branching expressions with multiple arguments (not just chains of calls) Mining API usage frequencies – but can still synthesize previously unseen code Distance to program point heuristics Filtering based on test-cases
59
Wrapping Up
60
Synthesis and Verification Some functionality is best synthesized from specs – other: better implemented, verified (and put into library) Currently, no choice –must always implement – specifications and verification are viewed as overhead Goal: make specifications intrinsic part of programs, with clear benefits to programmers – they run! Example: write an assertion, not how to establish it This will help both – verifiability: document, not reverse-engineer the invariants – productivity: avoid writing messy implementation
61
Conclusion: Implicit Programming Development within an IDE – InSynth tool – theorem proving as code completion Compilation – Comfusy : decision procedure synthesis procedure Scala implementation for integer arithmetic, BAPA – RegSy : solving WS1S constraints Execution – UDITA: Java + choice as test generation language – Scala ^ Z3 : invoking Z3 – Kaplan: constraint programming in Scala http://lara.epfl.ch/w/impro
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.