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