1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
(* finite sets *)
type 'a set
logic set_empty : 'a set
logic set_add : 'a, 'a set -> 'a set
logic set_rmv : 'a, 'a set -> 'a set
logic In : 'a, 'a set -> prop
predicate Is_empty(s : 'a set) = forall x:'a. not In(x, s)
predicate Incl(s1 : 'a set, s2 : 'a set) = forall x:'a. In(x, s1) -> In(x, s2)
axiom set_empty_def : Is_empty(set_empty)
axiom set_add_def :
forall x:'a. forall y:'a. forall s:'a set.
In(x, set_add(y,s)) <-> (x = y or In(x, s))
axiom set_rmv_def :
forall x:'a. forall y:'a. forall s:'a set.
In(x, set_rmv(y,s)) <-> (x <> y and In(x, s))
logic set_card : 'a set -> int
axiom card_nonneg :
forall s:'a set. set_card(s) >= 0
axiom card_set_add :
forall x:'a. forall s:'a set.
not In(x,s) -> set_card(set_add(x,s)) = 1 + set_card(s)
axiom card_set_rmv :
forall x:'a. forall s:'a set.
In(x,s) -> set_card(s) = 1 + set_card(set_rmv(x, s))
axiom card_Incl :
forall s1,s2 : 'a set. Incl(s1,s2) -> set_card(s1) <= set_card(s2)
(* iteration on a set *)
parameter set_has_next :
s:'a set ref ->
{} bool reads s { if result then Is_empty(s) else not Is_empty(s) }
parameter set_next :
s:'a set ref ->
{ not Is_empty(s) } 'a writes s { In(result,s@) and s = set_rmv(result,s@) }
(* maps *)
type ('a, 'b) map
logic map_get : ('a,'b) map, 'a -> 'b
logic map_set : ('a,'b) map, 'a, 'b -> ('a, 'b) map
axiom map_get_set_eq :
forall m : ('a,'b) map . forall i : 'a. forall v : 'b.
map_get(map_set(m,i,v), i) = v
axiom map_get_set_neq :
forall m : ('a, 'b) map. forall i : 'a. forall j : 'a. forall v : 'b.
i <> j -> map_get(map_set(m,i,v), j) = map_get(m,j)
(* graph *)
type vertex
logic V : vertex set
logic g_succ : vertex -> vertex set
axiom g_succ_sound :
forall x:vertex. Incl(g_succ(x), V)
logic weight : vertex, vertex -> int (* edge weight, if there is an edge *)
axiom weight_nonneg : forall x,y:vertex. weight(x,y) >= 0
parameter eq_vertex :
x:vertex -> y:vertex -> {} bool { if result then x=y else x<>y }
(* visited vertices *)
parameter S : vertex set ref
parameter S_add :
x:vertex -> {} unit writes S { S = set_add(x, S@) }
(* current distances *)
parameter d : (vertex, int) map ref
(* priority queue *)
parameter Q : vertex set ref
parameter Q_is_empty :
unit ->
{} bool reads Q { if result then Is_empty(Q) else not Is_empty(Q) }
parameter init :
src:vertex ->
{}
unit writes S,Q,d
{ Is_empty(S) and
Q = set_add(src, set_empty) and
d = map_set(d@, src, 0) }
parameter relax :
u:vertex -> v:vertex ->
{}
unit reads S writes d,Q
{ (In(v,S) and Q = Q@ and d = d@)
or
(In(v,Q) and map_get(d,u) + weight(u,v) >= map_get(d,v) and
Q = Q@ and d = d@)
or
(In(v,Q) and map_get(d,u) + weight(u,v) < map_get(d,v) and
Q = Q@ and d = map_set(d@, v, map_get(d,u) + weight(u,v)))
or
(not In(v,S) and not In(v,Q) and Q = set_add(v,Q@) and
d = map_set(d@, v, map_get(d,u) + weight(u,v))) }
predicate Min(m:vertex, Q:vertex set, d:(vertex, int) map) =
In(m, Q) and forall x:vertex. In(x, Q) -> map_get(d,x) <= map_get(d,m)
parameter Q_extract_min :
unit ->
{ not Is_empty(Q) }
vertex reads d writes Q
{ Min(result, Q@, d) and Q = set_rmv(result, Q@) }
(* paths and shortest paths
path(x,y,d) =
there is a path from x to y of length d
shortest_path(x,y,d) =
there is a path from x to y of length d, and no shorter path *)
logic path : vertex, vertex, int -> prop
axiom path_nil :
forall x:vertex. path(x,x,0)
axiom path_cons :
forall x,y,z:vertex. forall d:int.
path(x,y,d) -> In(z,g_succ(y)) -> path(x,z,d+weight(y,z))
axiom length_nonneg : forall x,y:vertex. forall d:int. path(x,y,d) -> d >= 0
predicate shortest_path(x:vertex, y:vertex, d:int) =
path(x,y,d) and forall d':int. path(x,y,d') -> d <= d'
axiom path_inversion :
forall src,v:vertex. forall d:int. path(src,v,d) ->
(v = src and d = 0) or
(exists v':vertex. path(src,v',d - weight(v',v)) and In(v,g_succ(v')))
axiom path_shortest_path :
forall src,v:vertex. forall d:int. path(src,v,d) ->
exists d':int. shortest_path(src,v,d') and d' <= d
(* lemmas (those requiring induction) *)
axiom main_lemma :
forall src,v:vertex. forall d:int.
path(src,v,d) -> not shortest_path(src,v,d) ->
exists v':vertex. exists d':int.
shortest_path(src,v',d') and In(v,g_succ(v')) and d' + weight(v',v) < d
axiom completeness_lemma :
forall s:vertex set. forall src:vertex. forall dst:vertex. forall d:int.
(* if s is closed under g_succ *)
(forall v:vertex. In(v,s) -> forall w:vertex. In(w,g_succ(v)) -> In(w,s))
->
(* and if s contains src *)
In(src, s) ->
(* then any vertex reachable from s is also in s *)
path(src, dst, d) -> In(dst, s)
(* definitions used in loop invariants *)
predicate Inv_src(src:vertex, S:vertex set, Q:vertex set) =
In(src,S) or In(src,Q)
predicate Inv(src:vertex, S:vertex set, Q:vertex set, d:(vertex,int) map) =
Inv_src(src, S, Q)
(* S,Q are contained in V *)
and Incl(S,V) and Incl(Q,V)
(* S and Q are disjoint *)
and
(forall v:vertex. In(v,Q) -> In(v,S) -> false)
(* we already found the shortest paths for vertices in S *)
and
(forall v:vertex. In(v,S) -> shortest_path(src,v,map_get(d,v)))
(* there are paths for vertices in Q *)
and
(forall v:vertex. In(v,Q) -> path(src,v,map_get(d,v)))
(* vertices at distance < min(Q) are already in S *)
and
(forall m:vertex. Min(m,Q,d) ->
forall x:vertex. forall dx:int. shortest_path(src,x,dx) ->
dx < map_get(d,m) -> In(x,S))
predicate InvSucc(src:vertex, S:vertex set, Q: vertex set) =
(* successors of vertices in S are either in S or in Q *)
(forall x:vertex. In(x, S) ->
forall y:vertex. In(y,g_succ(x)) -> In(y, S) or In(y, Q))
predicate InvSucc2(src:vertex, S:vertex set, Q: vertex set,
u:vertex, su:vertex set) =
(* successors of vertices in S are either in S or in Q,
unless they are successors of u still in su *)
(forall x:vertex. In(x, S) ->
forall y:vertex. In(y,g_succ(x)) ->
(x<>u or (x=u and not In(y,su))) -> In(y, S) or In(y, Q))
(* code *)
let shortest_path (src:vertex) (dst:vertex) =
{ In(src,V) and In(dst,V) }
init src;
while not (Q_is_empty void) do
{ invariant
Inv(src, S, Q, d) and InvSucc(src, S, Q)
variant
set_card(V) - set_card(S) }
let u = Q_extract_min void in
assert { shortest_path(src, u, map_get(d,u)) };
S_add u;
let su = ref (g_succ u) in
while not (set_has_next su) do
{ invariant
Incl(su,g_succ(u)) and
Inv(src, S, Q, d) and InvSucc2(src, S, Q, u, su)
variant
set_card(su) }
let v = set_next su in
relax u v
done
done
{ (forall v:vertex. In(v,S) -> shortest_path(src,v,map_get(d,v)))
and
(forall v:vertex. not In(v,S) -> forall dv:int. not path(src,v,dv)) }
(*
Local Variables:
compile-command: "gwhy dijkstra.why"
End:
*)
|