File: fmap.mlw

package info (click to toggle)
why3 1.8.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 45,020 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 (344 lines) | stat: -rw-r--r-- 8,855 bytes parent folder | download | duplicates (2)
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344

(** {1 Finite Domain Maps} *)

(** {2 Polymorphic finite domain maps}

To be used in specifications and ghost code only

 *)

module Fmap

  use int.Int
  use map.Map
  use set.Fset as S

  type fmap 'k 'v = abstract {
    contents: 'k -> 'v;
      domain: S.fset 'k;
  }
  meta coercion function contents

  predicate (==) (m1 m2: fmap 'k 'v) =
    S.(==) m1.domain m2.domain /\
    forall k. S.mem k m1.domain -> m1[k] = m2[k]

  axiom extensionality:
    forall m1 m2: fmap 'k 'v. m1 == m2 -> m1 = m2

  meta extensionality predicate (==)

  predicate mem (k: 'k) (m: fmap 'k 'v) =
    S.mem k m.domain

  predicate mapsto (k: 'k) (v: 'v) (m: fmap 'k 'v) =
    mem k m /\ m[k] = v

  lemma mem_mapsto:
    forall k: 'k, m: fmap 'k 'v. mem k m -> mapsto k m[k] m

  predicate is_empty (m: fmap 'k 'v) =
    S.is_empty m.domain

  function mk (d: S.fset 'k) (m: 'k -> 'v) : fmap 'k 'v

  axiom mk_domain:
    forall d: S.fset 'k, m: 'k -> 'v. domain (mk d m) = d

  axiom mk_contents:
    forall d: S.fset 'k, m: 'k -> 'v, k: 'k.
    S.mem k d -> (mk d m)[k] = m[k]

  constant empty: fmap 'k 'v

  axiom is_empty_empty: is_empty (empty: fmap 'k 'v)

  function add (k: 'k) (v: 'v) (m: fmap 'k 'v) : fmap 'k 'v

  function ([<-]) (m: fmap 'k 'v) (k: 'k) (v: 'v) : fmap 'k 'v =
    add k v m

  (*** FIXME? (add k v m).contents = m.contents[k <- v] *)

  axiom add_contents_k:
    forall k v, m: fmap 'k 'v. (add k v m)[k] = v

  axiom add_contents_other:
    forall k v, m: fmap 'k 'v, k1. mem k1 m -> k1 <> k -> (add k v m)[k1] = m[k1]

  axiom add_domain:
    forall k v, m: fmap 'k 'v. (add k v m).domain = S.add k m.domain

  (*** FIXME? find_opt (k: 'k) (m: fmap 'k 'v) : option 'v *)

  function find (k: 'k) (m: fmap 'k 'v) : 'v

  axiom find_def:
    forall k, m: fmap 'k 'v. mem k m -> find k m = m[k]

  function remove (k: 'k) (m: fmap 'k 'v) : fmap 'k 'v

  axiom remove_contents:
    forall k, m: fmap 'k 'v, k1. mem k1 m -> k1 <> k -> (remove k m)[k1] = m[k1]

  axiom remove_domain:
    forall k, m: fmap 'k 'v. (remove k m).domain = S.remove k m.domain

  function size (m: fmap 'k 'v) : int =
    S.cardinal m.domain

end


(** {3 Some additional fmap operators and their properties}

Mainly inspired from set theory a la B

*)

module Fmap_ext

use map.Map
use set.Fset as S
use export Fmap

function dom (m: fmap 'k 'v) : S.fset 'k = m.domain
(** An abbreviation for the domain *)

function apply (m: fmap 'k 'v) (x: 'k): 'v
(** map application *)

axiom apply_result:
  forall m: fmap 'k 'v, x.  mem x m -> mapsto x (apply m x) m
meta "remove_unused:dependency" axiom apply_result, function apply

function remove_set (s: S.fset 'k) (m: fmap 'k 'v) : fmap 'k 'v
(** domain anti-restriction, `<<|` in B *)

axiom remove_set_contents:
  forall m: fmap 'k 'v, s: S.fset 'k, x. mem x m -> not(S.mem x s) -> (remove_set s m)[x] = m[x]
meta "remove_unused:dependency" axiom remove_set_contents, function remove_set

axiom remove_set_domain:
  forall m: fmap 'k 'v, s: S.fset 'k. (remove_set s m).domain = S.diff m.domain s
meta "remove_unused:dependency" axiom remove_set_domain, function remove_set

function domain_res (s: S.fset 'k) (m: fmap 'k 'v) : fmap 'k 'v
(** domain restriction, `<|` in B *)

axiom domain_res_contents:
  forall m: fmap 'k 'v, s: S.fset 'k, x.
    mem x m -> S.mem x s -> (domain_res s m)[x] = m[x]
meta "remove_unused:dependency" axiom domain_res_contents, function domain_res

axiom domain_res_domain:
    forall m: fmap 'k 'v, s: S.fset 'k. (domain_res s m).domain = S.inter m.domain s
meta "remove_unused:dependency" axiom domain_res_domain, function domain_res

function override (m1 m2: fmap 'k 'v) : fmap 'k 'v
(** map override, `<+` in B *)

axiom override_contents_1:
  forall m1, m2: fmap 'k 'v, x. S.mem x m2.domain -> (override m1 m2)[x] = m2[x]
meta "remove_unused:dependency" axiom override_contents_1, function override

axiom override_contents_2:
  forall m1, m2: fmap 'k 'v, x.
    S.mem x (S.diff m1.domain m2.domain) -> (override m1 m2)[x] = m1[x]
meta "remove_unused:dependency" axiom override_contents_2, function override

axiom override_domain:
    forall m1, m2: fmap 'k 'v. (override m1 m2).domain = S.union m1.domain m2.domain
meta "remove_unused:dependency" axiom override_domain, function override

end

(** {3 Some additional facts about operators above}

They are automatically proven, see session `examples/stdlib/fmap`

*)

module Fmap_ext_facts

use set.Fset as S
use Fmap_ext

lemma anti_res_1 :
  forall u :  S.fset 'k , m :  fmap 'k 'v.
    S.inter m.domain u = S.empty -> remove_set u m == m
meta "remove_unused:dependency" lemma anti_res_1, function remove_set

lemma anti_res_2 :
  forall u :  S.fset 'k , m :  fmap 'k 'v.
    S.subset m.domain u -> remove_set u m == empty
meta "remove_unused:dependency" lemma anti_res_2, function remove_set

lemma anti_res_3 :
  forall m :  fmap 'k 'v. remove_set m.domain m == empty
meta "remove_unused:dependency" lemma anti_res_3, function remove_set

lemma anti_res_4 :
  forall m :  fmap 'k 'v. remove_set S.empty m == m
meta "remove_unused:dependency" lemma anti_res_4, function remove_set

lemma anti_res_res :
  forall u, v :  S.fset 'k , m :  fmap 'k 'v.
    remove_set u (domain_res v m) == domain_res (S.diff v u) m
meta "remove_unused:dependency" lemma anti_res_res, function remove_set

lemma anti_res_anti_res :
  forall u, v :  S.fset 'k , m :  fmap 'k 'v.
    remove_set u (remove_set v m) == remove_set (S.union v u) m
meta "remove_unused:dependency" lemma anti_res_anti_res, function remove_set

lemma anti_res_override_res :
  forall u, m1, m2 :  fmap 'k 'v.
    remove_set u (override m1 m2) == override (remove_set u m1)  (remove_set u m2)
meta "remove_unused:dependency" lemma anti_res_override_res, function remove_set
meta "remove_unused:dependency" lemma anti_res_override_res, function override

lemma remove_remove_set :
  forall x :  'k , m :  fmap 'k 'v.
    remove x m == remove_set (S.singleton x) m
meta "remove_unused:dependency" lemma remove_remove_set, function remove_set

lemma add_override :
  forall x:  'k , y: 'v, m :  fmap 'k 'v.
    add x y m == override m (mk (S.singleton x) (fun _ -> y))
meta "remove_unused:dependency" lemma add_override, function override

end

(** {2 Finite monomorphic maps to be used in programs only}

A program function `eq` deciding equality on the `key` type must be provided when cloned.
*)

(** {3 Applicative maps} *)

module MapApp

  use int.Int
  use map.Map
  use export Fmap

  type key

  (* we enforce type `key` to have a decidable equality
     by requiring the following function *)
  val eq (x y: key) : bool
    ensures { result <-> x = y }

  type t 'v = abstract {
    to_fmap: fmap key 'v;
  }
  meta coercion function to_fmap

  val create () : t 'v
    ensures { result.to_fmap = empty }

  val mem (k: key) (m: t 'v) : bool
    ensures { result <-> mem k m }

  val is_empty (m: t 'v) : bool
    ensures { result <-> is_empty m }

  val add (k: key) (v: 'v) (m: t 'v) : t 'v
    ensures { result = add k v m }

  val find (k: key) (m: t 'v) : 'v
    requires { mem k m }
    ensures  { result = m[k] }
    ensures  { result = find k m }

  use ocaml.Exceptions

  val find_exn (k: key) (m: t 'v) : 'v
    ensures { S.mem k m.domain }
    ensures { result = m[k] }
    raises  { Not_found ->  not (S.mem k m.domain) }

  val remove (k: key) (m: t 'v) : t 'v
    ensures { result = remove k m }

  val size (m: t 'v) : int
    ensures { result = size m }

end

(** {3 Applicative maps of integers} *)

module MapAppInt

  use int.Int

  clone export MapApp with type key = int, val eq = Int.(=)

end

(** {3 Imperative maps} *)

module MapImp

  use int.Int
  use map.Map
  use export Fmap

  type key

  val eq (x y: key) : bool
    ensures { result <-> x = y }

  type t 'v = abstract {
    mutable to_fmap: fmap key 'v;
  }
  meta coercion function to_fmap

  val create () : t 'v
    ensures { result.to_fmap = empty }

  val mem (k: key) (m: t 'v) : bool
    ensures { result <-> mem k m }

  val is_empty (m: t 'v) : bool
    ensures { result <-> is_empty m }

  val add (k: key) (v: 'v) (m: t 'v) : unit
    writes  { m }
    ensures { m = add k v (old m) }

  val find (k: key) (m: t 'v) : 'v
    requires { mem k m }
    ensures  { result = m[k] }
    ensures  { result = find k m }

  use ocaml.Exceptions

  val find_exn (k: key) (m: t 'v) : 'v
    ensures { S.mem k m.domain }
    ensures { result = m[k] }
    raises  { Not_found ->  not (S.mem k m.domain) }

  val remove (k: key) (m: t 'v) : unit
    writes  { m }
    ensures { m = remove k (old m) }

  val size (m: t 'v) : int
    ensures { result = size m }

  val clear (m: t 'v) : unit
    writes  { m }
    ensures { m = empty }

end

(** {3 Imperative maps of integers} *)

module MapImpInt

  use int.Int

  clone export MapImp with type key = int, val eq = Int.(=)

end