2 (* The 2nd Verified Software Competition (VSTTE 2012)
3 https://sites.google.com/site/vstte2012/compet
6 Shortest path in a graph using breadth-first search *)
15 val predicate eq (x y: vertex)
16 ensures { result <-> x = y }
18 function succ vertex : fset vertex
20 (* there is a path of length n from v1 to v2 *)
21 inductive path (v1 v2: vertex) (n: int) =
23 forall v: vertex. path v v 0
25 forall v1 v2 v3: vertex, n: int.
26 path v1 v2 n -> mem v3 (succ v2) -> path v1 v3 (n+1)
28 (* path length is non-negative *)
30 forall v1 v2: vertex, n: int. path v1 v2 n -> n >= 0
32 (* a non-empty path has a last but one node *)
34 forall v1 v3: vertex, n: int. n >= 0 ->
36 exists v2: vertex. path v1 v2 n /\ mem v3 (succ v2)
38 (* a path starting in a set S that is closed under succ ends up in S *)
40 forall s: fset vertex.
41 (forall x: vertex. mem x s ->
42 forall y: vertex. mem y (succ x) -> mem y s) ->
43 forall v1 v2: vertex, n: int. path v1 v2 n ->
46 predicate shortest_path (v1 v2: vertex) (n: int) =
48 forall m: int. m < n -> not (path v1 v2 m)
56 clone set.SetImp as B with type elt = vertex, val eq = eq
61 (* global invariant *)
62 predicate inv (s t: vertex) (visited current next: fset vertex) (d: int) =
64 subset current visited /\
65 (forall x: vertex. mem x current -> shortest_path s x d) /\
67 subset next visited /\
68 (forall x: vertex. mem x next -> shortest_path s x (d + 1)) /\
70 (forall x: vertex, m: int. path s x m -> m <= d -> mem x visited) /\
71 (forall x: vertex. mem x visited ->
72 exists m: int. path s x m /\ m <= d+1) /\
73 (* nodes at distance d+1 are either in next or not yet visited *)
74 (forall x: vertex. shortest_path s x (d + 1) ->
75 mem x next \/ not (mem x visited)) /\
77 (mem t visited -> mem t current \/ mem t next)
79 (* visited\current\next is closed under succ *)
80 predicate closure (visited current next: fset vertex) (x: vertex) =
81 mem x visited -> not (mem x current) -> not (mem x next) ->
82 forall y: vertex. mem y (succ x) -> mem y visited
84 function (!!) (s: B.set) : fset vertex = B.to_fset s
86 val pick_succ (v: vertex) : B.set
87 ensures { !!result = succ v }
89 (* function fill_next fills set next with the unvisited successors of v *)
90 let fill_next (s t v: vertex) (visited current next: B.set) (d:ref int)
91 requires { inv s t !!visited !!current !!next !d /\
92 shortest_path s v !d /\
93 (forall x: vertex. x<> v -> closure !!visited !!current !!next x) }
94 ensures { inv s t !!visited !!current !!next !d /\
95 subset (succ v) !!visited /\
96 (forall x: vertex. closure !!visited !!current !!next x) }
97 = let acc = pick_succ v in
98 while not (B.is_empty acc) do
100 inv s t !!visited !!current !!next !d /\
101 subset !!acc (succ v) /\
102 subset (diff (succ v) !!acc) !!visited /\
103 (forall x: vertex. x <> v -> closure !!visited !!current !!next x)
105 variant { cardinal !!acc }
106 let w = B.choose_and_remove acc in
107 if not (B.mem w visited) then begin
113 let bfs (s: vertex) (t: vertex)
114 ensures { forall d: int. not (path s t d) }
115 raises { Found r -> shortest_path s t r }
116 diverges (* the set of reachable nodes may be infinite *)
117 = let visited = B.empty () in
118 let current = ref (B.empty ()) in
119 let next = ref (B.empty ()) in
123 while not (B.is_empty !current) do
125 inv s t !!visited !! !current !! !next !d /\
126 (is_empty !! !current -> is_empty !! !next) /\
127 (forall x: vertex. closure !!visited !! !current !! !next x) /\
130 let v = B.choose_and_remove !current in
131 if eq v t then raise (Found !d);
132 fill_next s t v visited !current !next d;
133 if B.is_empty !current then begin
134 (current.contents, next.contents) <- (!next, B.empty ());
138 assert { not (mem t !!visited) }