File: dijkstra.why

package info (click to toggle)
why 2.30%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 26,916 kB
  • sloc: ml: 116,979; java: 9,376; ansic: 5,175; makefile: 1,335; sh: 531; lisp: 127
file content (248 lines) | stat: -rw-r--r-- 7,022 bytes parent folder | download | duplicates (3)
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: 
*)