From b384e0aea0eab7ceed741fc5199c52e0525b8743 Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <ekneuss@gmail.com> Date: Wed, 29 Apr 2015 15:56:58 +0200 Subject: [PATCH] start describing rules --- doc/synthesis.rst | 218 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/doc/synthesis.rst b/doc/synthesis.rst index 257782804..ec586583a 100644 --- a/doc/synthesis.rst +++ b/doc/synthesis.rst @@ -14,3 +14,221 @@ As we have seen previously, relatively precise specifications of complex operations can be written consicely. Synthesis can thus reduce development time and allows the user to focus on high-level aspects. +Deductive Synthesis Framework +----------------------------- + +Closing Rules +------------- + +Optimistic Ground +^^^^^^^^^^^^^^^^^ + +CEGIS +^^^^^ + +TEGIS +^^^^^ + +Ground +^^^^^^ + +Decomposing Rules +----------------- + +Equality Split +^^^^^^^^^^^^^^ + +Given two input variables `a` and `b` of compatible types, this rule +considers the cases where `a = b` and `a != b`. From: + +.. code-block:: scala + + choose(res => spec(a, b, res)) + + +this rule generates two sub-chooses, and combines them as follows: + +.. code-block:: scala + + if (a == b) { + choose(res => spec(a, a, res)) + } else { + choose(res => spec(a, b, res)) + } + + +Inequality Split +^^^^^^^^^^^^^^^^ + +Given two input variables `a` and `b` of numeric type, this rule +considers the cases where `a < b`, `a == b`, and `a > b`. From: + +.. code-block:: scala + + choose(res => spec(a, b, res)) + + +this rule generates three sub-chooses, and combines them as follows: + +.. code-block:: scala + + if (a < b) { + choose(res => spec(a, b, res)) + } else if (a > b) { + choose(res => spec(a, b, res)) + } else { + choose(res => spec(a, a, res)) + } + + +ADT Split +^^^^^^^^^ + +Given a variable `a` typed as an algebraic data type `T`, the rules decomposes +the problem in cases where each case correspond to one subtype of `T`: + +.. code-block:: scala + + abstract class T + case class A(f1: Int) extends T + case class B(f2: Boolean) extends T + case object C extends T + + choose(res => spec(a, res)) + + +this rule generates three sub-chooses, in which the input variable `a` is +substituted by the appropriate case, and combines them as follows: + +.. code-block:: scala + + a match { + case A(f1) => choose(res => spec(A(f1), res)) + case B(f2) => choose(res => spec(B(f2), res)) + case C => choose(res => spec(C, res)) + } + + +Int Induction +^^^^^^^^^^^^^ + +Given an integer (or bigint) variable `a`, the rules performs induction on `a`: + +.. code-block:: scala + + choose(res => spec(a, res)) + + +this rule generates three sub-chooses, one for the base case and one for each inductive case (we allow negative numbers): + +.. code-block:: scala + + def tmp1(a: Int) = { + if (a == 0) { + choose(res => spec(a, res)) + } else if (a > 0) { + val r1 = tmp1(a-1) + choose(res => spec(a, res)) + } else if (a < 0) { + val r1 = tmp1(a+1) + choose(res => spec(a, res)) + } + } + + tmp1(a) + +This allows Leon to synthesize a well-structured recursive function. + +One Point +^^^^^^^^^ + +This syntactic rule considers equalities of a variable at the top level of the +specification, and substitutes the variable with the corresponding expression in +the rest of the formula. Given the following specification: + +.. math:: + a = expr \land \phi + +and assuming :math:`expr` does not use :math:`a`, we generate the alternative and +arguable simpler specification: + + +.. math:: + \phi[a \rightarrow expr] + +This rule is typically combined with `Unused Input` or `Unconstrained Output` to +actually eliminate the input or output variable form the synthesis problem. + +Assert +^^^^^^ + +The `Assert` rule scans the specification for predicates that only constraint +input variables and lifts them out of the specification. Since these are +constraints over the input variables, they typically represent the +precondition necessary for the ``choose`` to be feasible. +Given an input variable `a`: + +.. code-block:: scala + + choose(res => spec(a, res) && pred(a)) + +will become: + +.. code-block:: scala + + require(pred(a)) + + choose(res => spec(a, res)) + +Case Split +^^^^^^^^^^ + +This rule considers a top-level disjunction and decomposes it: + +.. code-block:: scala + + choose(res => spec1(a, res) || spec2(a, res)) + +thus becomes two sub-chooses + +.. code-block:: scala + + if (P) { + choose(res => spec1(a, res)) + } else { + choose(res => spec2(a, res)) + } + +Here we note that ``P`` is not known until the first ``choose`` is solved, as it +corresponds to its precondition. + + + +Equivalent Input +^^^^^^^^^^^^^^^^ + +This rule discovers equivalences in the input variables in order to eliminate +redundancies. We consider two kinds of equivalences: + + 1) Simple equivalences: the specification contains :math:`a = b` at the top + level. +Equivawhetherlent input takes a synthesis problem with two compatible input variables +`a` and `b` relies on an SMT solver to establish if the path-condition implies +that `a == b` + +Unused Input +^^^^^^^^^^^^ + +Unconstrained Output +^^^^^^^^^^^^^^^^^^^^ + + +.. + Unification.DecompTrivialClash, + Disunification.Decomp, + ADTDual, + CaseSplit, + IfSplit, + DetupleOutput, + DetupleInput, + InnerCaseSplit -- GitLab