Merge branch 'smtv2-dont-fail-on-untyped-prover-vars' into 'master'
[why3.git] / doc / whyml.rst
blobb55eb8026fffea8b708776c490ae60413525a4ed
1 .. _chap.whyml:
3 Why3 by Examples
4 ================
6 This chapter describes the WhyML specification and programming language.
7 A WhyML source file has suffix :file:`.mlw`. It contains a list of modules.
8 Each module contains a list of declarations. These include
10 -  Logical declarations:
12    -  types (abstract, record, or algebraic data types);
14    -  functions and predicates;
16    -  axioms, lemmas, and goals.
18 -  Program data types. In a record type declaration, some fields can be
19    declared ``mutable`` and/or ``ghost``. Additionally, a record type
20    can be declared ``abstract`` (its fields are only visible in ghost
21    code / specification).
23 -  Program declarations and definitions. Programs include many
24    constructs with no counterpart in the logic:
26    -  mutable field assignment;
28    -  sequence;
30    -  loops;
32    -  exceptions;
34    -  local and anonymous functions;
36    -  ghost parameters and ghost code;
38    -  annotations: pre- and postconditions, assertions, loop invariants.
40    A program may be non-terminating. (But termination can be proved if
41    we wish.)
43 Command-line tools described in the previous chapter also apply to files
44 containing programs. For instance
48     why3 prove myfile.mlw
50 displays the verification conditions for programs contained in file
51 :file:`myfile.mlw`, and
55     why3 prove -P alt-ergo myfile.mlw
57 runs the SMT solver Alt-Ergo on these verification conditions. All this
58 can be performed within the GUI tool :why3:tool:`why3 ide` as well. See
59 :numref:`chap.manpages` for more details regarding command lines.
61 As an introduction to WhyML, we use a small logical puzzle
62 (:numref:`sec.einstein`) and then the five problems from the VSTTE 2010
63 verification competition :cite:`vstte10comp`. The source
64 code for all these examples is contained in Why3’s distribution, in
65 sub-directory :file:`examples/`. Look for files :file:`logic/einstein.why` and
66 :file:`vstte10_xxx.mlw`.
68 .. index:: Einstein’s problem
69 .. _sec.einstein:
71 Problem 0: Einstein’s Problem
72 -----------------------------
74 Let us use Why3 to solve a little puzzle known as “Einstein’s logic
75 problem”. (This Why3 example was contributed by Stéphane Lescuyer.)
76 The problem is stated as follows. Five persons, of five
77 different nationalities, live in five houses in a row, all painted with
78 different colors. These five persons own different pets, drink different
79 beverages, and smoke different brands of cigars. We are given the
80 following information:
82 -  The Englishman lives in a red house;
84 -  The Swede has dogs;
86 -  The Dane drinks tea;
88 -  The green house is on the left of the white one;
90 -  The green house’s owner drinks coffee;
92 -  The person who smokes Pall Mall has birds;
94 -  The yellow house’s owner smokes Dunhill;
96 -  In the house in the center lives someone who drinks milk;
98 -  The Norwegian lives in the first house;
100 -  The man who smokes Blends lives next to the one who has cats;
102 -  The man who owns a horse lives next to the one who smokes Dunhills;
104 -  The man who smokes Blue Masters drinks beer;
106 -  The German smokes Prince;
108 -  The Norwegian lives next to the blue house;
110 -  The man who smokes Blends has a neighbour who drinks water.
112 The question is: What is the nationality of the fish’s owner?
114 We start by introducing a general-purpose theory defining the notion of
115 *bijection*, as two abstract types together with two functions from one
116 to the other and two axioms stating that these functions are inverse of
117 each other.
119 .. code-block:: whyml
121     theory Bijection
122       type t
123       type u
125       function of t : u
126       function to_ u : t
128       axiom To_of : forall x : t. to_ (of x) = x
129       axiom Of_to : forall y : u. of (to_ y) = y
130     end
132 We now start a new theory, ``Einstein``, which will contain all the
133 individuals of the problem.
135 .. code-block:: whyml
137     theory Einstein
139 First, we introduce enumeration types for houses, colors, persons,
140 drinks, cigars, and pets.
142 .. code-block:: whyml
144       type house  = H1 | H2 | H3 | H4 | H5
145       type color  = Blue | Green | Red | White | Yellow
146       type person = Dane | Englishman | German | Norwegian | Swede
147       type drink  = Beer | Coffee | Milk | Tea | Water
148       type cigar  = Blend | BlueMaster | Dunhill | PallMall | Prince
149       type pet    = Birds | Cats | Dogs | Fish | Horse
151 We now express that each house is associated bijectively to a color, by
152 *cloning* the ``Bijection`` theory appropriately.
154 .. code-block:: whyml
156       clone Bijection as Color with type t = house, type u = color
158 Cloning a theory makes a copy of all its declarations, possibly in
159 combination with a user-provided substitution
160 (see :numref:`Module Cloning`).
161 Here we substitute type
162 ``house`` for type ``t`` and type ``color`` for type ``u``. As a result,
163 we get two new functions, namely ``Color.of`` and ``Color.to_``, from
164 houses to colors and colors to houses, respectively, and two new axioms
165 relating them. Similarly, we express that each house is associated
166 bijectively to a person
168 .. code-block:: whyml
170       clone Bijection as Owner with type t = house, type u = person
172 and that drinks, cigars, and pets are all associated bijectively to
173 persons:
175 .. code-block:: whyml
177       clone Bijection as Drink with type t = person, type u = drink
178       clone Bijection as Cigar with type t = person, type u = cigar
179       clone Bijection as Pet   with type t = person, type u = pet
181 Next, we need a way to state that a person lives next to another. We
182 first define a predicate ``leftof`` over two houses.
184 .. code-block:: whyml
186       predicate leftof (h1 h2 : house) =
187         match h1, h2 with
188         | H1, H2
189         | H2, H3
190         | H3, H4
191         | H4, H5 -> true
192         | _      -> false
193         end
195 Note how we advantageously used pattern matching, with an or-pattern for
196 the four positive cases and a universal pattern for the remaining 21
197 cases. It is then immediate to define a ``neighbour`` predicate over two
198 houses, which completes theory ``Einstein``.
200 .. code-block:: whyml
202       predicate rightof (h1 h2 : house) =
203         leftof h2 h1
204       predicate neighbour (h1 h2 : house) =
205         leftof h1 h2 \/ rightof h1 h2
206     end
208 The next theory contains the 15 hypotheses. It starts by importing
209 theory ``Einstein``.
211 .. code-block:: whyml
213     theory EinsteinHints
214       use Einstein
216 Then each hypothesis is stated in terms of ``to_`` and ``of`` functions.
217 For instance, the hypothesis “The Englishman lives in a red house” is
218 declared as the following axiom.
220 .. code-block:: whyml
222       axiom Hint1: Color.of (Owner.to_ Englishman) = Red
224 And so on for all other hypotheses, up to “The man who smokes Blends has
225 a neighbour who drinks water”, which completes this theory.
227 .. code-block:: whyml
229       ...
230       axiom Hint15:
231         neighbour (Owner.to_ (Cigar.to_ Blend)) (Owner.to_ (Drink.to_ Water))
232     end
234 Finally, we declare the goal in a fourth theory:
236 .. code-block:: whyml
238     theory Problem
239       use Einstein
240       use EinsteinHints
242       goal G: Pet.to_ Fish = German
243     end
245 and we can use Why3 to discharge this goal with any prover of our
246 choice.
248 .. code-block:: console
250     $ why3 prove -P alt-ergo einstein.why
251     einstein.why Goals G: Valid (1.27s, 989 steps)
253 The source code for this puzzle is available in the source distribution
254 of Why3, in file :file:`examples/logic/einstein.why`.
256 .. _sec.maxandsum:
258 Problem 1: Sum and Maximum
259 --------------------------
261 Let us now move to the problems of the VSTTE 2010 verification
262 competition :cite:`vstte10comp`. The first problem is stated
263 as follows:
265     Given an :math:`N`-element array of natural numbers, write a program
266     to compute the sum and the maximum of the elements in the array.
268 We assume :math:`N \ge 0` and :math:`a[i] \ge 0` for
269 :math:`0 \le i < N`, as precondition, and we have to prove the following
270 postcondition:
272 .. math:: sum \le N \times max.
274 In a file :file:`max_sum.mlw`, we start a new module:
276 .. code-block:: whyml
278     module MaxAndSum
280 We are obviously needing arithmetic, so we import the corresponding
281 theory, exactly as we would do within a theory definition:
283 .. code-block:: whyml
285       use int.Int
287 We are also going to use references and arrays from Why3 standard
288 library, so we import the corresponding modules:
290 .. code-block:: whyml
292       use ref.Ref
293       use array.Array
295 Modules ``Ref`` and ``Array`` respectively provide a type ``ref ’a`` for
296 references and a type ``array ’a`` for arrays, together with useful
297 operations and traditional syntax. They are loaded from the WhyML files
298 :file:`ref.mlw` and :file:`array.mlw` in the standard library.
300 We are now in position to define a program function ``max_sum``. A
301 function definition is introduced with the keyword ``let``. In our case,
302 it introduces a function with two arguments, an array ``a`` and its size
303 ``n``:
305 .. code-block:: whyml
307       let max_sum (a: array int) (n: int) : (int, int) = ...
309 (There is a function ``length`` to get the size of an array but we add
310 this extra parameter ``n`` to stay close to the original problem
311 statement.) The function body is a Hoare triple, that is a precondition,
312 a program expression, and a postcondition.
314 .. code-block:: whyml
316       let max_sum (a: array int) (n: int) : (int, int)
317         requires { n = length a }
318         requires { forall i. 0 <= i < n -> a[i] >= 0 }
319         ensures  { let (sum, max) = result in sum <= n * max }
320       = ... expression ...
322 The first precondition expresses that ``n`` is equal to the length of
323 ``a`` (this will be needed for verification conditions related to array
324 bound checking). The second precondition expresses that all elements of
325 ``a`` are non-negative. The postcondition decomposes the value returned
326 by the function as a pair of integers ``(sum, max)`` and states the
327 required property.
329 .. code-block:: whyml
331         returns { sum, max -> sum <= n * max }
333 We are now left with the function body itself, that is a code computing
334 the sum and the maximum of all elements in ``a``. With no surprise, it
335 is as simple as introducing two local references
337 .. code-block:: whyml
339         let sum = ref 0 in
340         let max = ref 0 in
342 scanning the array with a ``for`` loop, updating ``max`` and ``sum``
344 .. code-block:: whyml
346         for i = 0 to n - 1 do
347           if !max < a[i] then max := a[i];
348           sum := !sum + a[i]
349         done;
351 and finally returning the pair of the values contained in ``sum`` and
352 ``max``:
354 .. code-block:: whyml
356       !sum, !max
358 This completes the code for function ``max_sum``. As such, it cannot be
359 proved correct, since the loop is still lacking a loop invariant. In
360 this case, the loop invariant is as simple as ``!sum <= i * !max``,
361 since the postcondition only requires us to prove ``sum <= n * max``.
362 The loop invariant is introduced with the keyword ``invariant``,
363 immediately after the keyword ``do``:
365 .. code-block:: whyml
367         for i = 0 to n - 1 do
368           invariant { !sum <= i * !max }
369           ...
370         done
372 There is no need to introduce a variant, as the termination of a ``for``
373 loop is automatically guaranteed. This completes module ``MaxAndSum``,
374 shown below.
376 .. code-block:: whyml
378     module MaxAndSum
380       use int.Int
381       use ref.Ref
382       use array.Array
384       let max_sum (a: array int) (n: int) : (int, int)
385         requires { n = length a }
386         requires { forall i. 0 <= i < n -> a[i] >= 0 }
387         returns  { sum, max -> sum <= n * max }
388       = let sum = ref 0 in
389         let max = ref 0 in
390         for i = 0 to n - 1 do
391           invariant { !sum <= i * !max }
392           if !max < a[i] then max := a[i];
393           sum := !sum + a[i]
394         done;
395         !sum, !max
397     end
399 We can now proceed to its verification. Running :program:`why3`, or better
400 :why3:tool:`why3 ide`, on file :file:`max_sum.mlw` shows a single verification
401 condition with name ``WP max_sum``. Discharging this verification
402 condition requires a little bit of non-linear arithmetic. Thus some SMT
403 solvers may fail at proving it, but other succeed, *e.g.*, CVC4.
405 Note: It is of course possible to *execute* the code to test it,
406 before or after you prove it correct. This is detailed in
407 :numref:`sec.execute`.
409 .. index:: auto-dereference
410 .. rubric:: Auto-dereference
412 Why3 features an auto-dereferencing mechanism, which simplifies the use of
413 references. When a reference is introduced using ``let ref x`` (instead
414 of ``let x = ref``), the use of operator ``!`` to access its value
415 is not needed anymore. For instance, we can rewrite the program above
416 as follows (the contract being unchanged and omitted):
418 .. code-block:: whyml
420     let max_sum (a: array int) (n: int) : (sum: int, max: int)
421     = let ref sum = 0 in
422       let ref max = 0 in
423       for i = 0 to n - 1 do
424         invariant { sum <= i * max }
425         if max < a[i] then max <- a[i];
426         sum <- sum + a[i]
427       done;
428       sum, max
430 Note that use of operator ``<-`` for assignment (instead of ``:=``)
431 and the absence of ``!`` both in the loop invariant and in the program.
432 See :numref:`auto-dereference` for more details about the
433 auto-dereferencing mechanism.
436 Problem 2: Inverting an Injection
437 ---------------------------------
439 The second problem is stated as follows:
441     Invert an injective array :math:`A` on :math:`N` elements in the
442     subrange from :math:`0` to :math:`N - 1`, the output array :math:`B`
443     must be such that :math:`B[A[i]] = i` for :math:`0 \le i < N`.
445 The code is immediate, since it is as simple as
447 .. code-block:: whyml
449         for i = 0 to n - 1 do b[a[i]] <- i done
451 so it is more a matter of specification and of getting the proof done
452 with as much automation as possible. In a new file, we start a new
453 module and we import arithmetic and arrays:
455 .. code-block:: whyml
457     module InvertingAnInjection
458       use int.Int
459       use array.Array
461 It is convenient to introduce predicate definitions for the properties
462 of being injective and surjective. These are purely logical
463 declarations:
465 .. code-block:: whyml
467       predicate injective (a: array int) (n: int) =
468         forall i j. 0 <= i < n -> 0 <= j < n -> i <> j -> a[i] <> a[j]
470       predicate surjective (a: array int) (n: int) =
471         forall i. 0 <= i < n -> exists j: int. (0 <= j < n /\ a[j] = i)
473 It is also convenient to introduce the predicate “being in the subrange
474 from 0 to :math:`n-1`”:
476 .. code-block:: whyml
478       predicate range (a: array int) (n: int) =
479         forall i. 0 <= i < n -> 0 <= a[i] < n
481 Using these predicates, we can formulate the assumption that any
482 injective array of size :math:`n` within the range :math:`0..n-1` is
483 also surjective:
485 .. code-block:: whyml
487       lemma injective_surjective:
488         forall a: array int, n: int.
489           injective a n -> range a n -> surjective a n
491 We declare it as a lemma rather than as an axiom, since it is actually
492 provable. It requires induction and can be proved using the Coq proof
493 assistant for instance. Finally we can give the code a specification,
494 with a loop invariant which simply expresses the values assigned to
495 array ``b`` so far:
497 .. code-block:: whyml
499       let inverting (a: array int) (b: array int) (n: int)
500         requires { n = length a = length b }
501         requires { injective a n /\ range a n }
502         ensures  { injective b n }
503       = for i = 0 to n - 1 do
504           invariant { forall j. 0 <= j < i -> b[a[j]] = j }
505           b[a[i]] <- i
506         done
508 Here we chose to have array ``b`` as argument; returning a freshly
509 allocated array would be equally simple. The whole module is given below.
510 The verification conditions for function
511 ``inverting`` are easily discharged automatically, thanks to the lemma.
513 .. code-block:: whyml
515     module InvertingAnInjection
517       use int.Int
518       use array.Array
520       predicate injective (a: array int) (n: int) =
521         forall i j. 0 <= i < n -> 0 <= j < n -> i <> j -> a[i] <> a[j]
523       predicate surjective (a: array int) (n: int) =
524         forall i. 0 <= i < n -> exists j: int. (0 <= j < n /\ a[j] = i)
526       predicate range (a: array int) (n: int) =
527         forall i. 0 <= i < n -> 0 <= a[i] < n
529       lemma injective_surjective:
530         forall a: array int, n: int.
531           injective a n -> range a n -> surjective a n
533       let inverting (a: array int) (b: array int) (n: int)
534         requires { n = length a = length b }
535         requires { injective a n /\ range a n }
536         ensures  { injective b n }
537       = for i = 0 to n - 1 do
538           invariant { forall j. 0 <= j < i -> b[a[j]] = j }
539           b[a[i]] <- i
540         done
542     end
544 Problem 3: Searching a Linked List
545 ----------------------------------
547 The third problem is stated as follows:
549     Given a linked list representation of a list of integers, find the
550     index of the first element that is equal to 0.
552 More precisely, the specification says
554     You have to show that the program returns an index *i* equal
555     to the length of the list if there is no such element. Otherwise,
556     the *i*-th element of the list must be equal to 0, and all the
557     preceding elements must be non-zero.
559 Since the list is not mutated, we can use the algebraic data type of
560 polymorphic lists from Why3’s standard library, defined in theory
561 ``list.List``. It comes with other handy theories: ``list.Length``,
562 which provides a function ``length``, and ``list.Nth``, which provides a
563 function ``nth`` for the nth element of a list. The latter
564 returns an option type, depending on whether the index is meaningful or
565 not.
567 .. code-block:: whyml
569     module SearchingALinkedList
570       use int.Int
571       use option.Option
572       use export list.List
573       use export list.Length
574       use export list.Nth
576 It is helpful to introduce two predicates: a first one for a successful
577 search,
579 .. code-block:: whyml
581       predicate zero_at (l: list int) (i: int) =
582         nth i l = Some 0 /\ forall j. 0 <= j < i -> nth j l <> Some 0
584 and a second one for a non-successful search,
586 .. code-block:: whyml
588       predicate no_zero (l: list int) =
589         forall j. 0 <= j < length l -> nth j l <> Some 0
591 We are now in position to give the code for the search function. We
592 write it as a recursive function ``search`` that scans a list for the
593 first zero value:
595 .. code-block:: whyml
597       let rec search (i: int) (l: list int) : int =
598         match l with
599         | Nil      -> i
600         | Cons x r -> if x = 0 then i else search (i+1) r
601         end
603 Passing an index ``i`` as first argument allows to perform a tail call.
604 A simpler code (yet less efficient) would return 0 in the first branch
605 and ``1 + search ...`` in the second one, avoiding the extra argument
606 ``i``.
608 We first prove the termination of this recursive function. It amounts to
609 giving it a *variant*, that is a value that strictly decreases at each
610 recursive call with respect to some well-founded ordering. Here it is as
611 simple as the list ``l`` itself:
613 .. code-block:: whyml
615       let rec search (i: int) (l: list int) : int variant { l } = ...
617 It is worth pointing out that variants are not limited to values of
618 algebraic types. A non-negative integer term (for example, ``length l``)
619 can be used, or a term of any other type equipped with a well-founded
620 order relation. Several terms can be given, separated with commas, for
621 lexicographic ordering.
623 There is no precondition for function ``search``. The postcondition
624 expresses that either a zero value is found, and consequently the value
625 returned is bounded accordingly,
627 .. code-block:: whyml
629       i <= result < i + length l /\ zero_at l (result - i)
631 or no zero value was found, and thus the returned value is exactly ``i``
632 plus the length of ``l``:
634 .. code-block:: whyml
636       result = i + length l /\ no_zero l
638 Solving the problem is simply a matter of calling ``search`` with 0 as
639 first argument. The code is given below. The
640 verification conditions are all discharged automatically.
642 .. code-block:: whyml
644     module SearchingALinkedList
646       use int.Int
647       use export list.List
648       use export list.Length
649       use export list.Nth
651       predicate zero_at (l: list int) (i: int) =
652         nth i l = Some 0 /\ forall j. 0 <= j < i -> nth j l <> Some 0
654       predicate no_zero (l: list int) =
655         forall j. 0 <= j < length l -> nth j l <> Some 0
657       let rec search (i: int) (l: list int) : int variant { l }
658         ensures { (i <= result < i + length l /\ zero_at l (result - i))
659                \/ (result = i + length l /\ no_zero l) }
660       = match l with
661         | Nil -> i
662         | Cons x r -> if x = 0 then i else search (i+1) r
663         end
665       let search_list (l: list int) : int
666         ensures { (0 <= result < length l /\ zero_at l result)
667                \/ (result = length l /\ no_zero l) }
668       = search 0 l
670     end
672 Alternatively, we can implement the search with a ``while`` loop. To do
673 this, we need to import references from the standard library, together
674 with theory ``list.HdTl`` which defines functions ``hd`` and ``tl`` over
675 lists.
677 .. code-block:: whyml
679       use ref.Ref
680       use list.HdTl
682 Being partial functions, ``hd`` and ``tl`` return options. For the
683 purpose of our code, though, it is simpler to have functions which do
684 not return options, but have preconditions instead. Such a function
685 ``head`` is defined as follows:
687 .. code-block:: whyml
689       let head (l: list 'a) : 'a
690         requires { l <> Nil } ensures { hd l = Some result }
691       = match l with Nil -> absurd | Cons h _ -> h end
693 The program construct ``absurd`` denotes an unreachable piece of code.
694 It generates the verification condition ``false``, which is here
695 provable using the precondition (the list cannot be ``Nil``). Function
696 ``tail`` is defined similarly:
698 .. code-block:: whyml
700       let tail (l: list 'a) : list 'a
701         requires { l <> Nil } ensures { tl l = Some result }
702       = match l with Nil -> absurd | Cons _ t -> t end
704 Using ``head`` and ``tail``, it is straightforward to implement the
705 search as a ``while`` loop. It uses a local reference ``i`` to store the
706 index and another local reference ``s`` to store the list being scanned.
707 As long as ``s`` is not empty and its head is not zero, it increments
708 ``i`` and advances in ``s`` using function ``tail``.
710 .. code-block:: whyml
712       let search_loop (l: list int) : int
713         ensures { ... same postcondition as in search_list ... }
714       = let i = ref 0 in
715         let s = ref l in
716         while not (is_nil !s) && head !s <> 0 do
717           invariant { ... }
718           variant   { !s }
719           i := !i + 1;
720           s := tail !s
721         done;
722         !i
724 The postcondition is exactly the same as for function ``search_list``.
725 The termination of the ``while`` loop is ensured using a variant,
726 exactly as for a recursive function. Such a variant must strictly
727 decrease at each execution of the loop body. The reader is invited to
728 figure out the loop invariant.
730 Problem 4: N-Queens
731 -------------------
733 The fourth problem is probably the most challenging one. We have to
734 verify the implementation of a program which solves the *N*-queens
735 puzzle: place *N* queens on an *N*×*N* chess board so
736 that no queen can capture another one with a legal move. The program
737 should return a placement if there is a solution and indicates that
738 there is no solution otherwise. A placement is a *N*-element array
739 which assigns the queen on row *i* to its column. Thus we start
740 our module by importing arithmetic and arrays:
742 .. code-block:: whyml
744     module NQueens
745       use int.Int
746       use array.Array
748 The code is a simple backtracking algorithm, which tries to put a queen
749 on each row of the chess board, one by one (there is basically no better
750 way to solve the *N*-queens puzzle). A building block is a
751 function which checks whether the queen on a given row may attack
752 another queen on a previous row. To verify this function, we first
753 define a more elementary predicate, which expresses that queens on row
754 ``pos`` and ``q`` do no attack each other:
756 .. code-block:: whyml
758       predicate consistent_row (board: array int) (pos: int) (q: int) =
759         board[q] <> board[pos] /\
760         board[q] - board[pos] <> pos - q /\
761         board[pos] - board[q] <> pos - q
763 Then it is possible to define the consistency of row ``pos`` with
764 respect to all previous rows:
766 .. code-block:: whyml
768       predicate is_consistent (board: array int) (pos: int) =
769         forall q. 0 <= q < pos -> consistent_row board pos q
771 Implementing a function which decides this predicate is another matter.
772 In order for it to be efficient, we want to return ``False`` as soon as
773 a queen attacks the queen on row ``pos``. We use an exception for this
774 purpose and it carries the row of the attacking queen:
776 .. code-block:: whyml
778       exception Inconsistent int
780 The check is implemented by a function ``check_is_consistent``, which
781 takes the board and the row ``pos`` as arguments, and scans rows from 0
782 to ``pos - 1`` looking for an attacking queen. As soon as one is found,
783 the exception is raised. It is caught immediately outside the loop and
784 ``False`` is returned. Whenever the end of the loop is reached, ``True``
785 is returned.
787 .. code-block:: whyml
789       let check_is_consistent (board: array int) (pos: int) : bool
790         requires { 0 <= pos < length board }
791         ensures  { result <-> is_consistent board pos }
792       = try
793           for q = 0 to pos - 1 do
794             invariant {
795               forall j:int. 0 <= j < q -> consistent_row board pos j
796             }
797             let bq   = board[q]   in
798             let bpos = board[pos] in
799             if bq        = bpos    then raise (Inconsistent q);
800             if bq - bpos = pos - q then raise (Inconsistent q);
801             if bpos - bq = pos - q then raise (Inconsistent q)
802           done;
803           True
804         with Inconsistent q ->
805           assert { not (consistent_row board pos q) };
806           False
807         end
809 The assertion in the exception handler is a cut for SMT solvers. This
810 first part of the solution is given below.
812 .. code-block:: whyml
814     module NQueens
815       use int.Int
816       use array.Array
818       predicate consistent_row (board: array int) (pos: int) (q: int) =
819         board[q] <> board[pos] /\
820         board[q] - board[pos] <> pos - q /\
821         board[pos] - board[q] <> pos - q
823       predicate is_consistent (board: array int) (pos: int) =
824         forall q. 0 <= q < pos -> consistent_row board pos q
826       exception Inconsistent int
828       let check_is_consistent (board: array int) (pos: int)
829         requires { 0 <= pos < length board }
830         ensures  { result <-> is_consistent board pos }
831       = try
832           for q = 0 to pos - 1 do
833             invariant {
834               forall j:int. 0 <= j < q -> consistent_row board pos j
835             }
836             let bq   = board[q]   in
837             let bpos = board[pos] in
838             if bq        = bpos    then raise (Inconsistent q);
839             if bq - bpos = pos - q then raise (Inconsistent q);
840             if bpos - bq = pos - q then raise (Inconsistent q)
841           done;
842           True
843         with Inconsistent q ->
844           assert { not (consistent_row board pos q) };
845           False
846         end
848 We now proceed with the verification of the backtracking algorithm. The
849 specification requires us to define the notion of solution, which is
850 straightforward using the predicate ``is_consistent`` above. However,
851 since the algorithm will try to complete a given partial solution, it is
852 more convenient to define the notion of partial solution, up to a given
853 row. It is even more convenient to split it in two predicates, one
854 related to legal column values and another to consistency of rows:
856 .. code-block:: whyml
858       predicate is_board (board: array int) (pos: int) =
859         forall q. 0 <= q < pos -> 0 <= board[q] < length board
861       predicate solution (board: array int) (pos: int) =
862         is_board board pos /\
863         forall q. 0 <= q < pos -> is_consistent board q
865 The algorithm will not mutate the partial solution it is given and, in
866 case of a search failure, will claim that there is no solution extending
867 this prefix. For this reason, we introduce a predicate comparing two
868 chess boards for equality up to a given row:
870 .. code-block:: whyml
872       predicate eq_board (b1 b2: array int) (pos: int) =
873         forall q. 0 <= q < pos -> b1[q] = b2[q]
875 The search itself makes use of an exception to signal a successful
876 search:
878 .. code-block:: whyml
880       exception Solution
882 The backtracking code is a recursive function ``bt_queens`` which takes
883 the chess board, its size, and the starting row for the search. The
884 termination is ensured by the obvious variant ``n - pos``.
886 .. code-block:: whyml
888       let rec bt_queens (board: array int) (n: int) (pos: int) : unit
889         variant  { n - pos }
891 The precondition relates ``board``, ``pos``, and ``n`` and requires
892 ``board`` to be a solution up to ``pos``:
894 .. code-block:: whyml
896         requires { 0 <= pos <= n = length board }
897         requires { solution board pos }
899 The postcondition is twofold: either the function exits normally and
900 then there is no solution extending the prefix in ``board``, which has
901 not been modified; or the function raises ``Solution`` and we have a
902 solution in ``board``.
904 .. code-block:: whyml
906         ensures  { eq_board board (old board) pos }
907         ensures  { forall b:array int. length b = n -> is_board b n ->
908                      eq_board board b pos -> not (solution b n) }
909         raises   { Solution -> solution board n }
910       =
912 Whenever we reach the end of the chess board, we have found a solution
913 and we signal it using exception ``Solution``:
915 .. code-block:: whyml
917         if pos = n then raise Solution;
919 Otherwise we scan all possible positions for the queen on row ``pos``
920 with a ``for`` loop:
922 .. code-block:: whyml
924         for i = 0 to n - 1 do
926 The loop invariant states that we have not modified the solution prefix
927 so far, and that we have not found any solution that would extend this
928 prefix with a queen on row ``pos`` at a column below ``i``:
930 .. code-block:: whyml
932           invariant { eq_board board (old board) pos }
933           invariant { forall b:array int.  length b = n -> is_board b n ->
934             eq_board board b pos -> 0 <= b[pos] < i -> not (solution b n) }
936 Then we assign column ``i`` to the queen on row ``pos`` and we check for
937 a possible attack with ``check_is_consistent``. If not, we call
938 ``bt_queens`` recursively on the next row.
940 .. code-block:: whyml
942           board[pos] <- i;
943           if check_is_consistent board pos then bt_queens board n (pos + 1)
944         done
946 This completes the loop and function ``bt_queens`` as well. Solving the
947 puzzle is a simple call to ``bt_queens``, starting the search on row 0.
948 The postcondition is also twofold, as for ``bt_queens``, yet slightly
949 simpler.
951 .. code-block:: whyml
953       let queens (board: array int) (n: int) : unit
954         requires { length board = n }
955         ensures  { forall b:array int.
956                      length b = n -> is_board b n -> not (solution b n) }
957         raises   { Solution -> solution board n }
958       = bt_queens board n 0
960 This second part of the solution is given below. With
961 the help of a few auxiliary lemmas — not given here but available from
962 Why3’s sources — the verification conditions are all discharged
963 automatically, including the verification of the lemmas themselves.
965 .. code-block:: whyml
967       predicate is_board (board: array int) (pos: int) =
968         forall q. 0 <= q < pos -> 0 <= board[q] < length board
970       predicate solution (board: array int) (pos: int) =
971         is_board board pos /\
972         forall q. 0 <= q < pos -> is_consistent board q
974       predicate eq_board (b1 b2: array int) (pos: int) =
975         forall q. 0 <= q < pos -> b1[q] = b2[q]
977       exception Solution
979       let rec bt_queens (board: array int) (n: int) (pos: int) : unit
980         variant  { n - pos }
981         requires { 0 <= pos <= n = length board }
982         requires { solution board pos }
983         ensures  { eq_board board (old board) pos }
984         ensures  { forall b:array int. length b = n -> is_board b n ->
985                      eq_board board b pos -> not (solution b n) }
986         raises   { Solution -> solution board n }
987       = if pos = n then raise Solution;
988         for i = 0 to n - 1 do
989           invariant { eq_board board (old board) pos }
990           invariant { forall b:array int. length b = n -> is_board b n ->
991             eq_board board b pos -> 0 <= b[pos] < i -> not (solution b n) }
992           board[pos] <- i;
993           if check_is_consistent board pos then bt_queens board n (pos + 1)
994         done
996       let queens (board: array int) (n: int) : unit
997         requires { length board = n }
998         ensures  { forall b:array int.
999                      length b = n -> is_board b n -> not (solution b n) }
1000         raises   { Solution -> solution board n }
1001       = bt_queens board n 0
1003     end
1005 .. _sec.aqueue:
1007 Problem 5: Amortized Queue
1008 --------------------------
1010 The last problem consists in verifying the implementation of a
1011 well-known purely applicative data structure for queues. A queue is
1012 composed of two lists, *front* and *rear*. We push elements at the head
1013 of list *rear* and pop them off the head of list *front*. We maintain
1014 that the length of *front* is always greater or equal to the length of
1015 *rear*. (See for instance Okasaki’s *Purely Functional Data
1016 Structures* :cite:`okasaki98` for more details.)
1018 We have to implement operations ``empty``, ``head``, ``tail``, and
1019 ``enqueue`` over this data type, to show that the invariant over lengths
1020 is maintained, and finally
1021 to show that a client invoking these operations observes an abstract
1022 queue given by a sequence.
1024 In a new module, we import arithmetic and theory ``list.ListRich``, a
1025 combo theory that imports all list operations we will require: length,
1026 reversal, and concatenation.
1028 .. code-block:: whyml
1030     module AmortizedQueue
1031       use int.Int
1032       use option.Option
1033       use export list.ListRich
1035 The queue data type is naturally introduced as a polymorphic record
1036 type. The two list lengths are explicitly stored, for greater
1037 efficiency.
1039 .. code-block:: whyml
1041       type queue 'a = { front: list 'a; lenf: int;
1042                         rear : list 'a; lenr: int; }
1043       invariant { length front = lenf >= length rear = lenr }
1044       by { front = Nil; lenf = 0; rear = Nil; lenr = 0 }
1046 The type definition is accompanied with an invariant — a logical
1047 property imposed on any value of the type. Why3 assumes that any
1048 queue satisfies the invariant at any function entry and
1049 it requires that any queue satisfies the invariant at function exit
1050 (be the queue created or modified).
1051 The ``by`` clause ensures the non-vacuity of this type with
1052 invariant. If you omit it, a goal with an existential statement is
1053 generated. (See :numref:`Record Types` for more details about record
1054 types with invariants.)
1056 For the purpose of the specification, it is convenient to introduce a
1057 function ``sequence`` which builds the sequence of elements of a queue,
1058 that is the front list concatenated to the reversed rear list.
1060 .. code-block:: whyml
1062       function sequence (q: queue 'a) : list 'a = q.front ++ reverse q.rear
1064 It is worth pointing out that this function can only be used in
1065 specifications. We start with the easiest operation: building the empty
1066 queue.
1068 .. code-block:: whyml
1070       let empty () : queue 'a
1071         ensures { sequence result = Nil }
1072       = { front = Nil; lenf = 0; rear = Nil; lenr = 0 }
1074 The postcondition states that the returned queue represents the empty
1075 sequence. Another postcondition, saying that the returned queue
1076 satisfies the type invariant, is implicit. Note the cast to type
1077 ``queue 'a``. It is required, for the type checker not to complain about
1078 an undefined type variable.
1080 The next operation is ``head``, which returns the first element from a
1081 given queue ``q``. It naturally requires the queue to be non empty,
1082 which is conveniently expressed as ``sequence q`` not being ``Nil``.
1084 .. code-block:: whyml
1086       let head (q: queue 'a) : 'a
1087         requires { sequence q <> Nil }
1088         ensures  { hd (sequence q) = Some result }
1089       = let Cons x _ = q.front in x
1091 The fact that the argument ``q`` satisfies the type invariant is
1092 implicitly assumed. The type invariant is required to prove the
1093 absurdity of ``q.front`` being ``Nil`` (otherwise, ``sequence q`` would
1094 be ``Nil`` as well).
1096 The next operation is ``tail``, which removes the first element from a
1097 given queue. This is more subtle than ``head``, since we may have to
1098 re-structure the queue to maintain the invariant. Since we will have to
1099 perform a similar operation when implementing operation ``enqueue``
1100 later, it is a good idea to introduce a smart constructor ``create``
1101 that builds a queue from two lists while ensuring the invariant. The
1102 list lengths are also passed as arguments, to avoid unnecessary
1103 computations.
1105 .. code-block:: whyml
1107       let create (f: list 'a) (lf: int) (r: list 'a) (lr: int) : queue 'a
1108         requires { lf = length f /\ lr = length r }
1109         ensures  { sequence result = f ++ reverse r }
1110       = if lf >= lr then
1111           { front = f; lenf = lf; rear = r; lenr = lr }
1112         else
1113           let f = f ++ reverse r in
1114           { front = f; lenf = lf + lr; rear = Nil; lenr = 0 }
1116 If the invariant already holds, it is simply a matter of building the
1117 record. Otherwise, we empty the rear list and build a new front list as
1118 the concatenation of list ``f`` and the reversal of list ``r``. The
1119 principle of this implementation is that the cost of this reversal will
1120 be amortized over all queue operations. Implementing function ``tail``
1121 is now straightforward and follows the structure of function ``head``.
1123 .. code-block:: whyml
1125       let tail (q: queue 'a) : queue 'a
1126         requires { sequence q <> Nil }
1127         ensures  { tl (sequence q) = Some (sequence result) }
1128       = let Cons _ r = q.front in
1129         create r (q.lenf - 1) q.rear q.lenr
1131 The last operation is ``enqueue``, which pushes a new element in a given
1132 queue. Reusing the smart constructor ``create`` makes it a one line
1133 code.
1135 .. code-block:: whyml
1137       let enqueue (x: 'a) (q: queue 'a) : queue 'a
1138         ensures { sequence result = sequence q ++ Cons x Nil }
1139       = create q.front q.lenf (Cons x q.rear) (q.lenr + 1)
1141 The code is given below. The verification conditions are
1142 all discharged automatically.
1144 .. code-block:: whyml
1146     module AmortizedQueue
1148       use int.Int
1149       use option.Option
1150       use list.ListRich
1152       type queue 'a = { front: list 'a; lenf: int;
1153                         rear : list 'a; lenr: int; }
1154         invariant { length front = lenf >= length rear = lenr }
1155         by { front = Nil; lenf = 0; rear = Nil; lenr = 0 }
1157       function sequence (q: queue 'a) : list 'a =
1158         q.front ++ reverse q.rear
1160       let empty () : queue 'a
1161         ensures { sequence result = Nil }
1162       = { front = Nil; lenf = 0; rear = Nil; lenr = 0 }
1164       let head (q: queue 'a) : 'a
1165         requires { sequence q <> Nil }
1166         ensures  { hd (sequence q) = Some result }
1167       = let Cons x _ = q.front in x
1169       let create (f: list 'a) (lf: int) (r: list 'a) (lr: int) : queue 'a
1170         requires { lf = length f /\ lr = length r }
1171         ensures  { sequence result = f ++ reverse r }
1172       = if lf >= lr then
1173           { front = f; lenf = lf; rear = r; lenr = lr }
1174         else
1175           let f = f ++ reverse r in
1176           { front = f; lenf = lf + lr; rear = Nil; lenr = 0 }
1178       let tail (q: queue 'a) : queue 'a
1179         requires { sequence q <> Nil }
1180         ensures  { tl (sequence q) = Some (sequence result) }
1181       = let Cons _ r = q.front in
1182         create r (q.lenf - 1) q.rear q.lenr
1184       let enqueue (x: 'a) (q: queue 'a) : queue 'a
1185         ensures { sequence result = sequence q ++ Cons x Nil }
1186       = create q.front q.lenf (Cons x q.rear) (q.lenr + 1)
1188     end