-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfmap.mlw
More file actions
459 lines (316 loc) · 11.9 KB
/
Copy pathfmap.mlw
File metadata and controls
459 lines (316 loc) · 11.9 KB
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
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
(** {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
meta "remove_unused:dependency" axiom add_contents_k, function add
axiom add_contents_other:
forall k v, m: fmap 'k 'v, k1. mem k1 m -> k1 <> k -> (add k v m)[k1] = m[k1]
meta "remove_unused:dependency" axiom add_contents_other, function add
axiom add_domain:
forall k v, m: fmap 'k 'v. (add k v m).domain = S.add k m.domain
meta "remove_unused:dependency" axiom add_domain, function add
(*** 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]
meta "remove_unused:dependency" axiom find_def, function find
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]
meta "remove_unused:dependency" axiom remove_contents, function remove
axiom remove_domain:
forall k, m: fmap 'k 'v. (remove k m).domain = S.remove k m.domain
meta "remove_unused:dependency" axiom remove_domain, function remove
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 indexed by integers and strings} *)
module MapAppInt
use int.Int
use set.Fset as S
clone export MapApp with type key = int, val eq = Int.(=)
val mapi (f: int -> 'v -> 'w) (m: t 'v) : t 'w
ensures {forall i. S.mem i m.domain -> result i = f i (m i)}
scope Iter (* iteration over maps *)
type iter 'v = abstract {
initial: fmap int 'v;
mutable visited: S.fset int;
} invariant {
S.subset visited initial.domain
} by {
initial = empty;
visited = S.empty;
}
val create (m: t 'v) : iter 'v
ensures { result.initial = m.to_fmap }
ensures { S.is_empty result.visited }
exception Done
val next (it: iter 'v) : (int, 'v)
writes { it }
raises { Done -> it.visited = (old it).visited = it.initial.domain}
returns { (r,v) -> S.mem r it.initial.domain /\ it.initial r = v /\
not (S.mem r (old it).visited) /\
it.visited = S.add r (old it).visited }
end
end
module MapAppInt63
use mach.int.Int63
clone export MapApp with type key = int63, val eq = Int63.(=)
val mapi (f: int63 -> 'v -> 'w) (m: t 'v) : t 'w
ensures {forall i. S.mem i m.domain -> result i = f i (m i)}
scope Iter (* iteration over maps *)
type iter 'v = abstract {
initial: fmap int63 'v;
mutable visited: S.fset int63;
} invariant {
S.subset visited initial.domain
} by {
initial = empty;
visited = S.empty;
}
val create (m: t 'v) : iter 'v
ensures { result.initial = m.to_fmap }
ensures { S.is_empty result.visited }
exception Done
val next (it: iter 'v) : (int63, 'v)
writes { it }
raises { Done -> it.visited = (old it).visited = it.initial.domain}
returns { (r,v) -> S.mem r it.initial.domain /\ it.initial r = v /\
not (S.mem r (old it).visited) /\
it.visited = S.add r (old it).visited }
end
end
module MapAppString
use set.Fset as S
use string.OCaml as Str
clone export MapApp with type key = string, val eq = Str.(=)
val mapi (f: string -> 'v -> 'w) (m: t 'v) : t 'w
ensures {forall i. S.mem i m.domain -> result i = f i (m i)}
scope Iter (* iteration over maps *)
type iter 'v = abstract {
initial: fmap string 'v;
mutable visited: S.fset string;
} invariant {
S.subset visited initial.domain
} by {
initial = empty;
visited = S.empty;
}
val create (m: t 'v) : iter 'v
ensures { result.initial = m.to_fmap }
ensures { S.is_empty result.visited }
exception Done
val next (it: iter 'v) : (string, 'v)
writes { it }
raises { Done -> it.visited = (old it).visited = it.initial.domain}
returns { (r,v) -> S.mem r it.initial.domain /\ it.initial r = v /\
not (S.mem r (old it).visited) /\
it.visited = S.add r (old it).visited }
end
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