4 {1 VerifyThis @ ETAPS 2015 competition, Challenge 1: Relaxed Prefix}
8 The following is the original description of the verification task,
9 reproduced verbatim from
10 <a href="http://etaps2015.verifythis.org/challenges">the competition web site</a>.
13 RELAXED PREFIX (60 minutes)
14 ===========================
20 Verify a function isRelaxedPrefix determining if a list _pat_ (for
21 pattern) is a relaxed prefix of another list _a_.
23 The relaxed prefix property holds iff _pat_ is a prefix of _a_ after
24 removing at most one element from _pat_.
30 pat = {1,3} is a relaxed prefix of a = {1,3,2,3} (standard prefix)
32 pat = {1,2,3} is a relaxed prefix of a = {1,3,2,3} (remove 2 from pat)
34 pat = {1,2,4} is not a relaxed prefix of a = {1,3,2,3}.
40 You can implement lists as arrays, e.g., of integers. A reference
41 implementation is given below. It may or may not contain errors.
44 public class Relaxed {
46 public static boolean isRelaxedPrefix(int[] pat, int[] a) {
49 for(int i=0; i<pat.length; i++) {
50 if (pat[i]!=a[i-shift])
51 if (shift==0) shift=1;
58 public static void main(String[] argv) {
61 System.out.println(isRelaxedPrefix(pat, a1));
68 Advanced verification task (if you get bored)
69 ---------------------------------------------
71 Implement and verify a function relaxedContains(pat, a) returning
72 whether _a_ contains _pat_ in the above relaxed sense, i.e., whether
73 _pat_ is a relaxed prefix of any suffix of _a_.
76 The following is the solution by Jean-Christophe FilliĆ¢tre (CNRS)
77 and Guillaume Melquiond (Inria) who entered the competition as "team Why3".
88 val eq (x y : char) : bool ensures { result = True <-> x = y }
90 (** `a1[ofs1..ofs1+len]` and `a2[ofs2..ofs2+len]` are valid sub-arrays
92 predicate eq_array (a1: array char) (ofs1: int)
93 (a2: array char) (ofs2: int) (len: int) =
94 0 <= len /\ 0 <= ofs1 /\ 0 <= ofs2 /\
95 ofs1 + len <= length a1 /\ ofs2 + len <= length a2 /\
96 forall i: int. 0 <= i < len -> a1[ofs1 + i] = a2[ofs2 + i]
98 (** The target property. *)
100 predicate is_relaxed_prefix (pat a: array char) =
101 let n = length pat in
103 \/ exists i: int. 0 <= i < n /\
104 eq_array pat 0 a 0 i /\
105 eq_array pat (i+1) a i (n - i - 1)
107 (** This exception is used to exit the loop as soon as the target
108 property is no more possible. *)
112 (** Note regarding the code: the suggested pseudo-code is buggy, as it
113 may access `a` out of bounds. We fix it by strengthening the
114 test in the conditional. *)
116 let is_relaxed_prefix (pat a: array char) : bool
117 ensures { result <-> is_relaxed_prefix pat a }
119 let n = length pat in
123 let ghost ignored = ref 0 in
124 for i = 0 to n - 1 do
125 invariant { 0 <= !shift <= 1 }
126 invariant { !shift = 1 -> 0 <= !ignored < i }
127 invariant { m + !shift >= i }
129 if !shift = 0 then eq_array pat 0 a 0 i
130 else eq_array pat 0 a 0 !ignored /\
131 eq_array pat (!ignored + 1) a !ignored (i - !ignored - 1) /\
132 not (eq_array pat 0 a 0 i) /\
133 (!ignored < m -> pat[!ignored] <> a[!ignored]) }
134 if i - !shift >= m || not (eq pat[i] a[i - !shift]) then begin
135 if !shift = 1 then begin
136 assert { forall j. eq_array pat 0 a 0 j ->
137 eq_array pat (j+1) a j (n-j-1) ->
138 !ignored > j -> pat[j+1+(i-j-1)] = a[j+(i-j-1)]