From ecd17777499ce89cf133268c4c860bff8272f4e6 Mon Sep 17 00:00:00 2001 From: Viktor Kuncak <viktor.kuncak@epfl.ch> Date: Mon, 27 Apr 2015 19:44:10 -0700 Subject: [PATCH] doc: tutorial now essentially complete. Fixed also the file. --- doc/tutorial.rst | 96 ++++++++++++++++++++++----- testcases/web/demos/00_Tutorial.scala | 11 +++ 2 files changed, 90 insertions(+), 17 deletions(-) diff --git a/doc/tutorial.rst b/doc/tutorial.rst index 55f93f1f5..7a5628831 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -12,6 +12,7 @@ This tutorial shows how to: * use sets and recursive function to specify data structures * synthesize insertion into a sorted list * synthesize sorting on lists + * repair an incorrect function We assume that the user is using the web interface. The functionality is also available (possibly with less @@ -461,6 +462,9 @@ order. Insertion into Sorted List -------------------------- +Consider the following specification of insertion into a sorted list, +which is a building block for an insertion sort. + .. code-block:: scala def sInsert(x : BigInt, l : List) : List = { @@ -473,10 +477,14 @@ Insertion into Sorted List } } ensuring {(res:List) => isSorted(res)} +Leon verifies that the returned list is indeed sorted. Note +how we are again using a recursively defined function to +specify another function. + Being Sorted is Not Enough -------------------------- -A function such as this one is correct. +Note, however, that a function such as this one is also correct. .. code-block:: scala @@ -485,7 +493,8 @@ A function such as this one is correct. Nil } ensuring {(res:List) => isSorted(res)} -So, our specification may be considered weak. +So, our specification may be considered weak, because it does +not say anything about the elements. Using Size in Specification --------------------------- @@ -498,7 +507,7 @@ Consider a stronger additional postcondition property: Does it hold? If we try to add it, we obtain a counterexample. A correct strengthening, taking into account that the element -may or may not already be in the list, is: +may or may not already be in the list, is the following. .. code-block:: scala @@ -523,8 +532,9 @@ of the list. } ensuring {(res:List) => isSorted(res) && content(res) == content(l) ++ Set(x)} -To compute content, in this example we use sets, even though -it might be better in general to use multisets. +To compute `content`, in this example we use sets (even +though in general it might be better in general to use bags +i.e. multisets). .. code-block:: scala @@ -537,25 +547,28 @@ it might be better in general to use multisets. Sorting Specification and Running It ------------------------------------ +Specifying sorting is in fact very easy. + .. code-block:: scala - def sortMagic(l : List) = choose{(res:List) => - isSorted(res) && content(res) == content(l) - } + def sortMagic(l : List) = { + ???[List] + } ensuring((res:List) => + isSorted(res) && content(res) == content(l)) -We can execute it. +We can execute such a sort. .. code-block:: scala def mm = sortMagic(Cons(20, Cons(5, Cons(50, Cons(2, Nil))))) obtaining the expected `Cons(2, Cons(5, Cons(20, Cons(50, Nil))))`. - +Note that the function actually removes duplicates from the input list. Synthesizing Sort ----------------- -By asking the system to synthesize the `choose` construct, +By asking the system to synthesize the `choose` construct inside `magicSort`, we may obtain a function such as the following, which gives us the natural insertion sort. @@ -572,15 +585,64 @@ us the natural insertion sort. Going back and Synthesizing Insertion ------------------------------------- -In fact, if we had a precise enough specification of insert, -we could have synthesized it from the specification. +In fact, if we have a reasonably precise enough +specification of insert, we can synthesize the implementation. +To try this, remove the body of `sInsert` and replace it +with `???[List]` denoting an unknown value of the given type. + +.. code-block:: scala + + def sInsert(x : BigInt, l : List) : List = { + require(isSorted(l)) + ???[List] + } ensuring {(res:List) => + isSorted(res) && content(res) == content(l) ++ Set(x)} + +Leon can then synthesize the missing part, resulting in a similar +body to the one we wrote by hand originally. + +Repairing an Incorrect Function +------------------------------- + +You may notice that synthesis can take a long time and fail. +Often we do produce some version of the program, but it is +not correct according to a specification. Consider the +following attempt at `sInsert`. .. code-block:: scala - def insertMagic(x: BigInt, l: List): List = { + def sInsert(x : BigInt, l : List) : List = { require(isSorted(l)) - choose {(res: List) => - isSorted(res) && content(res) == content(l) ++ Set[BigInt](x) + l match { + case Nil => Cons(x, Nil) + case Cons(e, rest) => Cons(e, sInsert(x,rest)) } - } + } ensuring {(res:List) => + isSorted(res) && content(res) == content(l) ++ Set(x)} + +Leon reports a counterexample to the correctness. Instead of +trying to manually understand the counterexample, we can +instruct the system to **repair** this solution. If Leon can +reuse parts of the existing function, it can be much faster +than doing synthesis from scratch. Leon automatically finds +test inputs that it uses to localize the error and preserve +useful existing pieces of code. In this case, Leon repairs +the above function into the one equivalent to the original +one, by doing a case split and synthesizing two new cases, +resulting in the following equivalent function. + +.. code-block:: scala + + def sInsert(x : BigInt, l : List): List = { + require(isSorted(l)) + l match { + case Nil => Cons(x, Nil) + case Cons(e, rest) => + if (x < e) Cons(x, l) + else if (x == e) Cons(x, rest) + else Cons(e, sInsert(x, rest)) + } ensuring { (res : List) => + isSorted(res) && content(res) == content(l) ++ Set[BigInt](x) } + +This completes the tutorial. To learn more, check the rest of this documentation and browse the examples provided with Leon. diff --git a/testcases/web/demos/00_Tutorial.scala b/testcases/web/demos/00_Tutorial.scala index dc8734368..786fe3111 100644 --- a/testcases/web/demos/00_Tutorial.scala +++ b/testcases/web/demos/00_Tutorial.scala @@ -174,4 +174,15 @@ def max(x: Int, y: Int): Int = { // def mm = sortMagic(Cons(20, Cons(5, Cons(50, Cons(2, Nil))))) +/* + def sInsert(x : BigInt, l : List) : List = { + require(isSorted(l)) + l match { + case Nil => Cons(x, Nil) + case Cons(e, rest) => Cons(e, sInsert(x,rest)) + } + } ensuring {(res:List) => + isSorted(res) && content(res) == content(l) ++ Set(x)} + */ + } -- GitLab