1(* ========================================================================== *) 2(* FILE : tttTools.sml *) 3(* DESCRIPTION : Library of useful functions for TacticToe *) 4(* AUTHOR : (c) Thibault Gauthier, University of Innsbruck *) 5(* DATE : 2017 *) 6(* ========================================================================== *) 7 8structure tttTools :> tttTools = 9struct 10 11open HolKernel boolLib Abbrev Dep tttRedirect 12 13val ERR = mk_HOL_ERR "tttTools" 14 15type lbl_t = (string * real * goal * goal list) 16type fea_t = int list 17type feav_t = (lbl_t * fea_t) 18 19(* -------------------------------------------------------------------------- 20 Global parameters 21 -------------------------------------------------------------------------- *) 22 23val ttt_tactic_time = ref 0.05 24val ttt_search_time = ref (Time.fromReal 15.0) 25 26(* -------------------------------------------------------------------------- 27 Directories 28 -------------------------------------------------------------------------- *) 29 30val tactictoe_dir = HOLDIR ^ "/src/tactictoe" 31 32val ttt_tacfea_dir = tactictoe_dir ^ "/fea_tactic" 33val ttt_thmfea_dir = tactictoe_dir ^ "/fea_theorem" 34val ttt_glfea_dir = tactictoe_dir ^ "/fea_goallist" 35 36val ttt_code_dir = tactictoe_dir ^ "/gen_code" 37val ttt_open_dir = tactictoe_dir ^ "/gen_open" 38 39val ttt_search_dir = tactictoe_dir ^ "/log_search" 40val ttt_record_dir = tactictoe_dir ^ "/log_record" 41val ttt_buildheap_dir = tactictoe_dir ^ "/log_buildheap" 42val ttt_unfold_dir = tactictoe_dir ^ "/log_unfold" 43val ttt_eproof_dir = tactictoe_dir ^ "/proof_E" 44val ttt_proof_dir = tactictoe_dir ^ "/proof_ttt" 45 46(* do not use this with parallelism *) 47fun hide_out f x = 48 hide_in_file (ttt_code_dir ^ "/" ^ current_theory () ^ "_hide_out") f x 49 50(* -------------------------------------------------------------------------- 51 Commands 52 -------------------------------------------------------------------------- *) 53 54fun mkDir_err dir = 55 OS.FileSys.mkDir dir 56 handle Interrupt => raise Interrupt 57 | _ => () 58 59fun rmDir_err dir = 60 OS.FileSys.rmDir dir 61 handle Interrupt => raise Interrupt 62 | _ => () 63 64fun rmDir_rec dir = ignore (OS.Process.system ("rm -r " ^ dir)) 65 66fun cleanDir_rec dir = 67 ( 68 rmDir_rec dir; 69 mkDir_err dir 70 ) 71 72fun all_files dir = 73 let 74 val stream = OS.FileSys.openDir dir 75 fun loop acc stream = 76 case OS.FileSys.readDir stream of 77 NONE => acc 78 | SOME s => loop (s :: acc) stream 79 val l = loop [] stream 80 in 81 OS.FileSys.closeDir stream; 82 l 83 end 84 85fun clean_dir dir = 86 let 87 val _ = mkDir_err dir 88 val l0 = all_files dir 89 val l1 = map (fn x => OS.Path.concat (dir,x)) l0 90 in 91 app OS.FileSys.remove l1 92 end 93 94fun run_cmd cmd = ignore (OS.Process.system cmd) 95 96(* TODO: Use OS to change dir? *) 97fun cmd_in_dir dir cmd = run_cmd ("cd " ^ dir ^ "; " ^ cmd) 98 99fun exists_file file = OS.FileSys.access (file, []); 100 101(* -------------------------------------------------------------------------- 102 Dictionaries shortcuts 103 -------------------------------------------------------------------------- *) 104 105fun dfind k m = Redblackmap.find (m,k) 106fun dfind_err msg x dict = dfind x dict handle _ => raise ERR "dfind" msg 107 108fun drem k m = fst (Redblackmap.remove (m,k)) handle NotFound => m 109fun dmem k m = Lib.can (dfind k) m 110fun dadd k v m = Redblackmap.insert (m,k,v) 111fun daddl kvl m = Redblackmap.insertList (m,kvl) 112val dempty = Redblackmap.mkDict 113val dnew = Redblackmap.fromList 114val dlist = Redblackmap.listItems 115val dlength = Redblackmap.numItems 116val dapp = Redblackmap.app 117val dmap = Redblackmap.map 118val dfoldl = Redblackmap.foldl 119fun dkeys d = map fst (dlist d) 120 121fun inv_dict cmp d = dnew cmp (map (fn (a,b) => (b,a)) (dlist d)) 122 123(* -------------------------------------------------------------------------- 124 References 125 -------------------------------------------------------------------------- *) 126 127fun incr x = x := (!x) + 1 128fun decr x = x := (!x) + 1 129 130(* -------------------------------------------------------------------------- 131 Reserved tokens 132 -------------------------------------------------------------------------- *) 133 134val reserved_dict = 135 dnew String.compare 136 (map (fn x => (x,())) 137 ["op", "if", "then", "else", "val", "fun", 138 "structure", "signature", "struct", "sig", "open", 139 "infix", "infixl", "infixr", "andalso", "orelse", 140 "and", "datatype", "type", "where", ":", ";" , ":>", 141 "let", "in", "end", "while", "do", 142 "local","=>","case","of","_","|","fn","handle","raise","#", 143 "[","(",",",")","]","{","}","..."]) 144 145fun is_string s = String.sub (s,0) = #"\"" handle _ => false 146fun is_number s = Char.isDigit (String.sub (s,0)) handle _ => false 147fun is_chardef s = String.substring (s,0,2) = "#\"" handle _ => false 148 149fun is_reserved s = 150 dmem s reserved_dict orelse 151 is_number s orelse is_string s orelse is_chardef s 152 153(* -------------------------------------------------------------------------- 154 List 155 -------------------------------------------------------------------------- *) 156 157fun map_snd f l = map (fn (a,b) => (a, f b)) l 158fun map_fst f l = map (fn (a,b) => (f a, b)) l 159fun map_assoc f l = map (fn a => (a, f a)) l 160 161fun cartesian_product l1 l2 = 162 List.concat (map (fn x => map (fn y => (x,y)) l2) l1) 163 164fun findSome f l = case l of 165 [] => NONE 166 | a :: m => 167 let val r = f a in 168 if isSome r then r else findSome f m 169 end 170 171fun first_n n l = 172 if n <= 0 orelse null l 173 then [] 174 else hd l :: first_n (n - 1) (tl l) 175 176fun first_test_n test n l = 177 if n <= 0 orelse null l 178 then [] 179 else if test (hd l) 180 then hd l :: first_test_n test (n - 1) (tl l) 181 else first_test_n test n (tl l) 182 183fun part_aux n acc l = 184 if n <= 0 orelse null l 185 then (rev acc,l) 186 else part_aux (n - 1) (hd l :: acc) (tl l) 187 188fun part_n n l = part_aux n [] l 189 190fun number_list start l = case l of 191 [] => [] 192 | a :: m => (start,a) :: number_list (start + 1) m 193 194fun mk_fast_set compare l = 195 let 196 val empty_dict = dempty compare 197 fun f (k,dict) = dadd k () dict 198 in 199 map fst (Redblackmap.listItems (foldl f empty_dict l)) 200 end 201 202(* preserve the order of elements and take the first seen element as representant *) 203fun mk_sameorder_set_aux memdict rl l = 204 case l of 205 [] => rev rl 206 | a :: m => if dmem a memdict 207 then mk_sameorder_set_aux memdict rl m 208 else mk_sameorder_set_aux (dadd a () memdict) (a :: rl) m 209 210fun mk_sameorder_set compare l = mk_sameorder_set_aux (dempty compare) [] l 211 212(* Sort elements and preserve the order of equal elements *) 213fun dict_sort compare l = 214 let 215 val newl = number_list 0 l 216 fun newcompare ((n,x),(m,y)) = 217 case compare (x,y) of 218 EQUAL => Int.compare (n,m) 219 | LESS => LESS 220 | GREATER => GREATER 221 in 222 map snd (mk_fast_set newcompare newl) 223 end 224 225fun mk_string_set l = mk_fast_set String.compare l 226 227fun count_dict startdict l = 228 let 229 fun f (k,dict) = 230 let val old_n = dfind k dict handle _ => 0 in 231 dadd k (old_n + 1) dict 232 end 233 in 234 foldl f startdict l 235 end 236 237fun fold_left f l orig = case l of 238 [] => orig 239 | a :: m => let val new_orig = f a orig in fold_left f m new_orig end 240 241fun list_diff l1 l2 = filter (fn x => not (mem x l2)) l1 242 243fun topo_sort graph = 244 let val (topl,downl) = List.partition (fn (x,xl) => null xl) graph in 245 case (topl,downl) of 246 ([],[]) => [] 247 | ([],_) => raise ERR "topo_sort" "loop or missing nodes" 248 | _ => 249 let 250 val topl' = List.map fst topl 251 val graph' = List.map (fn (x,xl) => (x,list_diff xl topl')) downl 252 in 253 topl' @ topo_sort graph' 254 end 255 end 256 257fun sort_thyl thyl = topo_sort (map (fn x => (x, ancestry x)) thyl) 258 259 260(* --------------------------------------------------------------------------- 261 Reals 262 -------------------------------------------------------------------------- *) 263 264fun sum_real l = case l of [] => 0.0 | a :: m => a + sum_real m 265 266fun list_rmax l = case l of 267 [] => raise ERR "list_max" "" 268 | [a] => a 269 | a :: m => Real.max (a,list_rmax m) 270 271fun list_imax l = case l of 272 [] => raise ERR "list_imax" "" 273 | [a] => a 274 | a :: m => Int.max (a,list_imax m) 275 276fun sum_int l = case l of [] => 0 | a :: m => a + sum_int m 277 278fun average_real l = sum_real l / Real.fromInt (length l) 279 280fun int_div n1 n2 = 281 (if n2 = 0 then 0.0 else Real.fromInt n1 / Real.fromInt n2) 282 283fun pow (x:real) (n:int) = 284 if n <= 0 then 1.0 else x * (pow x (n-1)) 285 286fun approx n r = 287 let val mult = pow 10.0 n in 288 Real.fromInt (Real.round (r * mult)) / mult 289 end 290 291 292(* -------------------------------------------------------------------------- 293 Terms 294 -------------------------------------------------------------------------- *) 295 296fun rename_bvarl f tm = 297 let 298 val vi = ref 0 299 fun rename_aux tm = case dest_term tm of 300 VAR(Name,Ty) => tm 301 | CONST{Name,Thy,Ty} => tm 302 | COMB(Rator,Rand) => mk_comb (rename_aux Rator, rename_aux Rand) 303 | LAMB(Var,Bod) => 304 let 305 val vs = f (fst (dest_var Var)) 306 val new_tm = rename_bvar ("V" ^ int_to_string (!vi) ^ vs) tm 307 val (v,bod) = dest_abs new_tm 308 val _ = incr vi 309 in 310 mk_abs (v, rename_aux bod) 311 end 312 in 313 rename_aux tm 314 end 315 316fun all_bvar tm = 317 mk_fast_set Term.compare (map (fst o dest_abs) (find_terms is_abs tm)) 318 319(* -------------------------------------------------------------------------- 320 Goal 321 -------------------------------------------------------------------------- *) 322 323fun string_of_goal (asm,w) = 324 let 325 val mem = !show_types 326 val _ = show_types := false 327 val s = 328 (if asm = [] 329 then "[]" 330 else "[``" ^ String.concatWith "``,``" (map term_to_string asm) ^ 331 "``]") 332 val s1 = "(" ^ s ^ "," ^ "``" ^ (term_to_string w) ^ "``)" 333 in 334 show_types := mem; 335 s1 336 end 337 338fun string_of_bool b = if b then "T" else "F" 339 340(* -------------------------------------------------------------------------- 341 Comparisons 342 -------------------------------------------------------------------------- *) 343 344fun compare_imax ((_,r2),(_,r1)) = Int.compare (r1,r2) 345fun compare_imin ((_,r1),(_,r2)) = Int.compare (r1,r2) 346 347fun compare_rmax ((_,r2),(_,r1)) = Real.compare (r1,r2) 348fun compare_rmin ((_,r1),(_,r2)) = Real.compare (r1,r2) 349 350fun goal_compare ((asm1,w1), (asm2,w2)) = 351 list_compare Term.compare (w1 :: asm1, w2 :: asm2) 352 353fun cpl_compare cmp1 cmp2 ((a1,a2),(b1,b2)) = 354 let val r = cmp1 (a1,b1) in 355 if r = EQUAL then cmp2 (a2,b2) else r 356 end 357 358fun strict_term_compare (t1,t2) = 359 if Portable.pointer_eq (t1,t2) then EQUAL 360 else if is_var t1 andalso is_var t2 then Term.compare (t1,t2) 361 else if is_var t1 then LESS 362 else if is_var t2 then GREATER 363 else if is_const t1 andalso is_const t2 then Term.compare (t1,t2) 364 else if is_const t1 then LESS 365 else if is_const t2 then GREATER 366 else if is_comb t1 andalso is_comb t2 then 367 cpl_compare strict_term_compare 368 strict_term_compare (dest_comb t1, dest_comb t2) 369 else if is_comb t1 then LESS 370 else if is_comb t2 then GREATER 371 else 372 cpl_compare Term.compare strict_term_compare (dest_abs t1, dest_abs t2) 373 374fun strict_goal_compare ((asm1,w1), (asm2,w2)) = 375 list_compare strict_term_compare (w1 :: asm1, w2 :: asm2) 376 377fun lbl_compare ((stac1,_,g1,_),(stac2,_,g2,_)) = 378 cpl_compare String.compare goal_compare ((stac1,g1),(stac2,g2)) 379 380fun feav_compare ((lbl1,_),(lbl2,_)) = lbl_compare (lbl1,lbl2) 381 382(* -------------------------------------------------------------------------- 383 I/O 384 -------------------------------------------------------------------------- *) 385 386fun bare_readl path = 387 let 388 val file = TextIO.openIn path 389 fun loop file = case TextIO.inputLine file of 390 SOME line => line :: loop file 391 | NONE => [] 392 val l = loop file 393 in 394 (TextIO.closeIn file; l) 395 end 396 397fun readl path = 398 let 399 val file = TextIO.openIn path 400 fun loop file = case TextIO.inputLine file of 401 SOME line => line :: loop file 402 | NONE => [] 403 val l1 = loop file 404 fun rm_last_char s = String.substring (s,0,String.size s - 1) 405 fun is_empty s = s = "" 406 val l2 = map rm_last_char l1 (* removing end line *) 407 val l3 = filter (not o is_empty) l2 408 in 409 (TextIO.closeIn file; l3) 410 end 411 412fun readl_empty path = 413 let 414 val file = TextIO.openIn path 415 fun loop file = case TextIO.inputLine file of 416 SOME line => line :: loop file 417 | NONE => [] 418 val l1 = loop file 419 fun rm_last_char s = String.substring (s,0,String.size s - 1) 420 val l2 = map rm_last_char l1 (* removing end line *) 421 in 422 (TextIO.closeIn file; l2) 423 end 424 425 426fun write_file file s = 427 let val oc = TextIO.openOut file in 428 TextIO.output (oc,s); TextIO.closeOut oc 429 end 430 431fun erase_file file = write_file file "" handle _ => () 432 433fun writel file sl = 434 let val oc = TextIO.openOut file in 435 app (fn s => TextIO.output (oc, s ^ "\n")) sl; 436 TextIO.closeOut oc 437 end 438 439fun append_file file s = 440 let val oc = TextIO.openAppend file in 441 TextIO.output (oc,s); TextIO.closeOut oc 442 end 443 444fun append_endline file s = append_file file (s ^ "\n") 445 446(* -------------------------------------------------------------------------- 447 Profiling 448 -------------------------------------------------------------------------- *) 449 450fun add_time f x = 451 let 452 val rt = Timer.startRealTimer () 453 val r = f x 454 val time = Timer.checkRealTimer rt 455 in 456 (r, Time.toReal time) 457 end 458 459fun total_time total f x = 460 let val (r,t) = add_time f x in (total := (!total) + t; r) end 461 462fun print_time s r = print (s ^ ": " ^ Real.toString r ^ "\n") 463 464fun print_endline s = print (s ^ "\n") 465 466(* -------------------------------------------------------------------------- 467 Debugging and exporting feature vectors 468 -------------------------------------------------------------------------- *) 469 470(* unfold_dir *) 471val ttt_unfold_cthy = ref "scratch" 472 473fun debug_unfold s = 474 append_endline (ttt_unfold_dir ^ "/" ^ !ttt_unfold_cthy) s 475 476(* search_dir *) 477fun debug s = append_endline (ttt_search_dir ^ "/debug/" ^ current_theory ()) s 478 479fun debug_err s = (debug s; raise ERR "debug_err" s) 480 481fun debug_t s f x = 482 let 483 val _ = debug s 484 val (r,t) = add_time f x 485 val _ = debug (s ^ " " ^ Real.toString t) 486 in 487 r 488 end 489 490val debugsearch_flag = ref false 491 492fun set_debugsearch b = debugsearch_flag := b 493 494fun debug_search s = 495 if !debugsearch_flag 496 then append_endline (ttt_search_dir ^ "/search/" ^ current_theory ()) s 497 else () 498 499fun debug_proof s = 500 append_endline (ttt_proof_dir ^ "/" ^ current_theory ()) s 501 502fun debug_eproof s = 503 append_endline (ttt_eproof_dir ^ "/" ^ current_theory ()) s 504 505(* record_dir *) 506fun debug_parse s = 507 append_endline (ttt_record_dir ^ "/parse/" ^ current_theory ()) s 508 509fun debug_replay s = 510 append_endline (ttt_record_dir ^ "/replay/" ^ current_theory ()) s 511 512fun debug_record s = 513 append_endline (ttt_record_dir ^ "/record/" ^ current_theory ()) s 514 515(* -------------------------------------------------------------------------- 516 Parsing 517 -------------------------------------------------------------------------- *) 518 519fun unquote_string s = 520 if String.sub (s,0) = #"\"" andalso String.sub (s,String.size s - 1) = #"\"" 521 then String.substring (s, 1, String.size s - 2) 522 else raise ERR "unquote_string" s 523 524fun drop_sig s = 525 if last (explode s) = #"." 526 then s 527 else last (String.fields (fn x => x = #".") s) 528 529fun rm_last_n_string n s = 530 let 531 val l = explode s 532 val m = length l 533 in 534 implode (first_n (m - n) l) 535 end 536 537fun filename_of s = last (String.tokens (fn x => x = #"/") s) 538 handle _ => raise ERR "filename_of" s 539 540fun split_sl_aux s pl sl = case sl of 541 [] => raise ERR "split_sl_aux" "" 542 | a :: m => if a = s 543 then (rev pl, m) 544 else split_sl_aux s (a :: pl) m 545 546fun split_sl s sl = split_sl_aux s [] sl 547 548fun rpt_split_sl s sl = 549 let val (a,b) = split_sl s sl handle _ => (sl,[]) 550 in 551 if null b then [a] else a :: rpt_split_sl s b 552 end 553 554 555fun split_level_aux i s pl sl = case sl of 556 [] => raise ERR "split_level_aux" s 557 | a :: m => if a = s andalso i <= 0 558 then (rev pl, m) 559 else if mem a ["let","local","struct","(","[","{"] 560 then split_level_aux (i + 1) s (a :: pl) m 561 else if mem a ["end",")","]","}"] 562 then split_level_aux (i - 1) s (a :: pl) m 563 else split_level_aux i s (a :: pl) m 564 565fun split_level s sl = split_level_aux 0 s [] sl 566 567fun rpt_split_level s sl = 568 let val (a,b) = split_level s sl handle _ => (sl,[]) 569 in 570 if null b then [a] else a :: rpt_split_level s b 571 end 572 573fun split_charl acc buf csm l1 l2 = 574 if csm = [] then (rev acc, l2) else 575 case l2 of 576 [] => raise ERR "split_charl" "" 577 | a :: m => if hd csm = a 578 then split_charl acc (a :: buf) (tl csm) l1 m 579 else split_charl (a :: (buf @ acc)) [] l1 l1 m 580 581fun split_string s1 s2 = 582 let 583 val (l1,l2) = (explode s1, explode s2) 584 val (rl1,rl2) = split_charl [] [] l1 l1 l2 585 in 586 (implode rl1, implode rl2) 587 end 588 handle _ => raise ERR "split_string" (s1 ^ " " ^ s2) 589 590fun rm_prefix s2 s1 = 591 let val (a,b) = split_string s1 s2 in 592 if a = "" then b else raise ERR "rm_prefix" (s2 ^ " " ^ s1) 593 end 594 595fun rm_squote s = 596 if String.sub (s,0) = #"\"" andalso String.sub (s,String.size s - 1) = #"\"" 597 then String.substring (s, 1, String.size s - 2) 598 else raise ERR "rm_squote" s 599 600fun rm_space_aux l = case l of 601 [] => [] 602 | a :: m => if a = #" " then rm_space_aux m else l 603 604fun rm_space s = implode (rm_space_aux (explode s)) 605 606(* -------------------------------------------------------------------------- 607 Tactics 608 -------------------------------------------------------------------------- *) 609 610val ttt_tacerr = ref [] 611val ttt_tacfea = ref (dempty lbl_compare) 612val ttt_tacfea_cthy = ref (dempty lbl_compare) 613val ttt_tacdep = ref (dempty goal_compare) 614val ttt_taccov = ref (dempty String.compare) 615 616(* -------------------------------------------------------------------------- 617 Theorems 618 -------------------------------------------------------------------------- *) 619 620val ttt_thmfea = ref (dempty goal_compare) 621 622(* Warning: causes a problem if a theory is named namespace_tag *) 623val namespace_tag = "namespace_tag" 624 625fun dbfetch_of_string s = 626 let val (a,b) = split_string "Theory." s in 627 if a = current_theory () 628 then String.concatWith " " ["DB.fetch",mlquote a,mlquote b] 629 else 630 if a = namespace_tag then b else s 631 end 632 633fun mk_metis_call sl = 634 "metisTools.METIS_TAC " ^ 635 "[" ^ String.concatWith " , " (map dbfetch_of_string sl) ^ "]" 636 637(* -------------------------------------------------------------------------- 638 Lists of goals 639 -------------------------------------------------------------------------- *) 640 641val ttt_glfea = ref (dempty (list_compare Int.compare)) 642val ttt_glfea_cthy = ref (dempty (list_compare Int.compare)) 643 644(* -------------------------------------------------------------------------- 645 Cleaning tactictoe data (not necessary) 646 -------------------------------------------------------------------------- *) 647 648fun clean_tttdata () = 649 ( 650 ttt_tacerr := []; 651 ttt_tacfea := dempty lbl_compare; 652 ttt_tacfea_cthy := dempty lbl_compare; 653 ttt_tacdep := dempty goal_compare; 654 ttt_taccov := dempty String.compare; 655 ttt_thmfea := dempty goal_compare; 656 ttt_glfea := dempty (list_compare Int.compare); 657 ttt_glfea_cthy := dempty (list_compare Int.compare) 658 ) 659 660(*---------------------------------------------------------------------------- 661 escaping (for ATPs than do not support single quotes) 662 ----------------------------------------------------------------------------*) 663 664fun escape_char c = 665 if Char.isAlphaNum c then Char.toString c 666 else if c = #"_" then "__" 667 else 668 let val hex = Int.fmt StringCvt.HEX (Char.ord c) in 669 StringCvt.padLeft #"_" 3 hex 670 end 671 672fun escape s = String.translate escape_char s; 673 674fun isCapitalHex c = 675 Char.ord #"A" <= Char.ord c andalso Char.ord c <= Char.ord #"F" 676 677fun charhex_to_int c = 678 if Char.isDigit c 679 then Char.ord c - Char.ord #"0" 680 else if isCapitalHex c 681 then Char.ord c - Char.ord #"A" + 10 682 else raise ERR "charhex_to_int" "" 683 684fun unescape_aux l = case l of 685 [] => [] 686 | #"_" :: #"_" :: m => #"_" :: unescape_aux m 687 | #"_" :: a :: b :: m => 688 Char.chr (16 * charhex_to_int a + charhex_to_int b) :: unescape_aux m 689 | a :: m => a :: unescape_aux m 690 691fun unescape s = implode (unescape_aux (explode s)) 692 693(*---------------------------------------------------------------------------- 694 Theorems 695 ----------------------------------------------------------------------------*) 696 697fun depnumber_of_thm thm = 698 (Dep.depnumber_of o Dep.depid_of o Tag.dep_of o Thm.tag) thm 699 handle HOL_ERR _ => raise ERR "depnumber_of_thm" "" 700 701fun depidl_of_thm thm = 702 (Dep.depidl_of o Tag.dep_of o Thm.tag) thm 703 handle HOL_ERR _ => raise ERR "depidl_of_thm" "" 704 705fun tid_of_did (thy,n) = 706 let fun has_depnumber n (_,thm) = n = depnumber_of_thm thm in 707 case List.find (has_depnumber n) (DB.thms thy) of 708 SOME (name,_) => SOME (thy ^ "Theory." ^ name) 709 | NONE => NONE 710 end 711 712fun exists_did did = isSome (tid_of_did did) 713 714fun depl_of_thm thm = 715 let 716 fun f x = x = NONE 717 val l = map tid_of_did (depidl_of_thm thm) 718 val l' = filter f l 719 in 720 (null l', mapfilter valOf l) 721 end 722 723fun deplPartial_of_sthm s = 724 let val (a,b) = split_string "Theory." s in 725 if a = namespace_tag 726 then [] 727 else List.mapPartial tid_of_did (depidl_of_thm (DB.fetch a b)) 728 end 729 730fun only_concl x = 731 let val (a,b) = dest_thm x in 732 if null a then b else raise ERR "only_concl" "" 733 end 734 735(*---------------------------------------------------------------------------- 736 Parallelism 737 ----------------------------------------------------------------------------*) 738 739datatype 'a result = Res of 'a | Exn of exn; 740 741fun capture f x = Res (f x) handle e => Exn e 742 743fun release (Res y) = y 744 | release (Exn x) = raise x 745 746fun is_res (Res y) = true 747 | is_res (Exn x) = false 748 749fun is_exn (Res y) = false 750 | is_exn (Exn x) = true 751 752fun interruptkill worker = 753 if Thread.isActive worker 754 then 755 ( 756 Thread.interrupt worker handle Thread _ => (); 757 if Thread.isActive worker 758 then Thread.kill worker 759 else () 760 ) 761 else () 762 763fun compare_imin (a,b) = Int.compare (snd a, snd b) 764 765fun parmap_err ncores forg lorg = 766 let 767 (* input *) 768 val sizeorg = length lorg 769 val lin = List.tabulate (ncores,(fn x => (x, ref NONE))) 770 val din = dnew Int.compare lin 771 fun fi xi x = (x,xi) 772 val queue = ref (mapi fi lorg) 773 (* update process inputs *) 774 fun update_from_queue lineref = 775 if null (!queue) then () 776 else (lineref := SOME (hd (!queue)); queue := tl (!queue)) 777 fun is_refnone x = (not o isSome o ! o snd) x 778 fun dispatcher () = 779 app (update_from_queue o snd) (filter is_refnone lin) 780 (* output *) 781 val lout = List.tabulate (ncores,(fn x => (x, ref []))) 782 val dout = dnew Int.compare lout 783 val lcount = List.tabulate (ncores,(fn x => (x, ref 0))) 784 val dcount = dnew Int.compare lcount 785 (* process *) 786 fun process pi = 787 let val inref = dfind pi din in 788 case !inref of 789 NONE => process pi 790 | SOME (x,xi) => 791 let 792 val oldl = dfind pi dout 793 val oldn = dfind pi dcount 794 val y = capture forg x 795 in 796 oldl := (y,xi) :: (!oldl); 797 incr oldn; 798 inref := NONE; 799 process pi 800 end 801 end 802 fun fork_on pi = Thread.fork (fn () => process pi, []) 803 val threadl = map fork_on (List.tabulate (ncores,I)) 804 fun loop () = 805 ( 806 dispatcher (); 807 if null (!queue) andalso sum_int (map (! o snd) lcount) >= sizeorg 808 then app interruptkill threadl 809 else loop () 810 ) 811 in 812 loop (); 813 map fst (dict_sort compare_imin (List.concat (map (! o snd) lout))) 814 end 815 816fun parmap ncores f l = 817 map release (parmap_err ncores f l) 818 819fun parapp ncores f l = ignore (parmap ncores f l) 820 821end (* struct *) 822