1(*===================================================================== *) 2(* FILE : permLib.sml *) 3(* DESCRIPTION : some code to handle permutations *) 4(* *) 5(* AUTHORS : Thomas Tuerk *) 6(* DATE : March 2009 *) 7(* ===================================================================== *) 8 9 10structure permLib :> permLib = 11struct 12 13(* 14quietdec := true; 15loadPath := 16 (concat [Globals.HOLDIR, "/src/sort"]):: 17 !loadPath; 18 19map load ["sortingTheory"]; 20quietdec := true; 21*) 22 23 24open HolKernel Parse boolLib Drule sortingTheory listTheory 25 26(* 27quietdec := false; 28*) 29 30 31 32val LIST_NIL_CONV = 33 QCONV (REWRITE_CONV [CONJUNCT1 APPEND, APPEND_NIL]) 34 35 36val PERM_tm = ``PERM : 'a list -> 'a list -> bool``; 37val dest_PERM = dest_binop PERM_tm (mk_HOL_ERR "permLib" "dest_PERM" "") 38val is_PERM = can dest_PERM; 39 40 41(* 42val t = ``PERM (x1::l1 ++ (l2 ++ (x2::x3::l3) ++ x4::l4)) (x1::l1 ++ ((x2::x3::l3) ++ x4::l4 ++ l2))`` 43val t1 = ``x1::x2::x3::(l1 ++ (x2::x3::l3 ++ x4::l4 ++ l2 ++ l4))`` 44val t2 = ``x1::x2::x8::(x4::l4 ++ l2++l4)`` 45*) 46 47 48local 49 fun strip_perm_list_acc xs ls t = 50 if (listSyntax.is_cons t) then 51 let val (x,l) = listSyntax.dest_cons t; in 52 strip_perm_list_acc (x::xs) ls l 53 end 54 else if (listSyntax.is_append t) then 55 let 56 val (t1,t2) = listSyntax.dest_append t; 57 val (xs', ls') = strip_perm_list_acc xs ls t1; 58 in 59 strip_perm_list_acc xs' ls' t2 60 end 61 else 62 if (listSyntax.is_nil t) then (xs,ls) else (xs, t::ls) 63in 64 fun strip_perm_list t = 65 let 66 val (xs,ls) = strip_perm_list_acc [] [] t 67 in 68 (Listsort.sort Term.compare xs, Listsort.sort Term.compare ls) 69 end; 70end; 71 72 73fun bag_inter cmp [] _ = [] 74 | bag_inter cmp _ [] = [] 75 | bag_inter cmp (x::xs) (y::ys) = 76 case cmp (x, y) of 77 LESS => bag_inter cmp xs (y::ys) 78 | GREATER => bag_inter cmp (x::xs) ys 79 | EQUAL => x::(bag_inter cmp xs ys); 80 81 82fun perm_list_inter t1 t2 = 83 let 84 val (xs1,ls1) = strip_perm_list t1 85 val (xs2,ls2) = strip_perm_list t2 86 in 87 (bag_inter Term.compare xs1 xs2, 88 bag_inter Term.compare ls1 ls2) 89 end; 90 91fun perm_sub_list t1 t2 = 92 let 93 val (xs1,ls1) = strip_perm_list t1 94 val (xs2,ls2) = strip_perm_list t2 95 96 val xs = bag_inter Term.compare xs1 xs2; 97 val ls = bag_inter Term.compare ls1 ls2; 98 99 val t1_sub = (length xs = length xs1) andalso (length ls = length ls1); 100 val t2_sub = (length xs = length xs2) andalso (length ls = length ls2); 101 in 102 (t1_sub, t2_sub, (xs, ls)) 103 end; 104 105 106 107(*dummy for testing 108 109fun PERM_MOVE_CONS_TO_FRONT e t = SOME ( 110let val t' = rand t in 111mk_thm ([], ``PERM ^t' = PERM (^e::^t')``) end); 112*) 113 114 115fun PERM_MOVE_CONS_TO_FRONT e t = 116if (listSyntax.is_cons (rand t)) then 117 let 118 val (x, l) = listSyntax.dest_cons (rand t); 119 in 120 if (aconv x e) then SOME (REFL t) else 121 let 122 val l_term = mk_icomb (PERM_tm, l) 123 val l_thm_opt = PERM_MOVE_CONS_TO_FRONT e l_term; 124 in 125 if not (isSome l_thm_opt) then NONE else 126 let 127 val l2 = (rand o rand o rhs o concl o valOf) l_thm_opt 128 in 129 SOME (MP (ISPECL [x,l,e,l2] PERM_FUN_CONS_11_SWAP_AT_FRONT) 130 (valOf l_thm_opt)) 131 end 132 end 133 end 134else if (listSyntax.is_append (rand t)) then 135 let 136 val (l1,l2) = listSyntax.dest_append (rand t) 137 val l1_thm_opt = PERM_MOVE_CONS_TO_FRONT e (mk_icomb (PERM_tm, l1)) 138 val l2_thm_opt = if isSome l1_thm_opt then NONE else 139 PERM_MOVE_CONS_TO_FRONT e (mk_icomb (PERM_tm, l2)) 140 in 141 if (isSome l1_thm_opt) then 142 let 143 val l1' = (rand o rand o rhs o concl o valOf) l1_thm_opt 144 in 145 SOME (MP (ISPECL [l2,l1,e,l1'] PERM_FUN_CONS_APPEND_1) 146 (valOf l1_thm_opt)) 147 end 148 else if (isSome l2_thm_opt) then 149 let 150 val l2' = (rand o rand o rhs o concl o valOf) l2_thm_opt 151 in 152 SOME (MP (ISPECL [l1,l2,e,l2'] PERM_FUN_CONS_APPEND_2) 153 (valOf l2_thm_opt)) 154 end 155 else NONE 156 end 157else NONE; 158 159 160(* 161 val t = ``PERM (x1::x2::x3::[])``; 162 val xs = free_vars t; 163 PERM_MOVE_CONS_TO_FRONT_CONV xs t 164*) 165fun PERM_MOVE_CONS_TO_FRONT_CONV [] t = REFL t 166 | PERM_MOVE_CONS_TO_FRONT_CONV (x::xs) t = 167 let 168 val thm0_opt = PERM_MOVE_CONS_TO_FRONT x t; 169 val _ = if isSome thm0_opt then () else raise UNCHANGED; 170 val thm0 = valOf thm0_opt; 171 172 val l1 = (rand o rand o rhs o concl) thm0; 173 val thm1 = PERM_MOVE_CONS_TO_FRONT_CONV xs (mk_icomb (PERM_tm, l1)); 174 val l2 = (rand o rhs o concl) thm1; 175 176 val thm2 = ISPECL [x, l1, l2] PERM_FUN_CONS_IFF 177 val thm3 = MP thm2 thm1 178 in 179 TRANS thm0 thm3 180 end; 181 182 183 184 185(*dummy for testing 186 187fun PERM_MOVE_APPEND_TO_FRONT l t = SOME ( 188let val t' = rand t in 189mk_thm ([], ``PERM ^t' = PERM (^l ++ ^t')``) end); 190*) 191 192 193fun PERM_MOVE_APPEND_TO_FRONT l t = 194if (listSyntax.is_nil l) then 195 let 196 val ty = listSyntax.dest_list_type (type_of l) 197 val tm = inst [alpha |-> ty] PERM_tm; 198 in 199 SOME (AP_TERM tm (GSYM (ISPEC (rand t) (CONJUNCT1 APPEND)))) 200 end 201else if (listSyntax.is_cons (rand t)) then 202 let 203 val (x, l') = listSyntax.dest_cons (rand t); 204 in 205 let 206 val l'_term = mk_icomb (PERM_tm, l') 207 val l'_thm_opt = PERM_MOVE_APPEND_TO_FRONT l l'_term; 208 in 209 if not (isSome l'_thm_opt) then NONE else 210 let 211 val l2 = (rand o rand o rhs o concl o valOf) l'_thm_opt 212 in 213 SOME (MP (ISPECL [x,l',l,l2] PERM_FUN_CONS_11_APPEND) 214 (valOf l'_thm_opt)) 215 end 216 end 217 end 218else if (listSyntax.is_append (rand t)) then 219 let 220 val (l1,l2) = listSyntax.dest_append (rand t); 221 in 222 if (aconv l1 l) then SOME (REFL t) else 223 if (aconv l2 l) then 224 SOME (REWR_CONV PERM_FUN_APPEND t) 225 else 226 let 227 val l1_thm_opt = PERM_MOVE_APPEND_TO_FRONT l (mk_icomb (PERM_tm, l1)) 228 val l2_thm_opt = if isSome l1_thm_opt then NONE else 229 PERM_MOVE_APPEND_TO_FRONT l (mk_icomb (PERM_tm, l2)) 230 in 231 if (isSome l1_thm_opt) then 232 let 233 val l1' = (rand o rand o rhs o concl o valOf) l1_thm_opt 234 in 235 SOME (MP (ISPECL [l1,l,l1',l2] PERM_FUN_APPEND_APPEND_1) 236 (valOf l1_thm_opt)) 237 end 238 else if (isSome l2_thm_opt) then 239 let 240 val l2' = (rand o rand o rhs o concl o valOf) l2_thm_opt 241 in 242 SOME (MP (ISPECL [l2,l,l2',l1] PERM_FUN_APPEND_APPEND_2) 243 (valOf l2_thm_opt)) 244 end 245 else NONE 246 end 247 end 248else if (aconv l (rand t)) then 249 let 250 val ty = listSyntax.dest_list_type (type_of l) 251 val tm = inst [alpha |-> ty] PERM_tm; 252 in 253 SOME (AP_TERM tm (GSYM (ISPEC l APPEND_NIL))) 254 end 255else NONE; 256 257 258 259(* 260 val t = ``PERM (x1++x2++x3)``; 261 val ls = free_vars t; 262 PERM_MOVE_APPEND_TO_FRONT_CONV ls t 263 264 val (l::ls) = ls 265 val t = (mk_icomb (PERM_tm, l1)) 266*) 267 268fun PERM_MOVE_APPEND_TO_FRONT_CONV [] t = REFL t 269 | PERM_MOVE_APPEND_TO_FRONT_CONV (l::ls) t = 270 let 271 val thm0_opt = PERM_MOVE_APPEND_TO_FRONT l t; 272 val _ = if isSome thm0_opt then () else raise UNCHANGED; 273 val thm0 = valOf thm0_opt; 274 275 val l1 = (rand o rand o rhs o concl) thm0; 276 val thm1 = PERM_MOVE_APPEND_TO_FRONT_CONV ls (mk_icomb (PERM_tm, l1)); 277 val l2 = (rand o rhs o concl) thm1; 278 279 val thm2 = ISPECL [l, l1, l2] PERM_FUN_APPEND_IFF 280 val thm3 = MP thm2 thm1 281 in 282 TRANS thm0 thm3 283 end; 284 285 286 287(* 288val l = hd ls 289val l = ``x::(l3 ++ z3::l2 ++ x::z::x1::y::l1 ++ x3::x5::l0)``; 290val xs = [``x:'a``, ``x1:'a``, ``y:'a``, ``x:'a``]; 291val ls = [``l2:'a list``, ``l0:'a list``, ``l3:'a list``]; 292 293val (xs,ls) = strip_perm_list l 294*) 295 296fun PERM_SPLIT_el_lists l (xs,ls) = 297let 298 val t = mk_icomb (PERM_tm, l); 299 300 val thm0 = (QCHANGED_CONV (PERM_MOVE_APPEND_TO_FRONT_CONV ls) THENC 301 RAND_CONV (REWR_CONV (GSYM (CONJUNCT1 APPEND))) THENC 302 QCHANGED_CONV (PERM_MOVE_CONS_TO_FRONT_CONV xs)) t; 303 val thm1 = CONV_RULE (RHS_CONV (REWRITE_CONV [GSYM (CONJUNCT2 APPEND)])) thm0 304 305 val thm2 = CONV_RULE (RHS_CONV (RAND_CONV ( 306 quantHeuristicsLibBase.BOUNDED_REPEATC (length ls) (REWR_CONV APPEND_ASSOC)))) thm1; 307 308 val thm3 = CONV_RULE (RAND_CONV (RAND_CONV (RAND_CONV LIST_NIL_CONV))) thm2 309in 310 CONV_RULE (REWR_CONV (GSYM PERM_EQUIVALENCE_ALT_DEF)) thm3 311end 312 313 314fun PERM_ELIM_DUPLICATES_CONV_DIRECT (l1,l2) common_terms = 315let 316 val thm_l1 = PERM_SPLIT_el_lists l1 common_terms; 317 val thm_l2 = PERM_SPLIT_el_lists l2 common_terms; 318 319 val l3 = (rand o concl) thm_l1 320 val l4 = (rand o concl) thm_l2 321 322 val (lc,l3') = listSyntax.dest_append l3 323 val (_,l4') = listSyntax.dest_append l4 324 325 val thm0 = ISPECL [lc,l1,l3',l2,l4'] PERM_CONG_APPEND_IFF; 326 val thm1 = MP thm0 thm_l1 327 val thm2 = MP thm1 thm_l2 328 val thm3 = CONV_RULE (RHS_CONV (REWRITE_CONV [PERM_REFL, PERM_NIL, NOT_CONS_NIL, 329 APPEND_eq_NIL])) thm2 330in 331 thm3 332end; 333 334fun ASSUM_BY_CONV conv thm = let 335 val thm = CONV_RULE (RATOR_CONV (RAND_CONV conv)) thm 336 in MP thm TRUTH handle HOL_ERR e => (print ("ASSUM_BY_CONV: conv-ed thm: " 337 ^ Parse.thm_to_string thm ^ "\n"); raise (HOL_ERR e)) end 338 339fun add_count d k n = Redblackmap.update (d, k, fn NONE => n | SOME m => m + n) 340fun look_count d k = case Redblackmap.peek (d, k) of NONE => 0 | SOME n => n 341 342local 343 fun strip_build_opers t ops = 344 if (listSyntax.is_cons t) then 345 strip_build_opers (rand t) (rator t :: ops) 346 else if (listSyntax.is_append t) then 347 let 348 val (t1,t2) = listSyntax.dest_append t; 349 in 350 strip_build_opers t2 (strip_build_opers t1 ops) 351 end 352 else if (listSyntax.is_nil t) then ops 353 else rator (listSyntax.mk_append (t, t)) :: ops 354 355 fun mk_div_list count [] (sel, rej) = (sel, rej) 356 | mk_div_list count (oper :: ops) (sel, rej) = 357 if look_count count (rand oper) > 0 358 then mk_div_list (add_count count (rand oper) (~1)) ops 359 (mk_comb (oper, sel), rej) 360 else mk_div_list count ops (sel, mk_comb (oper, rej)) 361in 362 fun strip_perm_list_div count t = let 363 val opers = strip_build_opers t [] 364 val empty = listSyntax.mk_list ([], listSyntax.eltype t) 365 in mk_div_list count opers (empty, empty) end 366end 367 368(* Proves PERM l1comm l2comm ==> PERM l1 l2 = PERM l1rem l2rem 369 where l1comm and l2comm are the elements of 'common' in the 370 order they appear in l1/l2, and l1rem and l2rem are the 371 remainders. Fast: O(n) proof steps, O(nlogn) calculation. *) 372fun PERM_ELIM_COMMON_IMP common l1 l2 = let 373 val comm_tab = foldl (fn (x, d) => add_count d x 1) 374 (Redblackmap.mkDict Term.compare) common 375 val (l1_comm, l1_rem) = strip_perm_list_div comm_tab l1 376 val (l2_comm, l2_rem) = strip_perm_list_div comm_tab l2 377 val thm = ISPECL [l1, l1_comm, l1_rem, l2, l2_comm, l2_rem] 378 PERM_CONG_APPEND_IFF2 379 val conv = simpLib.SIMP_CONV boolSimps.bool_ss [PERM_TO_APPEND_SIMPS] 380 in ASSUM_BY_CONV conv (ASSUM_BY_CONV conv thm) end 381 382fun PERM_ELIM_DUPLICATES_CONV t = 383let 384 val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED 385 val common_terms = perm_list_inter l1 l2 386 387 val _ = length ((op @) common_terms) > 0 orelse raise UNCHANGED 388 val l1_length = length ((op @) (strip_perm_list l1)) 389 fun half xs = List.take (xs, Int.min (l1_length div 2, length xs)) 390 391in if l1_length > 10 392 then PERM_ELIM_COMMON_IMP (half ((op @) common_terms)) l1 l2 393 |> ASSUM_BY_CONV PERM_ELIM_DUPLICATES_CONV 394 |> CONV_RULE (RHS_CONV PERM_ELIM_DUPLICATES_CONV) 395 else PERM_ELIM_DUPLICATES_CONV_DIRECT (l1,l2) common_terms 396end 397 398(* testing 399 400val t = ``PERM (x1::l1 ++ (l2 ++ (x2::x3::(1 : num)::l3) ++ x4::l4)) 401 (x1::(1 : num)::l1 ++ ((x2::x3::l3) ++ x4::l4 ++ l2))`` 402val (t1, t2) = dest_PERM t 403val comm = [``l2 : num list``, ``x3 : num``] 404 405val test_IMP = PERM_ELIM_COMMON_IMP comm t1 t2 406 407fun mk_num_list is = listSyntax.mk_list (map numSyntax.term_of_int is, ``: num``); 408fun mk_PERM a b = list_mk_icomb PERM_tm [a, b]; 409 410fun test1 n = mk_PERM (mk_num_list (upto 1 n)) (mk_num_list (rev (upto 1 n))) 411 |> PERM_ELIM_DUPLICATES_CONV; 412val t1_200 = test1 200; 413 414fun test2 n = let 415 val app = listSyntax.mk_append 416 val lhs = app (app (mk_num_list (upto 1 n), t1), mk_num_list (upto 12 (n + 11))) 417 val rhs = app (app (mk_num_list (rev (upto 12 (n + 11))), mk_num_list (upto 4 n)), 418 app (``rmn : num list``, t2)) 419 in PERM_ELIM_DUPLICATES_CONV (mk_PERM lhs rhs) end 420 421val t2_200 = test2 200; 422*) 423 424 425(* 426PERM_SPLIT ls l 427 428val ls = ``(l1 ++l2):'a list`` 429val l = ``l2 ++ x::l1`` 430*) 431 432fun PERM_SPLIT ls l = 433let 434 val (b,_,common_terms) = perm_sub_list ls l; 435 val _ = if b then () else raise UNCHANGED; 436 437 val thm_l = PERM_SPLIT_el_lists l common_terms; 438 val thm_ls = PERM_SPLIT_el_lists ls common_terms; 439 val thm_ls = CONV_RULE (RAND_CONV (REWR_CONV APPEND_NIL)) thm_ls; 440 441 val l' = (rand o concl) thm_l 442 val ls' = (rand o concl) thm_ls 443 val (lc,l'') = listSyntax.dest_append l' 444 445 val thm0 = ISPECL [l,lc,ls,l''] PERM_FUN_SPLIT; 446 val thm1 = MP thm0 thm_l 447 val thm2 = MP thm1 thm_ls 448in 449 thm2 450end; 451 452 453(* 454 val t = ``(l2++x::l3)`` 455 val t = ``((TAKE n l)++l2++x::l3++(DROP n l))`` 456 val t = ``((TAKE n l)++(DROP m l2)++l2++x::l3++(TAKE m l2)++(DROP n l))`` 457*) 458fun PERM_TAKE_DROP t = 459 let 460 val (_, ls) = strip_perm_list t; 461 val drop_ls = mapfilter listSyntax.dest_drop ls 462 val take_ls = mapfilter listSyntax.dest_take ls 463 val common = first (fn e => mem e drop_ls) take_ls; 464 465 val common_t = listSyntax.mk_append (listSyntax.mk_take common, listSyntax.mk_drop common); 466 val thm0 = PERM_SPLIT common_t t; 467 val thm1 = CONV_RULE ((RAND_CONV o RATOR_CONV o RAND_CONV) (REWR_CONV listTheory.TAKE_DROP)) thm0 468 469 val thm2_opt = (total PERM_TAKE_DROP) (rand (concl thm1)) 470 val thm3 = if not (isSome thm2_opt) then thm1 else 471 MATCH_MP PERM_TRANS (CONJ thm1 (valOf thm2_opt)) 472 in 473 thm3 474 end; 475 476 477(* 478 val l1 = ``(TAKE n l)++l2++x::l3++(DROP n l)`` 479 val l2 = ``(DROP m l)++x::l3++(TAKE m l)++(DROP n l)`` 480 val t = ``PERM ^l1 ^l2`` 481*) 482fun PERM_TAKE_DROP_CONV t = 483let 484 val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED; 485 486 val thm_l1_opt = (total PERM_TAKE_DROP) l1; 487 val thm_l2_opt = (total PERM_TAKE_DROP) l2; 488 val _ = if isSome thm_l1_opt orelse isSome thm_l2_opt then () else raise UNCHANGED; 489 490 val thm_l1 = if isSome thm_l1_opt then valOf thm_l1_opt else ISPEC l1 PERM_REFL; 491 val thm_l2 = if isSome thm_l2_opt then valOf thm_l2_opt else ISPEC l2 PERM_REFL; 492 493 val l1' = (rand o concl) thm_l1 494 val l2' = (rand o concl) thm_l2 495 val thm0 = ISPECL [l1,l1',l2,l2'] PERM_CONG_2; 496 val thm1 = MP thm0 thm_l1 497 val thm2 = MP thm1 thm_l2 498in 499 thm2 500end; 501 502 503fun PERM_NO_ELIM_NORMALISE_CONV t = 504let 505 val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED; 506 507 fun ELIM_NIL_RULE thm = CONV_RULE (RAND_CONV (REWR_CONV APPEND_NIL)) thm 508 handle HOL_ERR _ => thm; 509 510 val thm_l1 = ELIM_NIL_RULE (PERM_SPLIT_el_lists l1 (strip_perm_list l1)); 511 val thm_l2 = ELIM_NIL_RULE (PERM_SPLIT_el_lists l2 (strip_perm_list l2)); 512 513 val l1' = (rand o concl) thm_l1 514 val l2' = (rand o concl) thm_l2 515 516 val thm0 = ISPECL [l1,l1',l2,l2'] PERM_CONG_2; 517 val thm1 = MP thm0 thm_l1 518 val thm2 = MP thm1 thm_l2 519 val thm3 = CONV_RULE (RHS_CONV (REWRITE_CONV [APPEND, APPEND_NIL])) thm2 520in 521 thm3 522end; 523 524fun PERM_TURN_CONV t = 525let 526 val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED; 527 528 val (xs1,ls1) = strip_perm_list l1; 529 val (xs2,ls2) = strip_perm_list l2; 530 val comp = pair_compare (list_compare Term.compare, list_compare Term.compare); 531 532 val turn = (length xs1 + length ls1 < length xs2 + length ls2) orelse 533 ((length xs1 + length ls1 = length xs2 + length ls2) andalso 534 (length ls1 < length ls2)) orelse 535 ((length ls1 = length ls2) andalso 536 (length xs1 = length xs2) andalso 537 (comp ((xs1,ls1), (xs2,ls2)) = LESS)) 538in 539 if turn then REWR_CONV PERM_SYM t else raise UNCHANGED 540end; 541 542 543val PERM_NORMALISE_CONV = PERM_ELIM_DUPLICATES_CONV THENC 544 PERM_TAKE_DROP_CONV THENC 545 PERM_NO_ELIM_NORMALISE_CONV THENC 546 PERM_TURN_CONV; 547 548(* 549val thm = (ASSUME ``PERM l1 [x;y;z]``) 550val t = ``PERM (z::y::x'::l2) (l3++(x'::l1))`` 551 552val thm = (el 2 new_thmL) 553val t = (concl (el 2 new_thmL)) 554PERM_REWR_CONV (el 2 new_thmL) (concl (el 2 new_thmL)) 555 556show_assums := true 557PERM_REWR_CONV thm t 558*) 559 560fun PERM_REWR_CONV thm t = 561let 562 val (l,r) = dest_PERM (concl thm) 563 564 val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED; 565 val (turn,split_thm) = 566 (false, PERM_SPLIT l l1) handle UNCHANGED => 567 (true, PERM_SPLIT l l2); 568 569 val (thm0,l1,l2) = if turn then (ISPECL [l1,l2] PERM_SYM,l2,l1) else (REFL t,l1,l2); 570 571 val l1' = (rand o concl) split_thm 572 val thm1a = ISPECL [l1,l1',l2,l2] PERM_CONG_2 573 val thm1b = MP thm1a split_thm 574 val thm1c = MP thm1b (ISPEC l2 PERM_REFL); 575 val thm1 = TRANS thm0 thm1c 576 577 578 val thm2a = ISPECL [l,r,rand l1',l2] PERM_REWR 579 val thm2b = MP thm2a thm 580 val thm2 = TRANS thm1 thm2b 581 582 val thm3 = CONV_RULE (RHS_CONV PERM_NORMALISE_CONV) thm2 583in 584 thm3 585end; 586 587 588 589fun PERM_SIMP_CONV thmL t = 590 let 591 val _ = if is_PERM t then () else raise UNCHANGED; 592 val thm = FIRST_CONV ((CHANGED_CONV PERM_NORMALISE_CONV)::(map (QCHANGED_CONV o PERM_REWR_CONV) thmL)) t; 593 in 594 thm 595 end; 596 597 598local 599 600exception perm_reducer_context of thm list 601 602fun perm_reducer_get_context e = 603 (raise e) 604 handle perm_reducer_context thmL => thmL; 605 606 607fun clean_perm_thm thm = filter (is_PERM o concl) (BODY_CONJUNCTS thm); 608fun clean_perm_thmL thmL = flatten (map clean_perm_thm thmL); 609fun normalise_RULE l thm = CONV_RULE (REPEATC (PERM_SIMP_CONV l)) thm handle HOL_ERR _ => thm 610fun normalise_RULE_bool l thm = 611 let val thm' = normalise_RULE l thm; in 612 (not (aconv (concl thm) (concl thm')), thm') 613 end; 614 615fun perm_reducer_add_context old_thmL [] = old_thmL 616 | perm_reducer_add_context old_thmL (new_thm::new_thmL) = 617 case clean_perm_thm (normalise_RULE old_thmL new_thm) of 618 [] => perm_reducer_add_context old_thmL new_thmL 619 | (new_thm'::new_thmL') => 620 let 621 val old_thmLb' = map (normalise_RULE_bool [new_thm']) old_thmL 622 val (new_thmLb'', old_thmLb'') = partition fst old_thmLb'; 623 val new_thmL'' = map snd new_thmLb''; 624 val old_thmL'' = map snd old_thmLb''; 625 in 626 perm_reducer_add_context (new_thm'::old_thmL'') 627 (append new_thmL'' (append new_thmL' new_thmL)) 628 end; 629 630val perm_simplify_thmL = perm_reducer_add_context []; 631 632fun perm_reducer_add_context2 (ctx, thmL) = 633 perm_reducer_context (perm_reducer_add_context 634 (perm_reducer_get_context ctx) thmL); 635 636fun perm_reducer_add_context_simple (ctx, thmL) = 637 perm_reducer_context (append (clean_perm_thmL thmL) 638 (perm_reducer_get_context ctx)); 639 640val PERM_REDUCER = 641 Traverse.REDUCER {name = SOME "PERM_REDUCER", 642 initial = perm_reducer_context [], 643 addcontext = perm_reducer_add_context2, 644 apply = fn args => QCHANGED_CONV (PERM_SIMP_CONV (perm_reducer_get_context (#context args))) 645 }; 646 647val PERM_REDUCER_SIMPLE = 648 Traverse.REDUCER {name = SOME "PERM_REDUCER_SIMPLE", 649 initial = perm_reducer_context [], 650 addcontext = perm_reducer_add_context_simple, 651 apply = fn args => QCHANGED_CONV (PERM_SIMP_CONV (perm_reducer_get_context (#context args))) 652 }; 653 654in 655 656val PERM_ss = simpLib.SSFRAG 657 {name=SOME"PERM_ss", 658 convs = [], rewrs = [], filter = NONE, dprocs = [PERM_REDUCER], congs = [], 659 ac = [] 660 } 661 662val PERM_SIMPLE_ss = simpLib.SSFRAG 663 {name=SOME"PERM_SIMPLE_ss", 664 convs = [], rewrs = [], filter = NONE, dprocs = [PERM_REDUCER_SIMPLE], congs = [], 665 ac = [] 666 } 667 668fun NORMALISE_ASM_PERM_TAC (asm, t) = 669let 670 val (asm_perm, asm_rest) = partition is_PERM asm; 671 val asm_perm_thmL = perm_simplify_thmL (map ASSUME asm_perm) 672 673 val asm' = append asm_rest (map concl asm_perm_thmL); 674 fun reconstruct thm' = foldl (fn (h, thm) => PROVE_HYP h thm) thm' asm_perm_thmL 675in 676 ([(asm', t)], fn thmL => reconstruct (hd thmL)) 677end; 678 679end; 680 681 682(* 683 684val conv = SIMP_CONV (std_ss++PERM_ss) [] 685 686 687conv ``X /\ (PERM (x::l1++l2) (l2++[x])) /\ Z`` 688conv ``(PERM (x::z::l1++l2) (l3++x::l1)) /\ Z`` 689 690conv ``(X /\ (PERM (l2++[]++[z]) (y::l4)) /\ Y) ==> ((PERM (x::z::l1++l2) (l3++x::l1)))`` 691 692conv ``(PERM l1 m1 /\ 693 PERM l2 m2 /\ 694 PERM (l1 ++ l2) n1 /\ 695 PERM (m1 ++ m2) n2) ==> 696 PERM n1 n2`` 697 698*) 699 700fun SORTED_CONV conv = let 701 fun safe_conv t = if is_conj t orelse t = ``T`` 702 then NO_CONV t else CHANGED_CONV conv t 703 in 704 REWRITE_CONV [SORTED_DEF] 705 THENC TOP_DEPTH_CONV safe_conv 706 THENC simpLib.SIMP_CONV boolSimps.bool_ss [] 707 end 708 709(* Prove `ALL_DISTINCT xs = T` by permuting to a sorted list 710 (i.e. using theorems ALL_DISTINCT_PERM and SORTED_ALL_DISTINCT). 711 Requires a relation R, a theorem `irreflexive R /\ transitive R`, 712 a function f used to sort the terms of xs in ML, and a conversion that 713 can show `R x y` for any x/y for which f `x` `y`. *) 714fun ALL_DISTINCT_CONV rel_thm ord_f conv tm = let 715 val xs_t = listSyntax.dest_all_distinct tm 716 handle HOL_ERR _ => raise UNCHANGED 717 val (xs, elT) = listSyntax.dest_list xs_t 718 handle HOL_ERR _ => raise UNCHANGED 719 val xs_ord = sort ord_f xs 720 val xs_ord_t = listSyntax.mk_list (xs_ord, elT) 721 val part1 = if xs_ord = xs then (fn t => raise UNCHANGED) 722 else (fn t => sortingTheory.ALL_DISTINCT_PERM 723 |> ISPEC xs_t |> SPEC xs_ord_t 724 |> ASSUM_BY_CONV PERM_ELIM_DUPLICATES_CONV) 725 val part2_thm = MATCH_MP sortingTheory.SORTED_ALL_DISTINCT rel_thm 726 |> ISPEC xs_ord_t |> ASSUM_BY_CONV (SORTED_CONV conv) 727 in (part1 THENC simpLib.SIMP_CONV boolSimps.bool_ss [part2_thm]) tm end 728 729(* testing -- requires good_cmp_Less_irrefl_trans from comparisonTheory 730 731val num_ALL_DISTINCT_CONV = ALL_DISTINCT_CONV 732 (MATCH_MP good_cmp_Less_irrefl_trans comparisonTheory.num_cmp_good) 733 (fn x => fn y => numSyntax.int_of_term x < numSyntax.int_of_term y) EVAL; 734 735val test = mk_icomb (listSyntax.all_distinct_tm, mk_num_list 736 (map (fn x => (x * 17) mod 1000) (upto 5 800))) 737 |> num_ALL_DISTINCT_CONV; 738 739*) 740 741 742end 743