Anagrammi
Verification of a short BASIC program from Umberto Eco's novel Foucault's Pendulum.
Authors: Jean-Christophe Filliâtre
Topics: Words
Tools: Why3
see also the index (by topic, by tool, by reference, by year)
Anagrammi
In Umberto Eco's "Foucault's Pendulum" (Il pendolo di Foucault, 1988), there is a short BASIC program that computes the 24 permutations of four letters. It is as follows:
10 REM anagrammi
20 INPUT L$(1), L$(2), L$(3), L$(4)
30 PRINT
40 FOR I1 = 1 TO 4
50 FOR I2 = 1 TO 4
60 IF I2=I1 THEN 130
70 FOR I3 = 1 TO 4
80 IF I3=I1 THEN 120
90 IF I3=i2 THEN 120
100 LET I4 = 10-(I1+I2+I3)
110 LPRINT L$(I1); L$(I2); L$(I3); L$(I4)
120 NEXT I3
130 NEXT I2
140 NEXT I1
150 END
Note: In the French edition (Grasset, 2013), there is a typo
on line 80, with =11 instead of =I1. And the dollar symbols
are replaced with the letter S.
I could not resist implementing it in WhyML and verifying it, which is a simple, yet enjoyable, exercise.
Author: Jean-Christophe Filliâtre (CNRS)
use int.Int use seq.Seq use seq.Mem use seq.Distinct type line = seq int
A line printed on the output by the program is a sequence of (4) integers.
predicate perm4 (s: line) = length s = 4 && (forall i. 0 <= i < 4 -> 1 <= s[i] <= 4) && distinct s
The line s is a permutation of 1234.
predicate lt (s1 s2: line) = exists i. 0 <= i < 4 && s1[i] < s2[i] && forall j. 0 <= j < i -> s1[j] = s2[j]
The program outputs the permutations in lexicographic order, so we introduce this order relation.
lemma lt_trans: forall s1 s2 s3. perm4 s1 -> perm4 s2 -> perm4 s3 -> lt s1 s2 -> lt s2 s3 -> lt s1 s3 predicate sorted (o: seq line) = (* only permutations *) (forall j. 0 <= j < length o -> perm4 o[j]) && (* and they are sorted (and thus all distinct) *) (forall j1 j2. 0 <= j1 < j2 < length o -> lt o[j1] o[j2])
A sequence of lines contains only permutations and is sorted.
predicate below (o: seq line) (pr: line -> bool) = sorted o && (forall j. 0 <= j < length o -> pr o[j]) && (forall s. perm4 s -> pr s -> mem s o)
A sequence of lines is sorted and contains exactly
the permutations satisfying predicate pr.
function pr1 (i1: int) : line->bool = fun s -> s[0]<i1 function pr2 (i1 i2: int) : line->bool = fun s -> pr1 i1 s || s[0]=i1 && s[1]<i2 function pr3 (i1 i2 i3: int) : line->bool = fun s -> pr2 i1 i2 s || s[0]=i1 && s[1]=i2 && s[2]<i3
Shortcut predicates for the loop invariants below:
val ref output: seq line
The output of the program is modeled with the following global variable that contains a sequence of lines.
let anagrammi () : unit requires { output = empty } ensures { below output (fun _ -> true) } = for i1 = 1 to 4 do invariant { below output (pr1 i1) } for i2 = 1 to 4 do invariant { below output (pr2 i1 i2) } if i2 = i1 then continue; for i3 = 1 to 4 do invariant { below output (pr3 i1 i2 i3) } if i3 = i1 then continue; if i3 = i2 then continue; let i4 = 10 - (i1+i2+i3) in (* LPRINT L$(I1); L$(I2); L$(I3); L$(I4) *) let line = cons i1 (cons i2 (cons i3 (cons i4 empty))) in assert { line[0] = i1 && line[1] = i2 && line[2] = i3 && line[3] = i4 }; assert { perm4 line }; output <- snoc output line done done done
download ZIP archive
Why3 Proof Results for Project "anagrammi"
Theory "anagrammi.Top": fully verified
| Obligations | Alt-Ergo 2.4.0 | CVC5 1.0.2 | Z3 4.8.10 | ||||||||||
| lt_trans | --- | --- | 0.03 | ||||||||||
| VC for anagrammi | --- | --- | --- | ||||||||||
| split_vc | |||||||||||||
| loop invariant init | --- | --- | 0.05 | ||||||||||
| loop invariant init | --- | --- | 0.03 | ||||||||||
| loop invariant preservation | 0.04 | --- | --- | ||||||||||
| loop invariant init | --- | --- | 0.02 | ||||||||||
| loop invariant preservation | 0.05 | --- | --- | ||||||||||
| loop invariant preservation | 0.05 | --- | --- | ||||||||||
| assertion | --- | --- | 0.09 | ||||||||||
| assertion | 0.32 | --- | --- | ||||||||||
| loop invariant preservation | --- | --- | --- | ||||||||||
| unfold below | |||||||||||||
| VC for anagrammi | --- | --- | --- | ||||||||||
| split_vc | |||||||||||||
| VC for anagrammi | --- | --- | --- | ||||||||||
| unfold sorted | |||||||||||||
| VC for anagrammi | --- | --- | --- | ||||||||||
| split_vc | |||||||||||||
| VC for anagrammi | --- | 0.17 | --- | ||||||||||
| VC for anagrammi | --- | --- | --- | ||||||||||
| case (length output = 1) | |||||||||||||
| true case | --- | --- | 0.07 | ||||||||||
| false case | --- | --- | --- | ||||||||||
| case (j2 = length output - 1) | |||||||||||||
| false case (true case) | --- | --- | --- | ||||||||||
| case (pr1 i1 output[j1]) | |||||||||||||
| false case (true case) | --- | --- | --- | ||||||||||
| unfold lt | |||||||||||||
| VC for anagrammi | --- | --- | --- | ||||||||||
| exists 0 | |||||||||||||
| anagrammi'vc.8.0.0.0.1.1.0.0.0.0 | --- | 0.20 | --- | ||||||||||
| false case (true case) | --- | --- | --- | ||||||||||
| case (pr2 i1 i2 output[j1]) | |||||||||||||
| false case (true case) | --- | 0.23 | --- | ||||||||||
| false case (true case) | --- | 0.28 | --- | ||||||||||
| false case | --- | 0.25 | --- | ||||||||||
| VC for anagrammi | --- | 0.25 | --- | ||||||||||
| VC for anagrammi | --- | --- | --- | ||||||||||
| case (s[2] = i3) | |||||||||||||
| true case | --- | --- | --- | ||||||||||
| case (s[1] = i2) | |||||||||||||
| true case | --- | --- | --- | ||||||||||
| case (s[0] = i1) | |||||||||||||
| true case | --- | --- | --- | ||||||||||
| assert (s[3] = i4) | |||||||||||||
| asserted formula | --- | 0.56 | --- | ||||||||||
| true case | --- | --- | --- | ||||||||||
| assert (s == line) | |||||||||||||
| asserted formula | --- | 0.30 | --- | ||||||||||
| true case | --- | --- | 0.09 | ||||||||||
| false case (true case) | --- | --- | 0.13 | ||||||||||
| false case (true case) | --- | 0.28 | --- | ||||||||||
| false case | --- | 0.28 | --- | ||||||||||
| loop invariant preservation | --- | --- | 0.07 | ||||||||||
| loop invariant preservation | 0.06 | --- | --- | ||||||||||
| loop invariant preservation | --- | --- | 0.08 | ||||||||||
| loop invariant preservation | --- | 0.08 | 0.03 | ||||||||||
| postcondition | --- | --- | 0.05 | ||||||||||
| postcondition | --- | --- | 0.04 | ||||||||||