1(*---------------------------------------------------------------------------*)
2(* The balanced_map theory constructs balanced binary trees as a model for   *)
3(* finite maps. Lookup of elements is done by use of a comparison function   *)
4(* returning elements in {Less, Equal, Greater}. As a consequence, if a node *)
5(* in the b-b-tree associates key k with value v, it is in actuality mapping *)
6(* v from any k' such that cmp k k' = Equal (cmp is the comparison fn). Thus *)
7(* the domain of such a map is made of *sets* of things equal to some key in *)
8(* the tree.                                                                 *)
9(*                                                                           *)
10(* The specifications of b-b-tree operations are phrased in terms of the     *)
11(* corresponding operations in finite_map theory. This seems to require a    *)
12(* map from ('a,'b) balanced_map to 'a|->'b. But that isn't possible by the  *)
13(* discussion above, and actually we have                                    *)
14(*                                                                           *)
15(*  to_fmap : ('a,'b) balanced_map -> (('a->bool) |-> 'b).                   *)
16(*                                                                           *)
17(* The major operations on b-b-trees are characterized in terms of to_fmap   *)
18(* in balanced_mapTheory. However, to support refinement scenarios, whereby  *)
19(* theorems phrased in terms of finite maps are converted to be over         *)
20(* b-b-trees, there is a need to translate from finite_map to b-b-trees.     *)
21(*                                                                           *)
22(* This translation is based on the requirement that                         *)
23(*                                                                           *)
24(*  (cmp x y = Equal) ==> (x = y)                                            *)
25(*                                                                           *)
26(* This is useful for settings where there is no derived equality at work,   *)
27(* for example regexp_compare.                                               *)
28(*---------------------------------------------------------------------------*)
29
30open HolKernel Parse boolLib bossLib BasicProvers;
31open optionTheory listTheory pred_setTheory comparisonTheory
32     balanced_mapTheory osetTheory finite_mapTheory regexpTheory;
33
34fun pat_elim q = Q.PAT_X_ASSUM q (K ALL_TAC);
35
36val simp_rule = SIMP_RULE;
37
38val comparison_distinct = TypeBase.distinct_of ``:ordering``
39val comparison_nchotomy = TypeBase.nchotomy_of ``:ordering``
40
41Triviality SET_EQ_THM :
42 !s1 s2. (s1 = s2) = !x. s1 x = s2 x
43Proof
44 METIS_TAC [EXTENSION,IN_DEF]
45QED
46
47Triviality INTER_DELETE :
48  !A a. A INTER (A DELETE a) = A DELETE a
49Proof
50  SET_TAC []
51QED
52
53Triviality LENGTH_NIL_SYM =
54   GEN_ALL (CONV_RULE (LHS_CONV SYM_CONV) (SPEC_ALL LENGTH_NIL));
55
56val list_ss = list_ss ++ rewrites [LENGTH_NIL, LENGTH_NIL_SYM];
57
58val set_ss = list_ss ++ pred_setLib.PRED_SET_ss ++ rewrites [SET_EQ_THM,IN_DEF]
59
60val _ = new_theory "regexp_map";
61
62Definition eq_cmp_def :
63   eq_cmp cmp <=> good_cmp cmp /\ !x y. (cmp x y = Equal) <=> (x=y)
64End
65
66Theorem eq_cmp_regexp_compare :
67  eq_cmp regexp_compare
68Proof
69  metis_tac [eq_cmp_def, regexp_compare_good,regexp_compare_eq]
70QED
71
72val [frange_def,fdom_def] =
73 TotalDefn.multiDefine
74   `(fdom cmp bmap   = {a | ?x. lookup cmp a bmap = SOME x}) /\
75    (frange cmp bmap = {x | ?a. lookup cmp a bmap = SOME x})`;
76
77Definition bmap_of_list_def :
78     bmap_of_list cmp (fmap:'a|->'b) list =
79        FOLDR (\k bmap. balanced_map$insert cmp k (fmap ' k) bmap)
80              Tip list
81End
82
83Definition fdom_bmap_def :
84    bmap_of cmp fmap = bmap_of_list cmp fmap (SET_TO_LIST (FDOM fmap))
85End
86;
87
88Theorem bmap_of_def[local] :
89 bmap_of cmp fmap =
90        FOLDR (\k bmap. balanced_map$insert cmp k (fmap ' k) bmap)
91              Tip
92              (SET_TO_LIST (FDOM fmap))
93Proof
94 metis_tac [bmap_of_list_def, fdom_bmap_def]
95QED
96
97Theorem invariant_insert_list[local] :
98 !(list:'a list) fmap cmp.
99   good_cmp cmp ==>
100   invariant cmp (FOLDR (\k bmap. balanced_map$insert cmp k (fmap ' k) bmap) Tip list)
101Proof
102 Induct >> rw [invariant_def] >> metis_tac [insert_thm]
103QED
104
105Theorem invariant_bmap_of :
106 !fmap cmp. good_cmp cmp ==> invariant cmp (bmap_of cmp fmap)
107Proof
108 rw [bmap_of_def,invariant_insert_list]
109QED
110
111Theorem eq_cmp_singleton_keyset :
112  !cmp k.
113     eq_cmp cmp ==> (key_set cmp k = {k})
114Proof
115 rw_tac set_ss [eq_cmp_def,key_set_def]
116QED
117
118Theorem eq_cmp_keyset :
119 !cmp k j. eq_cmp cmp ==> (key_set cmp k j <=> (k=j))
120Proof
121 rw_tac set_ss [eq_cmp_def,key_set_def] >> metis_tac[]
122QED
123
124Theorem eq_cmp_lookup_thm :
125 !bmap cmp.
126    invariant cmp bmap /\ eq_cmp cmp
127   ==>
128     !x. lookup cmp x bmap = FLOOKUP (to_fmap cmp bmap) {x}
129Proof
130 rw [] >> `good_cmp cmp` by metis_tac [eq_cmp_def]
131       >> rw [lookup_thm]
132       >> metis_tac [eq_cmp_singleton_keyset]
133QED
134
135Theorem lookup_insert_equal[local] :
136 !bmap a b y. good_cmp cmp /\ invariant cmp bmap /\ (cmp a b = Equal)
137             ==> (lookup cmp b (insert cmp a y bmap) = SOME y)
138Proof
139rw [insert_thm,lookup_thm,FLOOKUP_UPDATE]
140 >> fs [key_set_def,EXTENSION]
141 >> metis_tac [good_cmp_def,comparison_distinct]
142QED
143
144Theorem lookup_insert_notequal[local] :
145 !bmap a b y.
146     good_cmp cmp /\ invariant cmp bmap /\
147     ((cmp a b = Less) \/ (cmp a b = Greater))
148    ==> (lookup cmp b (insert cmp a y bmap) = lookup cmp b bmap)
149Proof
150rw [insert_thm,lookup_thm,FLOOKUP_UPDATE]
151 >> fs [key_set_def,EXTENSION]
152 >> metis_tac [good_cmp_def,comparison_distinct]
153QED
154
155Theorem lookup_insert_thm :
156 !bmap a b y.
157     good_cmp cmp /\ invariant cmp bmap
158    ==>
159     (lookup cmp b (insert cmp a y bmap) =
160        if cmp a b = Equal
161          then SOME y
162          else lookup cmp b bmap)
163Proof
164 metis_tac [lookup_insert_equal,lookup_insert_notequal,comparison_nchotomy]
165QED
166
167Theorem lookup_bmap_of_list[local] :
168 !list fmap x.
169   eq_cmp cmp /\ MEM x list
170   ==>
171    (lookup cmp x (bmap_of_list cmp fmap list) = SOME (fmap ' x))
172Proof
173Induct >> rw [bmap_of_list_def] >> `good_cmp cmp` by metis_tac [eq_cmp_def]
174 >- metis_tac [invariant_insert_list,good_cmp_thm,lookup_insert_equal]
175 >- (rw [Once lookup_insert_thm,invariant_insert_list,GSYM bmap_of_list_def]
176     >> metis_tac [eq_cmp_def])
177QED
178
179Theorem lookup_bmap_of_list_notin[local] :
180 !list fmap x.
181   eq_cmp cmp /\ ~MEM x list
182   ==>
183    (lookup cmp x (bmap_of_list cmp fmap list) = NONE)
184Proof
185Induct >> rw [bmap_of_list_def] >> `good_cmp cmp` by metis_tac [eq_cmp_def]
186 >- rw [lookup_def]
187 >- (rw [Once lookup_insert_thm,invariant_insert_list,GSYM bmap_of_list_def]
188     >> metis_tac [eq_cmp_def])
189QED
190
191Theorem lookup_bmap_of :
192 !list fmap x.
193   eq_cmp cmp
194   ==>
195    (lookup cmp x (bmap_of cmp fmap) =
196       if x IN FDOM fmap
197          then SOME (fmap ' x)
198          else NONE)
199Proof
200 metis_tac [fdom_bmap_def,lookup_bmap_of_list,
201            lookup_bmap_of_list_notin, MEM_SET_TO_LIST,FDOM_FINITE]
202QED
203
204Theorem FLOOKUP_lookup :
205 !fmap.
206    eq_cmp cmp ==> !x. FLOOKUP fmap x = lookup cmp x (bmap_of cmp fmap)
207Proof
208 metis_tac [FLOOKUP_DEF,lookup_bmap_of]
209QED
210
211Theorem inj_lem[local] :
212  !fmap x.
213    INJ (\x.{x}) (x INSERT FDOM fmap) (UNIV:('a->bool)->bool)
214Proof
215 rw[INJ_DEF]
216QED
217
218Theorem map_keys_fupdate =
219  MATCH_MP (SPEC_ALL MAP_KEYS_FUPDATE) (SPEC_ALL inj_lem);
220
221Theorem fdom_map_keys[local] :
222 !fmap. FDOM(MAP_KEYS (\x. {x}) fmap) = IMAGE (\x. {x}) (FDOM fmap)
223Proof
224 Induct >> rw[map_keys_fupdate]
225QED
226
227Theorem FLOOKUP_MAP_KEYS[local] :
228 !fmap x. FLOOKUP (MAP_KEYS (\x. {x}) fmap) {x} = FLOOKUP fmap x
229Proof
230 Induct >> rw [map_keys_fupdate,FLOOKUP_UPDATE]
231QED
232
233Theorem to_fmap_empty[local] :
234 !(bmap:('a,'b)balanced_map) (cmp:'a->'a->ordering).
235     good_cmp cmp ==> (FLOOKUP (to_fmap cmp bmap) {} = NONE)
236Proof
237Induct
238   >> rw [to_fmap_def,FLOOKUP_UPDATE,FLOOKUP_FUNION,key_set_def,EXTENSION]
239   >> metis_tac [good_cmp_thm]
240QED
241
242Theorem to_fmap_two[local] :
243 !(bmap:('a,'b)balanced_map) (cmp:'a->'a->ordering) a b s.
244     eq_cmp cmp /\ a IN s /\ b IN s /\ ~(a=b) ==>
245      (FLOOKUP (to_fmap cmp bmap) s = NONE)
246Proof
247Induct >> rw [to_fmap_def,FLOOKUP_UPDATE,FLOOKUP_FUNION,key_set_def,EXTENSION,
248              eq_cmp_def,GSYM IMP_DISJ_THM]
249       >- metis_tac []
250       >- (BasicProvers.CASE_TAC >> metis_tac[eq_cmp_def,NOT_SOME_NONE])
251QED
252
253Theorem flookup_map_keys_empty[local] :
254 !fmap. FLOOKUP (MAP_KEYS (\x. {x}) fmap) {} = NONE
255Proof
256  Induct >> rw [MAP_KEYS_FEMPTY,map_keys_fupdate,FLOOKUP_UPDATE,FLOOKUP_FUNION]
257QED
258
259Theorem flookup_map_keys_two[local] :
260 !fmap a b s.
261     ~(a=b) /\ a IN s /\ b IN s
262       ==>
263      (FLOOKUP (MAP_KEYS (\x. {x}) fmap) s = NONE)
264Proof
265Induct
266  >> rw [MAP_KEYS_FEMPTY,map_keys_fupdate,FLOOKUP_UPDATE]
267  >> `FLOOKUP (MAP_KEYS (\x. {x}) fmap) s = NONE` by metis_tac[]
268  >> rw[]
269  >> metis_tac [IN_SING]
270QED
271
272Theorem fdom_insert :
273  !bmap cmp k v.
274      eq_cmp cmp /\
275      invariant cmp bmap
276     ==>
277     (fdom cmp (insert cmp k v bmap) = $INSERT k (fdom cmp bmap))
278Proof
279 rw_tac set_ss [fdom_def]
280  >> `good_cmp cmp` by metis_tac [eq_cmp_def]
281  >> rw_tac set_ss [Once lookup_insert_thm]
282  >> metis_tac [eq_cmp_def]
283QED
284
285Theorem FDOM_fdom :
286 !fmap.
287     eq_cmp cmp ==> (FDOM fmap = fdom cmp (bmap_of cmp fmap))
288Proof
289  rw [fdom_def,lookup_bmap_of]
290QED
291
292Theorem FRANGE_frange :
293  !fmap cmp.
294      eq_cmp cmp ==> (FRANGE fmap = frange cmp (bmap_of cmp fmap))
295Proof
296 rw [frange_def,lookup_bmap_of,FRANGE_DEF]
297QED
298
299
300(*---------------------------------------------------------------------------*)
301(* Definitions and lemmas about balanced_map things                          *)
302(*---------------------------------------------------------------------------*)
303
304Definition fmap_inj_def :
305  fmap_inj cmp bmap =
306     !x y. x IN fdom cmp bmap /\
307           (lookup cmp x bmap = lookup cmp y bmap)
308            ==> (cmp x y = Equal)
309End
310
311
312Definition fapply_def :
313  fapply cmp bmap x = THE (lookup cmp x bmap)
314End
315
316Definition submap_def :
317  submap cmp t1 t2 =
318     !x. x IN fdom cmp t1
319          ==> x IN fdom cmp t2 /\
320             (lookup cmp x t1 = lookup cmp x t2)
321End
322
323Theorem member_iff_lookup :
324 !fmap cmp x.
325     member cmp x fmap <=> ?y. lookup cmp x fmap = SOME y
326Proof
327  Induct
328   >> rw_tac set_ss [member_def, lookup_def]
329   >> BasicProvers.EVERY_CASE_TAC
330QED
331
332Theorem lookup_bin :
333  !fmap fmap' n k v x.
334      (lookup cmp r (Bin n k v fmap fmap') = SOME x)
335      <=>
336      ((cmp r k = Equal) /\ (v = x)) \/
337      ((cmp r k = Less) /\ (lookup cmp r fmap = SOME x)) \/
338      ((cmp r k = Greater) /\ (lookup cmp r fmap' = SOME x))
339Proof
340 RW_TAC list_ss [lookup_def] THEN BasicProvers.CASE_TAC
341QED
342
343Theorem key_less_lookup :
344 !fmap cmp k1 k2 x.
345     invariant cmp fmap /\ good_cmp cmp /\
346     key_ordered cmp k1 fmap Less /\
347     (lookup cmp k2 fmap = SOME x)
348     ==>
349     (cmp k1 k2 = Less)
350Proof
351 Induct
352  >> rw_tac list_ss [key_ordered_def, lookup_def, invariant_def]
353  >> every_case_tac
354  >- metis_tac []
355  >- metis_tac [good_cmp_def,comparison_distinct]
356  >- metis_tac []
357QED
358
359Theorem key_greater_lookup :
360 !fmap cmp k1 k2 x.
361     invariant cmp fmap /\ good_cmp cmp /\
362     key_ordered cmp k1 fmap Greater /\
363     (lookup cmp k2 fmap = SOME x)
364     ==>
365     (cmp k2 k1 = Less)
366Proof
367 Induct
368  >> rw_tac list_ss [key_ordered_def, lookup_def, invariant_def]
369  >> every_case_tac
370  >- metis_tac []
371  >- metis_tac [good_cmp_def,comparison_distinct]
372  >- metis_tac []
373QED
374
375(*---------------------------------------------------------------------------*)
376(* submap lemmas                                                             *)
377(*---------------------------------------------------------------------------*)
378
379Theorem submap_id :
380  !t cmp. submap cmp t t
381Proof
382   rw [submap_def]
383QED
384
385Theorem submap_trans :
386 !t1 t2 t3 cmp.
387     submap cmp t1 t2 /\ submap cmp t2 t3 ==> submap cmp t1 t3
388Proof
389  rw [submap_def]
390QED
391
392Theorem submap_mono :
393 !t1 t2 k v cmp.
394    eq_cmp cmp /\ invariant cmp t2 /\ submap cmp t1 t2
395    /\ k NOTIN fdom cmp t1
396   ==>
397   submap cmp t1 (insert cmp k v t2)
398Proof
399  rw [submap_def,fdom_insert]
400  >> res_tac
401  >> `good_cmp cmp` by metis_tac [eq_cmp_def]
402  >> rw [lookup_insert_thm]
403  >> `k=x` by metis_tac [eq_cmp_def]
404  >> rw []
405  >> metis_tac[]
406QED
407
408Theorem submap_insert :
409 !bmap t cmp x v.
410    eq_cmp cmp /\ invariant cmp bmap /\
411    x NOTIN fdom cmp bmap /\
412    submap cmp (insert cmp x v bmap) t
413    ==> submap cmp bmap t
414Proof
415 rw_tac set_ss [submap_def]
416  >> `invariant cmp (insert cmp x v bmap)` by metis_tac [insert_thm,eq_cmp_def]
417  >- (qpat_x_assum `$! M` (mp_tac o Q.ID_SPEC) >> rw_tac set_ss [fdom_insert])
418  >- (`~(x' = x)` by (fs [fdom_def] >> metis_tac[])
419       >> `fdom cmp (insert cmp x v bmap) x'` by rw [fdom_insert,IN_DEF]
420       >> `good_cmp cmp` by metis_tac [eq_cmp_def]
421       >> `lookup cmp x' (insert cmp x v bmap) = lookup cmp x' t` by metis_tac[]
422       >> pop_assum (SUBST_ALL_TAC o SYM)
423       >> pat_elim `$!M`
424       >> rw_tac set_ss [lookup_insert_thm]
425       >> metis_tac [eq_cmp_def])
426QED
427
428Theorem fdom_ounion :
429 !a b.
430   good_cmp cmp /\ invariant cmp a /\ invariant cmp b
431   ==>
432   (fdom cmp (ounion cmp a b) = (fdom cmp a) UNION (fdom cmp b))
433Proof
434 rw[fdom_def,ounion_def,SET_EQ_THM]
435  >> metis_tac [regexp_compare_good,good_oset_def,
436       SIMP_RULE std_ss [oin_def,ounion_def,
437                         member_iff_lookup,oneTheory.one] oin_ounion]
438QED
439
440Theorem SING_IN_FDOM :
441 !x bstmap cmp.
442   eq_cmp cmp /\ invariant cmp bstmap
443    ==>
444   (x IN fdom cmp bstmap <=> {x} IN FDOM (to_fmap cmp bstmap))
445Proof
446 rw[fdom_def]
447  >> drule_then assume_tac eq_cmp_singleton_keyset
448  >> Induct_on `bstmap`
449  >- rw [to_fmap_def,lookup_def]
450  >- (rw [to_fmap_def,lookup_def,invariant_def]
451       >> CASE_TAC
452       >> rw[EQ_IMP_THM]
453       >> fs[]
454       >> metis_tac [eq_cmp_def, good_cmp_def,key_less_lookup,key_greater_lookup,
455                     ternaryComparisonsTheory.ordering_distinct])
456QED
457
458Theorem deleteFindMin_thm :
459 !t t' k v.
460   invariant regexp_compare t /\ ~null t /\
461   deleteFindMin t = ((k,v),t')
462   ==> invariant regexp_compare t' /\
463       (fdom regexp_compare t = {k} UNION fdom regexp_compare t')
464Proof
465 rw[]
466  >> `good_cmp regexp_compare /\ eq_cmp regexp_compare`
467       by metis_tac [eq_cmp_regexp_compare,eq_cmp_def]
468  >> `invariant regexp_compare t'` by metis_tac [deleteFindMin]
469  >> `FDOM (to_fmap regexp_compare t') =
470      FDOM(DRESTRICT (to_fmap regexp_compare t)
471            (FDOM (to_fmap regexp_compare t) DELETE key_set regexp_compare k))`
472     by metis_tac [deleteFindMin]
473  >> fs [FDOM_DRESTRICT,INTER_DELETE]
474  >> rfs[eq_cmp_singleton_keyset]
475  >> `k IN fdom regexp_compare t`
476          by (rw [fdom_def,eq_cmp_lookup_thm]
477               >> metis_tac[deleteFindMin,eq_cmp_singleton_keyset])
478  >> rw [EXTENSION,SING_IN_FDOM]
479  >> metis_tac[SING_IN_FDOM]
480QED
481
482Theorem invariant_oset :
483 !l. good_cmp cmp ==> invariant cmp (oset cmp l)
484Proof
485 simp_tac std_ss [oset_def]
486   >> Induct
487   >> fs [oempty_def,empty_def,oinsert_def]
488   >- metis_tac [invariant_def]
489   >- metis_tac [insert_thm]
490QED
491
492Theorem in_dom_oset :
493 !l x.
494   eq_cmp cmp ==> (x IN fdom cmp (oset cmp l) <=> MEM x l)
495Proof
496 Induct >> rw []
497  >- rw [oempty_def,empty_def,fdom_def,lookup_def]
498  >- (`good_cmp cmp` by metis_tac [eq_cmp_def]
499       >> imp_res_tac invariant_oset >> pop_assum (assume_tac o Q.SPEC `l`)
500       >> rw [oset_def]
501       >> rw [GSYM oset_def]
502       >> rw [oinsert_def]
503       >> rw_tac set_ss [fdom_insert])
504QED
505
506Theorem dom_oset_lem :
507 !l.
508    eq_cmp cmp ==> (fdom cmp (oset cmp l) = LIST_TO_SET l)
509Proof
510 rw [EXTENSION,in_dom_oset,eq_cmp_regexp_compare]
511QED
512
513Theorem member_insert :
514 !bmap x y v.
515    eq_cmp cmp /\ invariant cmp bmap ==>
516    (member cmp x (insert cmp y v bmap) <=> (x=y) \/ member cmp x bmap)
517Proof
518 rw [member_iff_lookup,GSYM (SIMP_RULE set_ss [SET_EQ_THM] fdom_def)] >>
519 rw [fdom_insert] >> metis_tac [IN_DEF]
520QED
521
522Theorem mem_foldrWithKey :
523 !(bset:'a oset) acc a. eq_cmp cmp /\ invariant cmp bset ==>
524     (MEM (a,()) (foldrWithKey (\k x xs. (k,())::xs) acc bset)
525            <=>
526      (a IN fdom cmp bset) \/ MEM (a,()) acc)
527Proof
528 simp_tac set_ss [fdom_def]
529 >> Induct >> rw [foldrWithKey_def,invariant_def] >> fs []
530 >- rw [lookup_def]
531 >- (`good_cmp cmp` by metis_tac [eq_cmp_def]
532      >> rw [lookup_bin,EQ_IMP_THM]
533      >> metis_tac [key_greater_lookup,key_less_lookup,good_cmp_thm,eq_cmp_def])
534QED
535
536Theorem mem_foldrWithKey_lem =
537    mem_foldrWithKey
538      |> Q.SPEC `bset`
539      |> Q.SPEC `[]`
540      |> SIMP_RULE list_ss [];
541
542Theorem invariant_ffoldr :
543 !list aset f.
544    good_cmp cmp /\ invariant cmp aset
545    ==>
546    invariant cmp (FOLDR (\(k,v) t. insert cmp (f k) v t) aset list)
547Proof
548  Induct >> rw [invariant_def]
549         >> Cases_on `h` >> rw [] >> metis_tac [insert_thm]
550QED
551
552Theorem left_to_right_alt :
553 eq_cmp (cmp:'b->'b->ordering)
554   ==>
555   !(list :('a # unit) list) (bset :'b oset) x f.
556      invariant cmp bset /\
557      (lookup cmp x (FOLDR (\(k,v:unit) t. insert cmp (f k) () t) bset list) = SOME ())
558            ==>
559           (?a. MEM (a,()) list /\ (x = f a))
560           \/
561           ((!a. MEM (a,()) list ==> (x <> f a)) /\ (lookup cmp x bset = SOME ()))
562Proof
563 strip_tac
564  >> `good_cmp cmp` by metis_tac [eq_cmp_def]
565  >> Induct
566     >- rw []
567     >- (Cases_on `h` >> rw [] >> fs []
568          >> pop_assum mp_tac
569          >> `invariant cmp (FOLDR (\(k,v:unit) t. insert cmp (f k) () t) bset list)`
570               by (Q.SPEC_TAC (`list`,`L`)
571                     >> Induct >> rw [invariant_def]
572                     >> Cases_on `h` >> rw [] >> metis_tac [insert_thm])
573          >> rw [lookup_insert_thm]
574          >> metis_tac [eq_cmp_def])
575QED
576
577Theorem left_to_right_lem =
578    left_to_right_alt
579      |> Q.GEN `cmp`
580      |> Q.SPEC `cmp2`
581      |> UNDISCH
582      |> Q.SPEC `foldrWithKey (\(k:'a) (x:unit) xs. (k,())::xs) [] aset`
583      |> Q.SPEC `Tip`
584      |> Q.SPEC `x`
585      |> Q.SPEC `f`
586      |> DISCH_ALL;
587
588Theorem oin_fdom :
589 !aset x.
590   oin cmp x aset <=> x IN fdom cmp aset
591Proof
592 rw [fdom_def, oin_def, member_iff_lookup]
593QED
594
595Theorem mem_oin :
596 !list x aset.
597     eq_cmp cmp /\ invariant cmp aset /\
598     MEM (x,()) list
599      ==>
600     oin cmp (f x) (FOLDR (\(k,u) s. insert cmp (f k) () s) aset list)
601Proof
602 Induct >> rw [oin_fdom]
603  >> `good_cmp cmp` by metis_tac [eq_cmp_def]
604  >> mp_tac (SPEC_ALL (invariant_ffoldr |> INST_TYPE [beta |-> ``:unit``, gamma |-> beta]))
605  >| [all_tac, Cases_on `h`]
606  >> rw[fdom_insert]
607  >> metis_tac [oin_fdom,IN_DEF]
608QED
609
610Theorem mem_oin_inst =
611   mem_oin
612   |> SPEC_ALL
613   |> Q.INST [`cmp` |-> `cmp2`, `aset` |-> `Tip`, `x` |-> `x'`]
614   |> Q.GEN `list`;
615
616
617Theorem fdom_oimage :
618 !aset:'a oset.
619     eq_cmp (cmp1:'a->'a->ordering) /\
620     eq_cmp (cmp2:'b->'b->ordering) /\ invariant cmp1 aset
621    ==> (fdom cmp2 (oimage cmp2 f aset) = {f x | oin cmp1 x aset})
622Proof
623 simp_tac set_ss
624   [oimage_def,map_keys_def,balanced_mapTheory.fromList_def,fdom_def,
625    toAscList_def,empty_def,
626    rich_listTheory.FOLDR_MAP,pairTheory.LAMBDA_PROD,oneTheory.one]
627 >> rw [EQ_IMP_THM]
628    >- (mp_tac left_to_right_lem >> rw[invariant_def]
629        >- (qexists_tac `a` >> rw[]
630             >> pat_elim `lookup _ __ ___ = SOME ()`
631             >> pat_elim `eq_cmp cmp2`
632             >> `a IN fdom cmp1 aset` by metis_tac [mem_foldrWithKey_lem]
633             >> pop_assum mp_tac
634             >> rw[oin_def,member_iff_lookup,fdom_def])
635        >- fs [lookup_def])
636    >- (`MEM (x',()) (foldrWithKey (\k x xs. (k,())::xs) [] aset)`
637          by metis_tac [oin_fdom,IN_DEF, mem_foldrWithKey_lem]
638         >> mp_tac mem_oin_inst >> rw [invariant_def]
639         >> res_tac
640         >> fs [oin_def,member_iff_lookup,oneTheory.one])
641QED
642
643Theorem fdom_oimage_insert :
644 !bset a f cmp1 cmp2.
645    eq_cmp (cmp1:'a->'a->ordering) /\
646     eq_cmp (cmp2:'b->'b->ordering) /\ invariant cmp1 bset
647         ==> (fdom cmp2 (oimage cmp2 f (oinsert cmp1 a bset))
648               =
649              ((f a) INSERT fdom cmp2 (oimage cmp2 f bset)))
650Proof
651rpt strip_tac
652 >> `invariant cmp1 (oinsert cmp1 a bset)`
653       by metis_tac [insert_thm, eq_cmp_def,oinsert_def]
654 >> mp_tac (fdom_oimage |> simp_rule set_ss [GSPECIFICATION_applied])
655 >> asm_simp_tac bool_ss[]
656 >> rw_tac set_ss []
657 >> `good_cmp cmp1 /\ good_cmp cmp2` by metis_tac [eq_cmp_def]
658 >> rw [oin_def, member_iff_lookup, oinsert_def]
659 >> fs [eq_cmp_def,lookup_insert_thm]
660 >> metis_tac[]
661QED
662
663Theorem fdom_oimage_inst =
664   fdom_oimage
665   |> INST_TYPE [alpha |-> ``:regexp``, beta |-> ``:num``]
666   |> Q.INST [`cmp1` |-> `regexp_compare`, `cmp2` |-> `num_cmp`]
667   |> SIMP_RULE std_ss [eq_cmp_regexp_compare,num_cmp_good,num_cmp_antisym,eq_cmp_def];
668
669
670Theorem invariant_foldl :
671  !list work f.
672     invariant regexp_compare work
673     ==>
674      invariant regexp_compare
675        (FOLDL (\B a. insert regexp_compare (f a) y B) work list)
676Proof
677 Induct
678  >> rw[]
679  >> `invariant regexp_compare (insert regexp_compare (f h) y work)`
680          by metis_tac [insert_thm, regexp_compare_good]
681  >> rw []
682QED
683
684Theorem oin_foldl_insert :
685  !list bmap r f.
686     invariant regexp_compare bmap
687     ==>
688    (oin regexp_compare r
689         (FOLDL (\B a. insert regexp_compare (f a) () B) bmap list)
690     <=>
691     oin regexp_compare r bmap \/ MEM r (MAP f list))
692Proof
693 simp_tac std_ss [oin_def]
694  >> Induct
695  >> simp_tac list_ss []
696  >> rpt gen_tac >> strip_tac
697  >> `invariant regexp_compare (insert regexp_compare (f h) () bmap)`
698        by metis_tac [regexp_compare_good,insert_thm]
699  >> first_x_assum drule
700  >> rw_tac list_ss [eq_cmp_regexp_compare,member_insert]
701  >> metis_tac[]
702QED
703
704val _ = export_theory();
705