Commit 9bcb4076 by Jean-Christophe Filliâtre

### added solutions for VerifyThis 2017

parent af08d5c4
 (* VerifyThis 2017 challenge 2 (** Maximum-sum submatrix (2D version of Kadane's algorithm) {1 VerifyThis @ ETAPS 2017 competition Challenge 2: Maximum-sum submatrix} See https://formal.iti.kit.edu/ulbrich/verifythis2017/ Author: Jean-Christophe Filliâtre (CNRS) *) (* note: this is a 2D-version of maximum-sum subarray, for which several verified implementations can be found in maximum_subarray.mlw, including Kadane's linear algorithm *) module Kadane2D use import int.Int ... ...
 ... ... @@ -5,7 +5,7 @@ ... ...
 (** {1 VerifyThis @ ETAPS 2017 competition Challenge 3: Odd-Even Transposition Sort} See https://formal.iti.kit.edu/ulbrich/verifythis2017/ Author: Jean-Christophe Filliâtre (CNRS) *) (* note: this is only a solution for the sequential (single processor) version of the challenge *) module Challenge3 use import int.Int use import int.Sum use import int.NumOf use import int.ComputerDivision use import ref.Refint use import array.Array use import array.IntArraySorted use import array.ArraySwap use import array.ArrayPermut (* odd-sorted up to n exclusive *) predicate odd_sorted (a: array int) (n: int) = forall i. 0 <= i -> 2*i + 2 < n -> a[2*i+1] <= a[2*i+2] (* even-sorted up to n exclusive *) predicate even_sorted (a: array int) (n: int) = forall i. 0 <= i -> 2*i + 1 < n -> a[2*i] <= a[2*i+1] let lemma odd_even_sorted (a: array int) (n: int) requires { 0 <= n <= length a } requires { odd_sorted a n } requires { even_sorted a n } ensures { sorted_sub a 0 n } = if n > 0 && length a > 0 then for i = 1 to n - 1 do invariant { sorted_sub a 0 i } assert { forall j. 0 <= j < i -> a[j] <= a[i] by a[i-1] <= a[i] by i-1 = 2 * div (i-1) 2 \/ i-1 = 2 * div (i-1) 2 + 1 } done (* to prove termination, we count the total number of inversions *) predicate inversion (a: array int) (i j: int) = a[i] > a[j] function inversions_for (a: array int) (i: int) : int = numof (inversion a i) i (length a) function inversions (a: array int) : int = sum (inversions_for a) 0 (length a) (* the key lemma to prove termination: whenever we swap two consecutive values that are ill-sorted, the total number of inversions decreases *) let lemma exchange_inversion (a1 a2: array int) (i0: int) requires { 0 <= i0 < length a1 - 1 } requires { a1[i0] > a1[i0 + 1] } requires { exchange a1 a2 i0 (i0 + 1) } ensures { inversions a2 < inversions a1 } = assert { inversion a1 i0 (i0+1) }; assert { not (inversion a2 i0 (i0+1)) }; assert { forall i. 0 <= i < i0 -> inversions_for a2 i = inversions_for a1 i by numof (inversion a2 i) i (length a2) = numof (inversion a2 i) i i0 + numof (inversion a2 i) i0 (i0+1) + numof (inversion a2 i) (i0+1) (i0+2) + numof (inversion a2 i) (i0+2) (length a2) /\ numof (inversion a1 i) i (length a1) = numof (inversion a1 i) i i0 + numof (inversion a1 i) i0 (i0+1) + numof (inversion a1 i) (i0+1) (i0+2) + numof (inversion a1 i) (i0+2) (length a1) /\ numof (inversion a2 i) i0 (i0+1) = numof (inversion a1 i) (i0+1) (i0+2) /\ numof (inversion a2 i) (i0+1) (i0+2) = numof (inversion a1 i) i0 (i0+1) /\ numof (inversion a2 i) i i0 = numof (inversion a1 i) i i0 /\ numof (inversion a2 i) (i0+2) (length a2) = numof (inversion a1 i) (i0+2) (length a1) }; assert { forall i. i0 + 1 < i < length a1 -> inversions_for a2 i = inversions_for a1 i }; assert { inversions_for a2 i0 = inversions_for a1 (i0+1) by numof (inversion a1 (i0+1)) (i0+2) (length a1) = numof (inversion a2 i0 ) (i0+2) (length a1) }; assert { 1 + inversions_for a2 (i0+1) = inversions_for a1 i0 by numof (inversion a1 i0) i0 (length a1) = numof (inversion a1 i0) (i0+1) (length a1) = 1 + numof (inversion a1 i0) (i0+2) (length a1) }; let sum_decomp (a: array int) (i j k: int) requires { 0 <= i <= j <= k <= length a = length a1 } ensures { sum (inversions_for a) i k = sum (inversions_for a) i j + sum (inversions_for a) j k } = () in let decomp (a: array int) requires { length a = length a1 } ensures { inversions a = sum (inversions_for a) 0 i0 + inversions_for a i0 + inversions_for a (i0+1) + sum (inversions_for a) (i0+2) (length a) } = sum_decomp a 0 i0 (length a); sum_decomp a i0 (i0+1) (length a); sum_decomp a (i0+1) (i0+2) (length a); in decomp a1; decomp a2; () (* note: program variable "sorted" renamed into "is_sorted" (clash with library predicate "sorted" on arrays) *) let odd_even_transposition_sort (a: array int) ensures { sorted a } ensures { permut_all (old a) a } = let is_sorted = ref false in while not !is_sorted do invariant { permut_all (old a) a } invariant { !is_sorted -> sorted a } variant { if !is_sorted then 0 else 1, inversions a } is_sorted := true; let i = ref 1 in let ghost half_i = ref 0 in label L in while !i < length a - 1 do invariant { 0 <= !half_i /\ 0 <= !i = 2 * !half_i + 1 } invariant { permut_all (old a) a } invariant { odd_sorted a !i } invariant { if !is_sorted then inversions a = inversions (a at L) else inversions a < inversions (a at L) } variant { length a - !i } if a[!i] > a[!i+1] then begin swap a !i (!i+1); is_sorted := false; end; i := !i + 2; ghost half_i := !half_i + 1 done; assert { odd_sorted a (length a) }; i := 0; ghost half_i := 0; while !i < length a - 1 do invariant { 0 <= !half_i /\ 0 <= !i = 2 * !half_i } invariant { 0 <= !i } invariant { permut_all (old a) a } invariant { !is_sorted -> odd_sorted a (length a) } invariant { even_sorted a !i } invariant { if !is_sorted then inversions a = inversions (a at L) else inversions a < inversions (a at L) } invariant { !is_sorted \/ inversions a < inversions (a at L) } variant { length a - !i } if a[!i] > a[!i+1] then begin swap a !i (!i+1); is_sorted := false; end; i := !i + 2; ghost half_i := !half_i + 1 done; assert { !is_sorted -> even_sorted a (length a) } done end