Files
why3/examples/search.mlw
Jean-Christophe Filliatre 8a0c430844 cleaning up
2023-12-14 20:01:43 +01:00

147 lines
4.3 KiB
Plaintext

(** Search Algorithms
Author: Jean-Christophe Filliâtre (CNRS)
*)
module Path
use export int.Int
use export seq.Seq
type state
val function moves (s: state) : seq state
val constant start: state
val predicate success (s: state)
inductive path state state int =
| Path0: forall s. path s s 0
| Path1: forall s i. 0 <= i < length (moves s) ->
path s (moves s)[i] 1
| Patht: forall s t u n m. path s t n -> path t u m -> path s u (n+m)
predicate move (s t: state) =
exists i. 0 <= i < length (moves s) /\ t = (moves s)[i]
let lemma path_inversion (s t: state) (n: int)
requires { path s t n }
ensures { n = 0 /\ s = t
\/ n > 0 /\ exists i. 0 <= i < length (moves s) /\
path (moves s)[i] t (n-1) }
= () (* by induction_pr *)
let lemma path_length (s t: state) (n: int)
requires { path s t n } ensures { n >= 0 }
= ()
let lemma path_first (s t: state) (n: int) : (s': state)
requires { path s t n } requires { n > 0 }
ensures { move s s' }
ensures { path s' t (n-1) }
= for i = 0 to length (moves s) - 1 do
invariant { forall j. 0 <= j < i -> not (path (moves s)[j] t (n-1)) }
let s' = (moves s)[i] in
if path s' t (n-1) then return s';
done;
absurd
let rec lemma path_inversion_right (s t: state) (n: int)
requires { path s t n }
ensures { n = 0 /\ s = t
\/ n > 0 /\ exists s'. path s s' (n-1) /\ move s' t }
variant { n }
= if n > 0 then path_inversion_right (path_first s t n) t (n-1)
let rec lemma path_last (s t: state) (n: int) : (t': state)
requires { path s t n } requires { n > 0 }
ensures { path s t' (n-1) } ensures { move t' t }
variant { n }
= if n = 1 then s else path_last (path_first s t n) t (n-1)
let rec lemma shorter_path (s t: state) (n m: int) : (r: state)
requires { path s t n } requires { 0 <= m <= n }
ensures { path s r m }
variant { n }
= if n = 0 || m = 0 then s else shorter_path (path_first s t n) t (n-1) (m-1)
type outcome =
| NoSolution
| Solution state int
end
module Bfs
use Path
use seq.Mem
let bfs () : (o: outcome)
ensures { match o with
| NoSolution -> forall t n. success t -> not (path start t n)
| Solution t n -> path start t n
end }
diverges
= let ref cur = cons start empty in
let ref p = 0 in
while length cur > 0 do
invariant { p >= 0 }
invariant { forall i. 0 <= i < length cur -> path start cur[i] p }
invariant { forall t. path start t p -> mem t cur }
invariant { forall t n. path start t n -> success t -> n >= p }
let ref nxt = empty in
for i = 0 to length cur - 1 do
invariant { forall l. 0 <= l < length nxt ->
exists j. 0 <= j < i /\ move cur[j] nxt[l] }
invariant { forall j k. 0 <= j < i -> 0 <= k < length (moves cur[j]) ->
mem (moves cur[j])[k] nxt }
invariant { forall j. 0 <= j < i -> not (success cur[j]) }
let s = cur[i] in
if success s then return (Solution s p);
nxt <- moves s ++ nxt
done;
cur <- nxt;
p <- p+1
done;
return NoSolution
end
module Dfs
use Path
let rec dfs (m: int) (s: state) (p: int) : (o: outcome)
requires { 0 <= p <= m+1 }
ensures { match o with
| NoSolution -> forall t n.
0 <= n <= m-p -> success t -> not (path s t n)
| Solution t n -> path s t n /\ success t /\ 0 <= n <= m-p
end }
variant { m - p }
= if p > m then return NoSolution;
if success s then return (Solution s 0);
let mv = moves s in
for i = 0 to length mv - 1 do
invariant { forall j t n. 0 <= j < i -> path mv[j] t n ->
success t -> 0 <= n < m-p -> false }
match dfs m mv[i] (p+1) with
| Solution t n -> return (Solution t (n+1))
| NoSolution -> ()
end
done;
return NoSolution
let dfs_max (m: int) : (o: outcome)
requires { 0 <= m }
ensures { match o with
| NoSolution -> forall t n.
0 <= n <= m -> success t -> not (path start t n)
| Solution t n -> path start t n /\ n <= m
end }
= dfs m start 0
end