Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
I
inox
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
LARA
inox
Commits
ecd17777
Commit
ecd17777
authored
9 years ago
by
Viktor Kuncak
Browse files
Options
Downloads
Patches
Plain Diff
doc: tutorial now essentially complete. Fixed also the file.
parent
130487b7
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
doc/tutorial.rst
+79
-17
79 additions, 17 deletions
doc/tutorial.rst
testcases/web/demos/00_Tutorial.scala
+11
-0
11 additions, 0 deletions
testcases/web/demos/00_Tutorial.scala
with
90 additions
and
17 deletions
doc/tutorial.rst
+
79
−
17
View file @
ecd17777
...
@@ -12,6 +12,7 @@ This tutorial shows how to:
...
@@ -12,6 +12,7 @@ This tutorial shows how to:
* use sets and recursive function to specify data structures
* use sets and recursive function to specify data structures
* synthesize insertion into a sorted list
* synthesize insertion into a sorted list
* synthesize sorting on lists
* synthesize sorting on lists
* repair an incorrect function
We assume that the user is using the web interface. The
We assume that the user is using the web interface. The
functionality is also available (possibly with less
functionality is also available (possibly with less
...
@@ -461,6 +462,9 @@ order.
...
@@ -461,6 +462,9 @@ order.
Insertion into Sorted List
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
.. code-block:: scala
def sInsert(x : BigInt, l : List) : List = {
def sInsert(x : BigInt, l : List) : List = {
...
@@ -473,10 +477,14 @@ Insertion into Sorted List
...
@@ -473,10 +477,14 @@ Insertion into Sorted List
}
}
} ensuring {(res:List) => isSorted(res)}
} 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
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
.. code-block:: scala
...
@@ -485,7 +493,8 @@ A function such as this one is correct.
...
@@ -485,7 +493,8 @@ A function such as this one is correct.
Nil
Nil
} ensuring {(res:List) => isSorted(res)}
} 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
Using Size in Specification
---------------------------
---------------------------
...
@@ -498,7 +507,7 @@ Consider a stronger additional postcondition property:
...
@@ -498,7 +507,7 @@ Consider a stronger additional postcondition property:
Does it hold? If we try to add it, we obtain a counterexample.
Does it hold? If we try to add it, we obtain a counterexample.
A correct strengthening, taking into account that the element
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
.. code-block:: scala
...
@@ -523,8 +532,9 @@ of the list.
...
@@ -523,8 +532,9 @@ of the list.
} ensuring {(res:List) =>
} ensuring {(res:List) =>
isSorted(res) && content(res) == content(l) ++ Set(x)}
isSorted(res) && content(res) == content(l) ++ Set(x)}
To compute content, in this example we use sets, even though
To compute `content`, in this example we use sets (even
it might be better in general to use multisets.
though in general it might be better in general to use bags
i.e. multisets).
.. code-block:: scala
.. code-block:: scala
...
@@ -537,25 +547,28 @@ it might be better in general to use multisets.
...
@@ -537,25 +547,28 @@ it might be better in general to use multisets.
Sorting Specification and Running It
Sorting Specification and Running It
------------------------------------
------------------------------------
Specifying sorting is in fact very easy.
.. code-block:: scala
.. code-block:: scala
def sortMagic(l : List) = choose{(res:List) =>
def sortMagic(l : List) = {
isSorted(res) && content(res) == content(l)
???[List]
}
} ensuring((res:List) =>
isSorted(res) && content(res) == content(l))
We can execute
i
t.
We can execute
such a sor
t.
.. code-block:: scala
.. code-block:: scala
def mm = sortMagic(Cons(20, Cons(5, Cons(50, Cons(2, Nil)))))
def mm = sortMagic(Cons(20, Cons(5, Cons(50, Cons(2, Nil)))))
obtaining the expected `Cons(2, Cons(5, Cons(20, Cons(50, 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
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
we may obtain a function such as the following, which gives
us the natural insertion sort.
us the natural insertion sort.
...
@@ -572,15 +585,64 @@ us the natural insertion sort.
...
@@ -572,15 +585,64 @@ us the natural insertion sort.
Going back and Synthesizing Insertion
Going back and Synthesizing Insertion
-------------------------------------
-------------------------------------
In fact, if we had a precise enough specification of insert,
In fact, if we have a reasonably precise enough
we could have synthesized it from the specification.
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
.. code-block:: scala
def
i
nsert
Magic
(x: BigInt, l: List): List = {
def
sI
nsert(x
: BigInt, l
: List)
: List = {
require(isSorted(l))
require(isSorted(l))
choose {(res: List) =>
l match {
isSorted(res) && content(res) == content(l) ++ Set[BigInt](x)
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.
This diff is collapsed.
Click to expand it.
testcases/web/demos/00_Tutorial.scala
+
11
−
0
View file @
ecd17777
...
@@ -174,4 +174,15 @@ def max(x: Int, y: Int): Int = {
...
@@ -174,4 +174,15 @@ def max(x: Int, y: Int): Int = {
// def mm = sortMagic(Cons(20, Cons(5, Cons(50, Cons(2, Nil)))))
// 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)}
*/
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment