File: dijkstra.mlw

package info (click to toggle)
why3 1.8.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 45,028 kB
  • sloc: xml: 185,443; ml: 111,224; ansic: 3,998; sh: 2,578; makefile: 2,568; java: 865; python: 720; javascript: 290; lisp: 205; pascal: 173
file content (232 lines) | stat: -rw-r--r-- 6,996 bytes parent folder | download | duplicates (4)
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

(* Dijkstra's shortest path algorithm.

   This proof follows Cormen et al's "Algorithms".

   Author: Jean-Christophe Filliâtre (CNRS) *)

module ImpmapNoDom

  use map.Map
  use map.Const

  type key

  type t 'a = abstract { mutable contents: map key 'a }

  val function create (x: 'a): t 'a
    ensures { result.contents = const x }

  val function ([]) (m: t 'a) (k: key): 'a
    ensures { result = m.contents[k] }

  val ghost function ([<-]) (m: t 'a) (k: key) (v: 'a): t 'a
    ensures { result.contents = m.contents[k <- v] }

  val ([]<-) (m: t 'a) (k: key) (v: 'a): unit
    writes { m }
    ensures { m = (old m)[k <- v] }

end

module DijkstraShortestPath

  use int.Int
  use ref.Ref

  (** The graph is introduced as a set v of vertices and a function g_succ
     returning the successors of a given vertex.
     The weight of an edge is defined independently, using function weight.
     The weight is an integer. *)

  type vertex

  clone set.SetImp with type elt = vertex
  clone ImpmapNoDom with type key = vertex

  constant v: fset vertex

  val ghost function g_succ (_x: vertex) : fset vertex
    ensures { subset result v }

  val get_succs (x: vertex): set
    ensures { result = g_succ x  }

  val function weight vertex vertex : int (* edge weight, if there is an edge *)
    ensures { result >= 0 }

  (** Data structures for the algorithm. *)

  (* The set of already visited vertices. *)

  val visited: set

  (* Map d holds the current distances from the source.
     There is no need to introduce infinite distances. *)

  val d: t int

  (* The priority queue. *)

  val q: set

  predicate min (m: vertex) (q: set) (d: t int) =
    mem m q /\
    forall x: vertex. mem x q -> d[m] <= d[x]

  val q_extract_min () : vertex writes {q}
    requires { not is_empty q }
    ensures  { min result (old q) d }
    ensures  { q = remove result (old q) }

  (* Initialisation of visited, q, and d. *)

  val init (src: vertex) : unit writes { visited, q, d }
    ensures { is_empty visited }
    ensures { q = singleton src }
    ensures { d = (old d)[src <- 0] }

  (* Relaxation of edge u->v. *)

  let relax u v
    ensures {
      (mem v visited /\ q = old q /\ d = old d)
      \/
      (mem v q /\ d[u] + weight u v >= d[v] /\ q = old q /\ d = old d)
      \/
      (mem v q /\ (old d)[u] + weight u v < (old d)[v] /\
          q = old q /\ d = (old d)[v <- (old d)[u] + weight u v])
      \/
      (not mem v visited /\ not mem v (old q) /\
          q = add v (old q) /\
          d = (old d)[v <- (old d)[u] + weight u v]) }
  = if not mem v visited then
      let x = d[u] + weight u v in
      if mem v q then begin
        if x < d[v] then d[v] <- x
      end else begin
        add v q;
        d[v] <- x
      end

  (* 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 *)

  inductive path vertex vertex int =
    | Path_nil :
        forall x: vertex. path x x 0
    | Path_cons:
        forall x y z: vertex. forall d: int.
        path x y d -> mem z (g_succ y) -> path x z (d + weight y z)

  lemma Length_nonneg: forall x y: vertex. forall d: int. path x y d -> d >= 0

  predicate shortest_path (x y: vertex) (d: int) =
    path x y d /\ forall d': int. path x y d' -> d <= d'

  lemma Path_inversion:
    forall src v:vertex. forall d:int. path src v d ->
    (v = src /\ d = 0) \/
    (exists v':vertex. path src v' (d - weight v' v) /\ mem v (g_succ v'))

  lemma Path_shortest_path:
    forall src v: vertex. forall d: int. path src v d ->
    exists d': int. shortest_path src v d' /\ d' <= d

  (* Lemmas (requiring induction). *)

  lemma Main_lemma:
    forall src v: vertex. forall d: int.
    path src v d -> not (shortest_path src v d) ->
    v = src /\ d > 0
    \/
    exists v': vertex. exists d': int.
      shortest_path src v' d' /\ mem v (g_succ v') /\ d' + weight v' v < d

  lemma Completeness_lemma:
    forall s: set.
    (* if s is closed under g_succ *)
    (forall v: vertex.
       mem v s -> forall w: vertex. mem w (g_succ v) -> mem w s) ->
    (* and if s contains src *)
    forall src: vertex. mem src s ->
    (* then any vertex reachable from s is also in s *)
    forall dst: vertex. forall d: int.
    path src dst d -> mem dst s

  (* Definitions used in loop invariants. *)

  predicate inv_src (src: vertex) (s q: set) =
    mem src s \/ mem src q

  predicate inv (src: vertex) (s q: set) (d: t int) =
    inv_src src s q /\ d[src] = 0 /\
    (* S and Q are contained in V *)
    subset s v /\ subset q v /\
    (* S and Q are disjoint *)
    (forall v: vertex. mem v q -> mem v s -> false) /\
    (* we already found the shortest paths for vertices in S *)
    (forall v: vertex. mem v s -> shortest_path src v d[v]) /\
    (* there are paths for vertices in Q *)
    (forall v: vertex. mem v q -> path src v d[v])

  predicate inv_succ (_src: vertex) (s q: set) (d: t int) =
    (* successors of vertices in S are either in S or in Q *)
    forall x: vertex. mem x s ->
    forall y: vertex. mem y (g_succ x) ->
    (mem y s \/ mem y q) /\ d[y] <= d[x] + weight x y

  predicate inv_succ2 (_src: vertex) (s q: set) (d: t int) (u: vertex) (su: 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. mem x s ->
    forall y: vertex. mem y (g_succ x) ->
    (x<>u \/ (x=u /\ not (mem y su))) ->
    (mem y s \/ mem y q) /\ d[y] <= d[x] + weight x y

 lemma inside_or_exit:
    forall s, src, v, d. mem src s -> path src v d ->
      mem v s
      \/
      exists y. exists z. exists dy.
        mem y s /\ not (mem z s) /\ mem z (g_succ y) /\
        path src y dy /\ (dy + weight y z <= d)

  (* Algorithm's code. *)

  let shortest_path_code (src dst: vertex)
    requires { mem src v /\ mem dst v }
    ensures  { forall v: vertex. mem v visited ->
                 shortest_path src v d[v] }
    ensures  { forall v: vertex. not mem v visited ->
                 forall dv: int. not path src v dv }
  = init src;
    while not is_empty q do
      invariant { inv src visited q d }
      invariant { inv_succ src visited q d }
      invariant { (* vertices at distance < min(Q) are already in S *)
                  forall m: vertex. min m q d ->
                  forall x: vertex. forall dx: int. path src x dx ->
                  dx < d[m] -> mem x visited }
      variant   { cardinal v - cardinal visited }
      let u = q_extract_min () in
      assert { shortest_path src u d[u] };
      add u visited;
      let su = get_succs u in
      while not is_empty su do
        invariant { subset su (g_succ u) }
        invariant { inv src visited q d  }
        invariant { inv_succ2 src visited q d u su }
        variant   { cardinal su }
        let v = choose_and_remove su in
        relax u v;
        assert { d[v] <= d[u] + weight u v }
      done
    done

  end