.. _tutorial:

Tutorial: Sorting
=================

This tutorial shows how to:

  * use the `choose` construct for synthesis and constraint solving
  * define lists as algebraic data types
  * use sets to specify properties of interest
  * specify sortedness of a list and use function contracts
  * verify properties of an insertion into a sorted list
  * execute or synthesize provably correct operations using specifications alone,
    without the need to write implementation

For this tutorial we occasionally assume that the user is using the web 
interface. The functionality is also available (possibly with less
convenient interface) from the command line, see :ref:`gettingstarted`.

Sorting Two Elements
--------------------

As a preview, let us start by **specifying** a function that
sorts **two** mathematical integers. Here is what we need
to write.

.. code-block:: scala

  import leon.lang._
  import leon.lang.synthesis._
  object Sort {
    def sort2(x : BigInt, y : BigInt) = choose{(res: (BigInt,BigInt)) =>
      Set(x,y) == Set(res._1, res._2) && res._1 <= res._2
    }
  }

A Leon program consists of one or more modules delimited by
`object` and `class` declarations. We use `import` to
include core constructs that are specific to Leon. Note
that, with the definitions in `leon._` packages, Leon
programs should also compile with the standard Scala
compiler. In that sense, Leon is a proper subset of Scala.

Our initial function that "sorts" two mathematical integers
is named `sort2`.  Namely, it accepts two arguments, `x` and
`y`, and returns a tuple, which we will here denote `res`,
which stores either `(x,y)` or `(y,x)` such that the first
component is less than equal the second component.

Note that we use `BigInt` to denote unbounded mathematical
integers. As in Scala and Java, `Int` denotes 32-bit
integers with the usual signed arithmetic operations from
computer architecture. In contrast, `BigInt` denotes the
unbounded integers, which closely mimic mathematical
integers.

As usual in Scala, we write `res._1` for the first component
of the return tuple `res`, and `res._2` for the second
component of the tuple.

The specification says that the set of arguments is equal to
the set consisting of the returned tuple elements. The
notation `Set(x1,x2,...,xN)` denotes

.. math::

  \{ x_1, \ldots, x_N \}

that is, a finite set containing precisely the elements 
`x1`, `x2`,..., `xN`.

Finally, the `choose` construct takes a variable name (here,
`res`) denoting the value of interest and then gives, after
the `=>` symbol, a property that this value should
satisfy. We can read `choose{(x:T) => P}` as 

**choose x of type T such that P**

Here, we are interested in computing a result `res` tuple
such that the set of elements in the tuple is the same as
`{x,y}` and that the elements are in ascending order in the
tuple.  The specification thus describes sorting of lists of
length two.  Note that the result is uniquely specified, no
matter what the values of `x` and `y` are.

Evaluating exppressions containing choose
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Leon contains a built-in evaluator. To see it in action in
the web interface, just define a function without
parameters, such as 

.. code-block:: scala

    def test1 = sort2(30, 4)

Hovering over `test1` should display the computed result
`(4,30)`. From :ref:`cmdlineoptions`, use `--eval`.

This shows that Leon's evaluator can also execute `choose`
constructs. In other words, it supports programming
with constraints. Executing the `choose` construct
is, however, expensive. Moreover, the execution times
are not very predictable. This is why it is desirable
to eventually replace your `choose` constructs with
more efficient code. Leon can automate this process
in some cases, using **synthesis**.

Synthesizing Sort for Two Elements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Instead of executing `choose` using a constraint solver
during execution, we can alternatively instruct Leon to
synthesize a function corresponding to `choose`.  The system
then synthesizes a computation that satisfies the
specification, such as, for, example:

.. code-block:: scala

    def sort2(x : BigInt, y : BigInt) = choose{(res: (BigInt,BigInt)) =>
      if (x < y) x
      else y
    }

Depending on the particular run, Leon may also produce a solution such as

.. code-block:: scala

  def sort2(x : BigInt, y : BigInt): (BigInt, BigInt) = {
    if (x < y) {
      (x, y)
    } else if (x == y) {
      (x, x)
    } else {
      (y, x)
    }
  }

This code performs some unnecessary case analysis, but still
satisfies our specification. In this case, the specification
of the program output is unambiguous, so all programs that
one can synthesize compute the same results for all inputs.

Remarks on Uniqueness
^^^^^^^^^^^^^^^^^^^^^

Let us give a name to the specification for `sort2`.

.. code-block:: scala

  def sort2spec(x: BigInt, y: BigInt, res: (BigInt, BigInt)): Boolean = {
    Set(x,y) == Set(res._1, res._2) && res._1 <= res._2
  }

We can then prove that the result is unique, by asking Leon
to show the following function returns `true` for all inputs
for which the `require` clause holds.

.. code-block:: scala

  def unique2(x: BigInt, y: BigInt, 
            res1: (BigInt, BigInt),
            res2: (BigInt, BigInt)): Boolean = {
    require(sort2spec(x,y,res1) && sort2spec(x,y,res2))
    res1 == res2
  }.holds

In contrast, if we define the corresponding specification for three integers

.. code-block:: scala

  def sort3spec(x: BigInt, y: BigInt, z: BigInt, res: (BigInt, BigInt, BigInt)): Boolean = {
    Set(x,y,z) == Set(res._1, res._2, res._3) && res._1 <= res._2 && res._2 <= res._3
  }

Then uniqueness of the solution is the following conjecture:

.. code-block:: scala
  
  def unique3(x: BigInt, y: BigInt, z: BigInt, 
      res1: (BigInt, BigInt, BigInt),
      res2: (BigInt, BigInt, BigInt)): Boolean = {
    require(sort3spec(x,y,z,res1) && sort3spec(x,y,z,res2))
    res1 == res2
  }.holds

This time, however, Leon will report a counterexample, indicating
that the conjecture does not hold. One such counterexample is
0, 1, 1, for which the result (0, 0, 1) also satisfies the specification,
because sets ignore the duplicates, so 

.. code-block:: scala

    Set(x,y,z) == Set(res._1, res._2, res._2)

is true. This shows that writing specifications can be subtle, but Leon's
capabilities can help in the process as well.

Defining Lists and Their Properties
-----------------------------------

We next consider sorting an unbounded number of elements.
For this purpose, we define a data structure for lists of
integers.  Leon has a built-in data type of parametric
lists, see :ref:`Leon Library <library>`, but here we define
our own variant instead. 

Lists
^^^^^

We use a recursive algebraic data type
definition, expressed using Scala's **case classes**.

.. code-block:: scala

  sealed abstract class List
  case object Nil extends List
  case class Cons(head: BigInt, tail: List) extends List

We can read the definition as follows: List is defined
by applying the following two rules finitely many times:

  * empty list `Nil` is a list
  * if `head` is an integer and `tail` is a `List`, then
    `Cons(head,tail)` is a `List`.

A list containing elements 5, 2, and 7, in that order, can
be written as

.. code-block:: scala

    Cons(5, Cons(2, Cons(7, Nil)))

Having defined the structure of lists, we can move on to
define some semantic properties of lists that are of
interests. For this purpose, we use recursive functions
defined on lists. 

Size of a List
^^^^^^^^^^^^^^

As the starting point, we define size of a list.

.. code-block:: scala

    def size(l: List) : BigInt = (l match {
        case Nil => 0
        case Cons(x, rest) => 1 + size(rest)
    })

We can add a specification that the size is non-negative.

.. code-block:: scala

    def size(l: List) : BigInt = (l match {
        case Nil => 0
        case Cons(x, rest) => 1 + size(rest)
    }) ensuring(res => res >= 0)

The construct `ensuring(res => P)` denotes that, if
we denote by `res` the return value of the function,
then `res` satisfies the boolean-valued expression `P`.
We call the predicate `P` the **postcondition**.

Sorted Lists
^^^^^^^^^^^^

We define properties of values simply as executable
predicates that check if the property holds. The following
is a property that a list is sorted in a strictly ascending
order.

.. code-block:: scala

    def isSorted(l : List) : Boolean = l match {
      case Nil => true
      case Cons(_,Nil) => true
      case Cons(x1, Cons(x2, rest)) => 
        x1 < x2 && isSorted(Cons(x2,rest))
    }

Insertion into Sorted List
--------------------------

.. 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) => l
      case Cons(e, rest) if (x < e) => Cons(x, Cons(e,rest))
      case Cons(e, rest) if (x > e) => Cons(e, sInsert(x,rest))
    }
  } ensuring {(res:List) => isSorted(res)}

Being Sorted is Not Enough
--------------------------

A function such as this one is correct.

.. code-block:: scala

    def fsInsert(x : BigInt, l : List) : List = {
      require(isSorted(l))
      Nil
    } ensuring {(res:List) => isSorted(res)}

So, our specification may be considered weak.

Using Size in Specification
---------------------------

Consider a stronger additional postcondition property:

.. code-block:: scala

  size(res) == size(l) + 1

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:

.. code-block:: scala

  size(l) <= size(res) && size(res) <= size(l) + 1

Using Content in Specification
------------------------------

A stronger specification needs to talk about the `content`
of the list.

.. 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) => l
      case Cons(e, rest) if (x < e) => Cons(x, Cons(e,rest))
      case Cons(e, rest) if (x > e) => Cons(e, sInsert(x,rest))
    }
  } 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.

.. code-block:: scala

  def content(l: List): Set[BigInt] = l match {
    case Nil => Set()
    case Cons(i, t) => Set(i) ++ content(t)
  }


Sorting Specification and Running It
------------------------------------

.. code-block:: scala

  def sortMagic(l : List) = choose{(res:List) => 
    isSorted(res) && content(res) == content(l)
  }

We can execute it.

.. 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))))`.


Synthesizing Sort
-----------------

By asking the system to synthesize the `choose` construct,
we may obtain a function such as the following, which gives
us the natural insertion sort.

.. code-block:: scala

    def sortMagic(l : List): List = {
      l match {
        case Cons(head, tail) =>
          sInsert(head, sortMagic(tail))
        case Nil => Nil
      }
    }

Going back and Synthesizing Insertion
-------------------------------------

In fact, if we had a precise enough specification of insert,
we could have synthesized it from the specification.

.. code-block:: scala

  def insertMagic(x: BigInt, l: List): List = {
    require(isSorted(l))
    choose {(res: List) => 
      isSorted(res) && content(res) == content(l) ++ Set[BigInt](x)
    }
  }