signature AC_PROOF_DATA = sig type T val get: Proof.context -> T val put: T -> Proof.context -> Proof.context valmap: (T -> T) -> Proof.context -> Proof.context val transfer: Proof.context -> Proof.context -> Proof.context end;
functor AC_Proof_Data(Data: PROOF_DATA_ARGS): AC_PROOF_DATA = struct structure Data = Proof_Data(Data); open Data; fun transfer from_ctxt to_ctxt = put (get from_ctxt) to_ctxt; end;
infix 1 force_then_conv;
infix 1 then_force_conv;
(* omits reflexive shortcut for cv2 to allow renaming of bound variables *) fun (cv1 then_force_conv cv2) ct = let val eq1 = cv1 ct; val eq2 = cv2 (Thm.rhs_of eq1); in if Thm.is_reflexive eq1 then eq2 else Thm.transitive eq1 eq2 end;
(* omits reflexive shortcut for cv1 to allow renaming of bound variables *) fun (cv1 force_then_conv cv2) ct = let val eq1 = cv1 ct; val eq2 = cv2 (Thm.rhs_of eq1); in if Thm.is_reflexive eq2 then eq1 else Thm.transitive eq1 eq2 end;
structure Utils = struct open Utils fun dest_name_type t = case t of
Free (n, T) => (n, T)
| Var ((n,i), T) => (n, T)
| Const (n, T) => (n, T)
| _ => raise TERM ("dest_name_type: unexpected term", [t])
fun transitive eq1 eq2 = Thm.transitive (safe_mk_meta_eq eq1) (safe_mk_meta_eq eq2)
(* Convert a term into a string. *) fun term_to_string ctxt t =
Syntax.check_term ctxt t
|> Thm.cterm_of ctxt
|> @{make_string}
fun pretty_term_typed ctxt t =
Pretty.block [Syntax.pretty_term ctxt t, Pretty.str ": ", Syntax.pretty_typ ctxt (fastype_of t)] fun string_of_term_typed ctxt ts = pretty_term_typed ctxt ts |> Pretty.string_of fun pretty_terms_typed ctxt ts =
Pretty.list"[""]" (map (pretty_term_typed ctxt) ts) fun string_of_terms_typed ctxt ts = pretty_terms_typed ctxt ts |> Pretty.string_of
(* Warning with 'autocorres' prefix. *) fun ac_warning str = warning ("autocorres: " ^ str)
(* List functions that should really be included in PolyML. *)
fun zipWith f (x::xs) (y::ys) = f x y :: zipWith f xs ys
| zipWith _ _ _ = [] fun zip xs ys = zipWith (curry I) xs ys fun zip3 (x::xs) (y::ys) (z::zs) = ((x,y,z)::(zip3 xs ys zs))
| zip3 _ _ _ = []
fun findIndex p = letfunfind _ [] = NONE
| find n (x::xs) = if p x then SOME (x, n) elsefind (n+1) xs infind0end
fun enumerate xs = let fun enum _ [] = []
| enum n (x::xs) = (n, x) :: enum (n+1) xs in enum 0 xs end
fun nubBy _ [] = []
| nubBy f (x::xs) = x :: filter (fn y => f x <> f y) (nubBy f xs)
fun accumulate f acc xs = let fun walk results acc [] = (results [], acc)
| walk results acc (x::xs) = let val acc' = f x acc; in walk (results o cons acc') acc' xs end; in walk I acc xs end;
fun fetch_thm name ctxt = let val thm = Proof_Context.get_thm ctxt name in
thm end
fun fetch_thms name ctxt = Proof_Context.get_thms ctxt name
fun export_prop {closed} inner outer prop = let val dummy_thm = Goal.prove_internal inner [] prop (fn _ => ALLGOALS (Skip_Proof.cheat_tac inner)) in
dummy_thm |> singleton (Proof_Context.export inner outer)
|> closed? Thm.forall_intr_vars
|> Thm.cprop_of end
(*** evaluate function in locale, preserving slots ***)
fun transfer_slots slots from to =
to |> fold (fn transfer => fn ctxt => transfer from ctxt) slots
(* Note that the result is the raw-result from the locale 'name' *) fun gen_in_locale_result slots name f lthy = let val start = Timing.start (); val bottom_locale = Named_Target.bottom_locale_of lthy val ((reenter, inner_lthy), transfer) = if bottom_locale = SOME name (* if we are already in the locale, stay there *) then ((I, lthy), (K (K I))) else (Target_Context.switch_named_cmd (SOME (name, Position.none)) (Context.Proof lthy) |> apfst (fn exit => Context.proof_of o exit),
transfer_slots) val _ = Utils.timing_msg' 2 lthy (fn _ => "gen_in_locale_result enter") start val (res, inner_lthy') = f (transfer slots lthy inner_lthy) val after = Timing.start (); val lthy' = inner_lthy'
|> reenter |> transfer slots inner_lthy' val _ = Utils.timing_msg' 2 lthy (fn _ => "gen_in_locale_result back") after in
(res, lthy') end
fun gen_in_locale slots name f lthy =
lthy |> gen_in_locale_result slots name (fn lthy => ((), f lthy)) |> snd
fun gen_eval_in_locale slots name f lthy = let val (_, inner_lthy) = Target_Context.switch_named_cmd (SOME (name, Position.none)) (Context.Proof lthy) val res = f (transfer_slots slots lthy inner_lthy) in
res end
fun gen_in_theory_result slots f lthy = let val reinit = if Named_Target.is_theory lthy then Named_Target.theory_init else Named_Target.init [] (the (Named_Target.bottom_locale_of lthy)) val thy = lthy |> Local_Theory.exit_global val (res, thy') = f thy val lthy' = thy' |> reinit |> transfer_slots slots lthy in
(res, lthy') end
fun gen_in_theory slots f lthy =
lthy |> gen_in_theory_result slots (fn thy => ((), f thy)) |> snd
fun gen_in_theory_result' slots f lthy = if Named_Target.is_theory lthy then
f lthy else let val reinit = Named_Target.init [] (the (Named_Target.bottom_locale_of lthy)) val (res, lthy') = lthy |> Local_Theory.exit_global
|> Named_Target.theory_init
|> transfer_slots slots lthy
|> f val lthy'' = lthy' |> Local_Theory.exit_global |> reinit |> transfer_slots slots lthy' in
(res, lthy'') end
fun gen_in_theory' slots f lthy =
lthy |> gen_in_theory_result' slots (fn thy => ((), f thy)) |> snd
(* *Defineaconstant"name"ofvalue"term"intothelocaltheory"lthy". * *Arguments"args"tothetermmaybegiven,whichconsistofalistofnames *andtypes.
*) fun define_const_args name qualify concealed term args decls attrs lthy = let fun maybe_hide x = if concealed then Binding.concealed x else x
(* Generate a header for the term. *) val head = betapplys (Free (name, (map snd args) ---> fastype_of term), args |> map Free) val new_term = Logic.mk_equals (head, term) val def_binding = Binding.make (name ^ "_def", \<^here>) |> maybe_hide |> qualify (* Define the constant. *) val lthy = lthy val ((lhs, (def_name, thm)), lthy) =
Specification.definition (SOME (maybe_hide (Binding.name name), NONE, NoSyn))
[] [] ((def_binding, attrs), new_term) lthy handle ERROR x => (tracing ("define_const_args: " ^ @{make_string} (Thm.cterm_of lthy term)); raise ERROR x) val lthy = lthy |> fold (fn thm_decl => thm_decl thm) decls in
((lhs, def_name, thm), lthy) end
fun define_global_const binding concealed term args attribs lthy = let val _ = @{assert} (Named_Target.is_theory lthy) fun maybe_hide x = if concealed then Binding.concealed x else x val name = Binding.name_of binding (* Generate a header for the term. *) val head = betapplys (Free (name, (map snd args) ---> fastype_of term), args |> map Free) val new_term = Logic.mk_equals (head, term)
(* Define the constant. *) (* The begin_nested / end_nested block removes hypothesis *Freedef_name\<equiv>Constglobal_constfromthelthy
*) val ((lhs, (def_name, thm)), lthy) = lthy |> Local_Theory.begin_nested |> snd |>
Specification.definition (SOME (maybe_hide (binding), NONE, NoSyn))
[] [] ((Binding.empty, attribs), new_term) handle ERROR x => (tracing ("define_global_const: " ^ @{make_string} (Thm.cterm_of lthy term)); raise ERROR x) val export = Local_Theory.target_morphism lthy in
((Morphism.term export lhs, Morphism.thm export thm), Local_Theory.end_nested lthy) end
val src_attr = Attrib.internal \<^here> o K
(* *Definea(possiblyrecursive)setoffunctions. * *Wetakealistoffunctions.Foreachfunction,wehaveaname,list *ofarguments,andabody(whichisassumedtohavealambda *abstractionforeachargument). * *Recursion(andmutualrecursion)canbeachievedbythebody *containingafreevariablewiththenameofthefunctiontobecalled *ofthecorrecttype. * *Terminationmustbeabletobeautomaticallyprovedforrecursive *functiondefinitionstosucceed.Thisimpliesthatrecursive *functionsmusthaveatleastoneargument(lesttherebenoarguments *toproveterminationon). * *Forexample,theinput: * *[("fact",[("n",@{typnat}],@{term"%n.ifn=0then1elsen*fact(n-1))})] * *woulddefineanewfunction"fact". * *Wereturnatuple: * *(<listoffunctiondefinitionthms>,<newcontext>)
*) fun define_functions func_defs (qualify: binding -> binding) concealed is_recursive ccpo_name name_attrs name_decls induct_decls lthy = let fun maybe_hide x = if concealed then Binding.concealed x else x fun attrs name = map (src_attr o rev_app name) name_attrs (* Define a set of mutually recursive functions. The function package *refusestomakeadefinitionthatdoesn'ttakeanyarguments,sowe
* use this strictly for functions with at least one argument. *) fun define_recursive_function func_defs lthy = let (* Get the list of function bindings. *) val function_bindings = map (fn (name, bname, _, _) =>
(ccpo_name, (maybe_hide (Binding.name bname), NONE, NoSyn))) func_defs
(* Get the list of function bodies. *) fun mk_fun_term name args body = let (* Get the type of the function, and generate a free term for it. *) val fun_free = Free (name, fastype_of body)
(* Create a head of the function, with appropriate arguments. *) val fun_head = fun_free val fun_body = body val def_eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (fun_head, fun_body)) in
def_eq end fun simps_binding bname = let val b = Binding.make ("simps", \<^here>) |> Binding.qualify true bname |> maybe_hide val qb = qualify b inif qb <> b then qb else Binding.empty end(* avoid duplicate fact declaration *)
fun subsingleton_solver ctxt = ALLGOALS (simp_tac ctxt) (* Define the function. *) val lthy = lthy val (info, lthy) =
lthy
|> Mutual_CCPO_Rec.add_fixed_point function_bindings
(map (fn (name, (b, body)) => (((b, attrs name), body), [], [])) function_bodies)
(subsingleton_solver)
val rec_simps = (#simps info) |> map (the_single o snd) val inducts = snd (#inducts info)
val lthy = lthy
|> fold (fn (name, thm) => fold (fn decl => decl name thm) name_decls #> fold (fn decl => decl name inducts) induct_decls)
(map fst function_bodies ~~ rec_simps) in
((#consts info, rec_simps, inducts), lthy) end in case (is_recursive, func_defs) of (* Single non-recursive function. *)
(false, [(name,bname, args, body)]) =>
define_const_args bname qualify concealed (betapplys (body, map Free args)) args (map (rev_app name) name_decls) (attrs name) lthy
|> (fn ((lhs, _, ctxt_thm), def_lthy) => (([lhs],[ctxt_thm], []), def_lthy))
| (true, _) => (* Recursion or mutual recursion. *)
define_recursive_function func_defs lthy end
(* Define a constant "name" of type "term" into the local theory "lthy". *) fun define_const name term lthy = let val lthy = lthy |> Local_Theory.begin_nested |> snd val ((_, (def_name, thm)), lthy) = Local_Theory.define ((Binding.name name, NoSyn), (Binding.empty_atts, term)) lthy val lthy' = Local_Theory.end_nested lthy val thm' = Morphism.thm (Local_Theory.target_morphism lthy) thm in
((def_name, thm'), lthy') end
fun define_const_eq name eq lthy = let
val ((_, (def_name, _)), lthy) =
Specification.definition (SOME (Binding.name name, NONE, NoSyn))
[] [] (Binding.empty_atts, eq) lthy in
(fetch_thm def_name, lthy) end
fun define_lemmas name thm_list attribs lthy = let val ((name, _), lthy) = Local_Theory.note ((Binding.name name, map (Attrib.internal \<^here> o K) attribs), thm_list) lthy in
(fetch_thms name, lthy) end
(* Define a single lemma into the local theory. *) fun define_lemma binding attribs thm lthy = let val ((name, [thm]), lthy) = Local_Theory.note ((binding, map src_attr attribs), [thm]) lthy in
(thm, lthy) end
fun define_lemma'' binding attribs thm lthy = let val ((name, [thm]), lthy) = Local_Theory.note ((binding, attribs), [thm]) lthy in
(thm, lthy) end
(* Define a single lemma into the local theory. *) fun define_lemma' binding decls thm lthy = let val ((name, [thm]), lthy) = Local_Theory.note ((binding, []), [thm]) lthy val lthy = lthy |> fold (fn decl => decl thm) decls in
(thm, lthy) end
(* Return an instance of the term "name". *) fun get_term ctxt name =
Syntax.read_term ctxt name
(* Calculate a fixpoint. *) fun fixpoint f eq init = let val new = f init in if (eq (new, init)) then init else (fixpoint f eq new) end
(* *Conveniencefunctionforgeneratingtypes. * *gen_typ@{typ"'a+'b"}[@{typword32},@{typnat}] * *willgenerate@{typ"word32+nat"}
*) fun gen_typ t params = let fun typ_convert (TFree (a, _)) = String.extract (a, 1, NONE)
|> (fn x => ord x - ord"a")
|> nth params
| typ_convert x = x in
Term.map_atyps typ_convert t end
(* Anonymous variable name for a lambda abstraction. *) (* TODO this is unused *) val dummy_abs_name = Name.internal Name.uu
(* *Determineifthegiventermcontainsthegivensubterm.
*) fun contains_subterm needle haysack =
exists_subterm (fn a => a = needle) haysack
(* *cterm_instantiatewithnamedparameter. * *(fromrecordspackage)
*) fun named_cterm_instantiate ctxt values thm = let funmatch name ((name', _), _) = name = name' fun getvar name =
(case find_first (match name) (Term.add_vars (Thm.prop_of thm) []) of
SOME var => #1 var
| NONE => raise THM ("named_cterm_instantiate: " ^ name, 0, [thm])); in
infer_instantiate ctxt (map (apfst getvar) values) thm end
(* *Fetchalluniqueschematicsinthegiventerm.
*) fun get_vars t = let val all_vars = fold_aterms (fn x => fn l =>
(case x of Var _ => (x :: l) | _ => l)) t [] in
sort_distinct Term_Ord.fast_term_ord all_vars end
(* *Givenafunction"f"thatreturnseitherSOMEctermorNONE,instantiate *everyschematicvariableinthegivenfunctionwiththeresultof"f". * *IfNONEisreturned,thevariableisleftas-is.
*) fun instantiate_thm_vars ctxt f thm = let (* Fetch all vars. *) val all_vars = get_vars (Thm.prop_of thm)
(* Get instantiations. *) val insts = map_filter (fn Var var => Option.map (fn x => (#1 var, x)) (f var)) all_vars in
infer_instantiate ctxt insts thm end
(* *Givenalistofname/ctermpairs,instantiateschematicvariablesinthe *given"thm"withthegivennamewiththectermvalues.
*) fun instantiate_thm ctxt vars thm = let val dict = Symtab.make vars in
instantiate_thm_vars ctxt (fn ((n, _), _) => Symtab.lookup dict n) thm end
(* Apply a conversion to the n'th argument of a term. If n < 0, count from the end. *) fun nth_arg_conv n conv c = let val num_args = Drule.strip_comb c |> snd |> length; val num_strips = num_args - (if n < 0then num_args + 1 + n else n); val new_conv = fold (fn _ => fn x => Conv.fun_conv x) (replicate num_strips ()) (Conv.arg_conv conv) in
new_conv c end handle Subscript => Conv.no_conv c
fun lhs_conv cv = Conv.combination_conv (Conv.arg_conv cv) Conv.all_conv; fun rhs_conv cv = Conv.combination_conv Conv.all_conv cv
(* *Unsafevarify. * *ConvertVar'stoFree's,avoidingnamingcollisions. * *fixme:Usesofthisfunctionareallbroken.
*) fun unsafe_unvarify term = let fun used_names (Free (x, _)) = [x]
| used_names (a $ b) = (used_names a) @ (used_names b)
| used_names (Abs (_, _, x)) = used_names x
| used_names _ = [] val term_names = used_names term in
map_aterms
(fn Var ((x, _), T) => Free (singleton (Name.variant_list term_names) x, T)
| x => x) term
|> map_types Logic.unvarifyT_global end
(* Attempt to guess if the given theorem is a "cong" rule. *) fun is_cong thm = case (Thm.concl_of thm) of
(Const (@{const_name "HOL.Trueprop"}, _) $ (Const (@{const_name "HOL.eq"}, _) $ lhs $ rhs)) =>
(Term.head_of lhs = Term.head_of rhs)
| _ => false
(* Given two theorems, attempt to rename bound variables in theorem "new" to
* use the names in theorem "old". *) fun thm_restore_names ctxt old_thm new_thm = let fun restore_names old new = case (old, new) of
(Abs (old_name, _, old_body), Abs (_, new_T, new_body)) =>
Abs (old_name, new_T, restore_names old_body new_body)
| ((x1 $ y1), (x2 $ y2)) =>
(restore_names x1 x2 $ restore_names y1 y2)
| (_, other) => other val renamed_prop = restore_names (Thm.prop_of old_thm) (Thm.prop_of new_thm) in
Thm.cterm_of ctxt renamed_prop
|> Goal.init
|> resolve_tac ctxt [new_thm] 1
|> Seq.hd
|> Goal.finish ctxt end
(* *Findtheterm"term"intheterm"body",andpullitoutintoalambda *function. * *Forinstance: * *abs_over"x"@{term"cat"}@{term"cat+dog"} * *wouldresultinthe(SOME@{term"%x.x+dog"}).
*) fun abs_over varname term body =
Term.lambda_name (varname, term) (incr_boundvars 1 body)
fun abs_over_apply varname term body = let val Abs (s, T, bdy) = Term.lambda_name (varname, term) (incr_boundvars 1 body) in
Abs (s, T, bdy $ Bound 0) end
(* *Abstractoveratupleofvariables. * *Forexample,giventhelist["a","b"]ofvariablestoabstractover,and *theterm"a+b+c",wewillproduce"%(a,b).a+b+c"where"a"and"b" *havebecomebound. * *Iftheinputisasingle-elementlist,thisfunctionisequivalentto *"abs_over".
*) fun abs_over_tuple [] body =
absdummy @{typ unit} body
| abs_over_tuple [(var_name, abs_term)] body =
abs_over var_name abs_term body
| abs_over_tuple ((var_name, abs_term)::xs) body =
HOLogic.mk_case_prod (abs_over var_name abs_term (abs_over_tuple xs body))
fun abs_over_list [] body =
absdummy @{typ unit} body
| abs_over_list [(var_name, abs_term)] body =
abs_over var_name abs_term body
| abs_over_list ((var_name, abs_term)::xs) body =
(abs_over var_name abs_term (abs_over_list xs body))
fun infer_head ctxt (c as Const (cn, cT)) args = let (* avoid large term arguments for type-inference by introducing fixed variables *) val (arg_names, ctxt') = Variable.variant_fixes (map (fn i => "_" ^ string_of_int i) (1 upto (length args))) ctxt val arg_types = map Term.fastype_of args val t = infer_types_simple ctxt (betapplys (Term.map_types (fn _ => dummyT) c, args)) val cT' = arg_types ---> fastype_of t in
betapplys (Const (cn, cT'), args) end handle ERROR str => raise TERM (str, c:: args)
(* Make a list of conjunctions. *) fun mk_conj_list [] = @{term "HOL.True"}
| mk_conj_list [x] = x
| mk_conj_list (x::xs) = HOLogic.mk_conj (x, (mk_conj_list xs))
(* Destruct a list of conjunctions. *) fun dest_conj_list (Const (@{const_name "HOL.conj"}, _) $ l $ r)
= l :: dest_conj_list r
| dest_conj_list x = [x]
fun gen_apply_tac print ctxt (step : string) thmfun (st : thm) = let val _ = ifprintthen print_tac ctxt step st else Seq.empty in
(thmfun st |> Seq.hd) handleOption => raise TERM ("Failed to apply tactic during " ^ quote step, Thm.prems_of st) end
val apply_tac = gen_apply_tac false
fun PRIM ctxt (step: string) thmfun = PRIMITIVE (apply_tac ctxt step thmfun)
(* *A"the"operatorthatexplainswhatisgoingwrong.
*) fun the' str x =
(the x) handleOption => error str
(* *Mapeveryiteminatermfrombottomtotop.Wedifferfrom *"map_aterms"becausewewillvisitcompoundterms,suchas *"a$b$c".
*) fun term_map_bot f (Abs (a, t, b)) = f (Abs (a, t, term_map_bot f b))
| term_map_bot f (a $ b) = f (term_map_bot f a $ term_map_bot f b)
| term_map_bot f x = f x
(* *Mapeveryiteminatermfromtoptobottom.Asecondparameteris *returnedbyourmappingfunction"f"whichissettotrueifwe *shouldhaltrecursionafteraparticularreplacement.
*) fun term_map_top' f x =
(case f x of
(x, true) => x
| (Abs (a, t, b), false) => Abs (a, t, term_map_top' f b)
| ((a $ b), false) => term_map_top' f a $ term_map_top' f b
| (x, false) => x) fun term_map_top f x = term_map_top' (fn x => (f x, false)) x
(* *Mapeveryiteminatermfromtoptobottom,collectingitems *inalistalongtheway.
*) fun term_fold_map_top' f x =
(case f x of
(l, x, true) => (l, x)
| (l, Abs (a, t, b), false) => let val (new_l, new_t) = term_fold_map_top' f b in
(l @ new_l, Abs (a, t, new_t)) end
| (l, (a $ b), false) => let val (list_a, new_a) = term_fold_map_top' f a val (list_b, new_b) = term_fold_map_top' f b in
(l @ list_a @ list_b, new_a $ new_b) end
| (l, x, false) => (l, x)) fun term_fold_map_top f x =
term_fold_map_top' (fn x =>
((f x, false) |> (fn ((a, b), c) => (a, b, c)))) x
fun import_universal_prop t ctxt = case t of Const (@{const_name Pure.all}, _) $ (abs as Abs (x, xT, P)) => let val ([v], ctxt') = fix_variant_frees [(x, xT)] ctxt val ((vs, t'), ctxt'') = import_universal_prop (betapply(abs, v)) ctxt' in
((v::vs, t'), ctxt'') end
| _ => (([], t), ctxt)
(* *Mapalllevelsofthesimpset.
*) fun simp_map f =
Context.map_proof (
Local_Theory.declaration {syntax = false, pervasive = false, pos = \<^here>} (
K (Simplifier.map_ss f)))
|> Context.proof_map
(* *Createastringfromatemplateandasetofvalues. * *Templatevariablesareoftheform"%n"where"n"isanumberbetween0and *9,indicatingthevaluetosubstitutein. * *Forexample,thetemplate"moo%0cow%1"withthevalues["cat","dog"] *wouldgenereate"moocatcowdog".
*) fun subs_template template vals = let fun subs_template' vals (#"%"::v::xs) =
(nth vals ((Char.ord v) - (Char.ord #"0"))) @ subs_template' vals xs
| subs_template' vals (v::xs) = v :: (subs_template' vals xs)
| subs_template' _ [] = [] in
subs_template' (map String.explode vals) (String.explode template)
|> String.implode end
(* Prove a set of rules, giving them the given names. *) fun prove_rules name lemmas tac lthy = let val thms = map (fn txt =>
Syntax.read_prop lthy txt
|> Syntax.check_term lthy
|> (fn x => Goal.prove lthy [] [] x (K tac))
|> Thm.forall_intr_frees
) lemmas in
Local_Theory.note ((Binding.name name, []), thms) lthy |> snd end
(* Prove a rule from the given string, giving it the given name. *) fun prove_rule name lemma tac lthy =
prove_rules name [lemma] tac lthy
(* *Givenatermoftheform"Abs(a,T,x)"andafunction"f"thatprocessesa *termintoanother,feedtheterm"x"to"f"suchthatboundvariablesare *replacedwithfreevariables,andthenabstractedoutagainonce"f"is *complete. * *Forexample,ifwearecalledwith: * *concrete_absf(Abs("x",@{typnat},Bound0)) * *then"f"willbegiven"Free("x",@{typnat})",andsuchinstancesofthis *freevariablewillbeabstractedoutagainonce"f"iscomplete. * *Thevariant"concrete_abs'"doesnotperformtheabstractionstep,but *insteadreturnstheFreevariableused.
*) fun concrete_abs' ctxt t = let val lambda_name = (case t of Abs (n, _, _) => n | _ => "x") val first_argT = domain_type (fastype_of t) val (n', _) = Name.variant lambda_name (Variable.names_of (Variable.declare_names t ctxt)) val free = Free (n', first_argT) in
((betapply (t, free)), free, n') end fun concrete_abs ctxt f t = let val (term, free, name) = concrete_abs' ctxt t in
f term |>> abs_over name free end
(* *Givenadefinition"thm"oftheform: * *xabc==a+b+c * *returnthe"thm"withargumentsinstantiated.
*) fun inst_args ctxt vals thm = let (* Fetch schematic variables on the LHS, stripping away locale assumptions
* and locale fixed variables first. *) val vars = Thm.cprop_of thm
|> Drule.strip_imp_concl
|> Thm.term_of
|> lhs_of_eq
|> Term.strip_comb
|> snd
|> filter (is_Var)
|> map (#1 o dest_Var) in
Drule.infer_instantiate ctxt ((take (length vals) vars) ~~ vals) thm end
(* *Atacticlike"rtac",butonlyperformsfirst-ordermatching.
*) fun first_order_rule_tac thm = SUBGOAL (fn (goal_term, n) => fn st => let val thy = Thm.theory_of_thm st val ctxt = Proof_Context.init_global thy
(* First-order match "thm" against the n'th premise of our goal. *) val thm_term = Thm.concl_of thm val tenv = Pattern.first_order_match thy (thm_term, goal_term)
(Vartab.empty, Vartab.empty) |> snd
(* Instantiate "thm" with the matched values. *) val inst = map (fn (var_name, (var_type, value)) =>
(var_name, Thm.cterm_of ctxt value))
(Vartab.dest tenv) val new_thm = infer_instantiate ctxt inst thm in
resolve_tac ctxt [new_thm] n st end handle Pattern.MATCH => Seq.empty)
(* Guess the name of a thm. *) fun guess_thm_name ctxt thm =
Find_Theorems.all_facts_of ctxt
|> get_first (fn (a, thm') => if Thm.eq_thm (thm, thm') then SOME (Thm_Name.print a) else NONE);
(* Expand type abbreviations. *) fun expand_type_abbrevs ctxt t = Thm.typ_of (Thm.ctyp_of ctxt t)
(* *Instantiatetheschematicsinathmfromthegivenenvironment.
*) fun instantiate_normalize_from_env ctxt env = let fun prep_type (x, (S, ty)) =
((x,S), Thm.ctyp_of ctxt ty) fun prep_term (x, (T, t)) =
((x,T), Thm.cterm_of ctxt t) val term_vals = Vartab.dest (Envir.term_env env) val typ_vals = Vartab.dest (Envir.type_env env) in
(Drule.instantiate_normalize
(TVars.make (map prep_type typ_vals), Vars.make (map prep_term term_vals))) end
(* *Aconversionwithbehavioursimilarto"applysubst". * *Inparticular,itcanapplyarewriteruleoftheform: * *?A+?A==f * *whereas"rewrite_conv"andfriendswillfailbecauseofthereuseof *theschematic?Aontheleft-hand-side.
*) fun subst_conv_raw ctxt thm ct = let val thy = Proof_Context.theory_of ctxt val lhs = lhs_of (Thm.concl_of thm)
(* Determine if the types match. *) val maybe_match =
(Sign.typ_unify thy (fastype_of lhs, fastype_of (Thm.term_of ct)) (Vartab.empty, 0); true) handleType.TUNIFY => false val maybe_match2 =
(Type.raw_unify (fastype_of lhs, fastype_of (Thm.term_of ct)) (Vartab.empty); true) handleType.TUNIFY => false
val _ = if maybe_match <> maybe_match2 then raise CTERM ("bub", [ct]) else ()
(* If so, attempt to unify. *) val env = if maybe_match then
Unify.matchers (Context.Proof ctxt) [(lhs, Thm.term_of ct)] handle ListPair.UnequalLengths => Seq.empty
| Term.TERM _ => Seq.empty else
Seq.empty in case Seq.pull env of
NONE =>
Conv.no_conv ct
| SOME (env, _) =>
Conv.rewr_conv (instantiate_normalize_from_env ctxt env thm) ct end fun subst_conv ctxt thm =
(Thm.eta_conversion
then_conv subst_conv_raw ctxt (Drule.eta_contraction_rule thm))
val eta_conv = Thm.eta_conversion val eta_norm = Conv.fconv_rule eta_conv val eta_contract = eta_conv #> Thm.rhs_of
(* A conversion to wade through any Isabelle/Pure or Isabelle/HOL
* logical gunf. *) fun remove_meta_conv conv ctxt ct =
(case Thm.term_of ct of Const (@{const_name "Pure.all"}, _) $ Abs _ =>
Conv.arg_conv (Conv.abs_conv (fn (_, ctxt) =>
remove_meta_conv conv ctxt) ctxt) ct
| Const (@{const_name "Trueprop"}, _) $ _ =>
Conv.arg_conv (remove_meta_conv conv ctxt) ct
| _ =>
conv ctxt ct
)
val beta_eta_normal_conv = Conv.bottom_conv (K Drule.beta_eta_conversion) fun beta_eta_normal_rule ctxt = Conv.fconv_rule (beta_eta_normal_conv ctxt)
(* Messages for non-critical errors. *) val keep_going_instruction = "\nPlease notify the AutoCorres maintainers of this failure. " ^ "In the meantime, use \"autocorres [keep_going]\" to ignore the failure." val keep_going_info = "\nIgnoring this error because keep_going is enabled."
(* Raise exceptions unless keep_going is set. *) fun TERM_non_critical keep_going msg term = if keep_going then warning (msg ^ keep_going_info) elseraise TERM (msg ^ keep_going_instruction, term)
fun CTERM_non_critical keep_going msg ct = if keep_going then warning (msg ^ keep_going_info) elseraise CTERM (msg ^ keep_going_instruction, ct)
fun THM_non_critical keep_going msg n thm = if keep_going then warning (msg ^ keep_going_info) elseraise THM (msg ^ keep_going_instruction, n, thm)
(* Perform a "Method.trace" on the given list of thms if the given tactic
* succeeds. *) fun trace_rule ctxt goal rule = if Config.get ctxt Method.rule_trace then let val _ = Goal_Display.print_goal ctxt "" goal |> tracing val _ = (case guess_thm_name ctxt rule of
SOME x => Pretty.str x
| NONE => Thm.pretty_thm_item ctxt rule)
|> Pretty.string_of |> tracing in
() end else ();
(* Apply the given tactic. If successful, trace the given "thm" and current
* goal state. *) fun trace_if_success ctxt thm tac goal =
(tac THEN (fn y => (trace_rule ctxt goal thm; all_tac y))) goal
(* Get the type a pointer points to. *) fun dest_ptrT T = dest_Type T |> snd |> hd fun mk_ptrT T = Type (@{type_name "ptr"}, [T])
(* Get / dest an option type. *) fun dest_optionT (Type ("Option.option", [x])) = x fun mk_optionT T = Type (@{type_name "option"}, [T])
(* Construct other terms. *) fun mk_the T t = Const (@{const_name "the"}, mk_optionT T --> T) $ t fun mk_Some T t = Const (@{const_name "Some"}, T --> mk_optionT T) $ t fun mk_fun_upd rangeT domT f src dest = Const (@{const_name "fun_upd"}, (rangeT --> domT) --> rangeT --> domT --> rangeT --> domT)
$ f $ src $ dest fun mk_bool true = @{term True}
| mk_bool false = @{term False}
(* Succeed only if there are no subgoals. *) fun solved_tac thm = if Thm.nprems_of thm = 0then Seq.single thm else Seq.empty
(* Convenience function for making simprocs. *) fun mk_simproc' ctxt (name : string, pats : string list, proc : Proof.context -> cterm -> thm option) = let in Simplifier.make_simproc ctxt {name = name, kind = Simproc, identifier = [],
lhss = map (Proof_Context.read_term_pattern ctxt) pats,
proc = K proc} end
(* Get named_theorems in reverse order. We use this for translation rulesets
* so that user-added rules can override the built-in ones. *) fun get_rules ctxt = Named_Theorems.get ctxt #> rev
(* As Substring.position but searches from the end *) fun positionr pat s = let val (s0, begin0, size0) = Substring.base s fun search i = if i < begin0 then
(s, Substring.substring (s0, begin0 + size0, 0)) (* not found *) elseifSubstring.isPrefix pat (Substring.substring (s0, i, size0 - i)) then
(Substring.substring (s0, begin0, i), (* found *) Substring.substring (s0, begin0 + i, size0 - i)) else search (i - 1) in search size0 end val _ = assert (apply2 Substring.string (positionr "br" (Substring.full "abracadabra"))
= ("abracada", "bra")) "" val _ = assert (apply2 Substring.string (positionr "xx" (Substring.full "abracadabra"))
= ("abracadabra", "")) ""
(* Merge a list of Symtabs. *) fun symtab_merge allow_dups tabs =
maps Symtab.dest tabs
|> (if allow_dups then sort_distinct (fast_string_ord o apply2 fst) else I)
|> Symtab.make;
(* Merge with custom merge operation. *) fun symtab_merge_with merge (tab1, tab2) =
sort_distinct fast_string_ord (Symtab.keys tab1 @ Symtab.keys tab2)
|> map (fn k => (k, case (Symtab.lookup tab1 k, Symtab.lookup tab2 k) of
(SOME x1, SOME x2) => merge (x1, x2)
| (SOME x1, NONE) => x1
| (NONE, SOME x2) => x2 (* (NONE, NONE) impossible *)))
|> Symtab.make
fun app_snds f ps = let val (xs, ys) = split_list ps in xs ~~ f ys end
fun map_reduce
(trace: (unit -> string) -> unit)
(string_of: ''c -> string)
(id:'b -> ''c)
(depends: ''c -> ''c list)
(f:'b -> 'a -> 'a)
(join: 'a list -> 'a)
(tasks: 'b list)
(acc: 'a) : (''c * 'a) list = let val group = Future.new_group NONE; fun params deps = {name = "map_reduce", group = SOME group, deps = deps, pri = 0, interrupts = true}; fun fork deps f = (singleton o Future.forks) (params deps) f fun string_of_tasks ts = ts |> map (string_of o id) |> Pretty.str_list "[""]" |> Pretty.string_of
fun work imports t () = let val acc = if null imports then acc else let val results = Future.joins (map snd imports) val res = join results in
res end val acc' = f t acc in acc' end
fun ready scheduled task = subset (op =) (depends (id task), map id scheduled)
fun group_tasks scheduled [] = scheduled
| group_tasks scheduled tasks = let val (next, waiting) = split_filter (ready (flat scheduled)) tasks val _ = if null next then error ("tasks cannot be scheduled according to dependencies. Stuck with:\n " ^ string_of_tasks tasks) else () in group_tasks (scheduled @ [next]) waiting end
fun task_imports forked task = let val imports = fold (fn t => fn xs =>
((t, the (AList.lookup (op =) forked t)))::xs) (depends (id task)) [] in imports end
fun fork_group tasks forked = let fun fork_work task = let val imports = task_imports forked task val deps = map (Future.task_of o snd) imports in (id task, fork deps (work imports task)) end in forked @ map fork_work tasks end
val grouped = group_tasks [[]] tasks val _ = trace (fn () => "grouped tasks: " ^ @{make_string} (map (map (string_of o id)) grouped))
val fork_all = let val running = fold fork_group grouped [] in running end
val results = app_snds Future.joins fork_all in
rev results end
(* Some Conversions and Tactics *)
fun beta (t1 $ t2) = (betapply (beta t1, t2))
| beta t = t
fun open_beta (t as (t1 $ _)) = (case open_beta t1 of Abs (_, _, b) => open_beta b | _ => t)
| open_beta t = t
val open_beta_eta = open_beta o snd o eta_redex val open_beta_norm_eta = open_beta o snd o norm_eta
val placeholder = @{pattern "?X"} |> (fn Var ((x, i), T) => Var (("_", i), T));
fun mk_pattern @{term_pat "?a $ ?b"} = (true, snd (mk_pattern a) $ snd (mk_pattern b))
| mk_pattern (Abs (x,T,b)) = letval (is_pattern, bdy) = mk_pattern b in (is_pattern, Abs ("_",T,bdy)) end
| mk_pattern _ = (false, placeholder)
fun reify_comb eq1 eq2 = let val rule = @{lemma "a \<equiv> a' \<Longrightarrow> b \<equiv> b' \<Longrightarrow> a b \<equiv> (a' $ b')"by simp} in rule OF [eq1, eq2] end
fun gen_combination_conv dest comb cv1 cv2 ct = letval (ct1, ct2) = dest ct in comb (cv1 ct1) (cv2 ct2) end;
fun gen_reify_comb_conv prep ctxt pat = let val pattern = prep pat fun conv (Var x) = Conv.all_conv
| conv (t1 $ t2) = gen_combination_conv Thm.dest_comb reify_comb (conv t1) (conv t2)
| conv (Abs (x, _, t)) = Conv.abs_conv (K (conv t)) ctxt
| conv _ = Conv.no_conv in conv pattern end
val reify_comb_conv = gen_reify_comb_conv (snd o mk_pattern)
fun dest_reified_comb ct = case Thm.term_of ct of
@{term_pat "?a $ ?b"} => Thm.dest_comb ct |>> Thm.dest_arg
| _ => raise CTERM ("no reified combination", [ct])
fun unreify_comb_conv ctxt pat = let val pattern = snd (mk_pattern pat) fun conv (Var x) = Conv.all_conv
| conv (t1 $ t2) = gen_combination_conv dest_reified_comb Thm.combination (conv t1) (conv t2)
| conv (Abs (x, _, t)) = Conv.abs_conv (K (conv t)) ctxt
| conv _ = Conv.no_conv in conv pattern end
fun trace_conv msg ct = let val _ = tracing (msg ^ @{make_string} ct) in Conv.all_conv ct end
fun trace_simps msg P ctxt = let val simps = simpset_of ctxt |> Simplifier.dest_simps |> filter P |> map #2 val _ = tracing (Pretty.string_of (Pretty.big_list msg (map (Thm.pretty_thm ctxt) simps))) in
() end
fun unify_env ctxt env pat obj = case Unify.unifiers (Context.Proof ctxt, env, [(pat, obj)]) |> Seq.pull of
SOME ((env,_), _) => env
| NONE => error ("unify_env failed; pat: " ^ Syntax.string_of_term ctxt pat ^ "\nobj: " ^ Syntax.string_of_term ctxt obj);
fun unify_insts ctxt env pat obj = case Unify.unifiers (Context.Proof ctxt, env, [(pat, obj)]) |> Seq.pull of
SOME ((env,_), _) => mk_unify_insts ctxt env
| NONE => error ("unify_insts failed; pat: " ^ Syntax.string_of_term ctxt pat ^ "\nobj: " ^ Syntax.string_of_term ctxt obj);
fun match_or_unify ctxt pat obj =
match_insts ctxt pat obj handle Pattern.MATCH => unify_insts ctxt (Envir.init) pat obj
fun get_index' P = get_index (fn x => if P x then SOME x else NONE)
fun get_last_index f = let fun get_aux (_: int) [] = NONE
| get_aux i (x :: xs) =
(case get_aux (i + 1) xs of
NONE => (case f x of NONE => NONE | SOME y => SOME (i, y))
| SOME y => SOME y) in get_aux 0end;
fun get_last_index' P = get_last_index (fn x => if P x then SOME x else NONE)
fun get_indexes f = let fun get_aux (_: int) [] = []
| get_aux i (x :: xs) = let val rest = get_aux (i + 1) xs in case f x of
NONE => rest
| SOME y => (i, y) :: rest end in get_aux 0end;
fun get_indexes' P = get_indexes (fn x => if P x then SOME x else NONE)
fun indexes [] xs = []
| indexes (i::is) xs = nth xs i :: indexes is xs
\<comment>\<open>
\<open>fo_arg_resolve_tac rule\<close> does some custom first order matching for a rule containing
the HOL-reified function application @{term "($)"}. Arguments containing @{term "($)"} are treated
differently according to their position:
* The last argument is considered to be *matched* against a *concrete term* in the goal
* Optional arguments before are not preprocessed so they are treated by ordinary rule composition.
Here is a typical example:
\<open>abstract_val ?Q ?x id ?x' \<Longrightarrow>
abstract_val ?P ?f id ?f' \<Longrightarrow>
abstract_val (?P \<and> ?Q) (?g $ ?f $ ?x) ?g (?f' $ ?x')\<close>
Argument \<open>(?f' $ ?x')\<close> is matched against a concrete term in the goal. This avoids higher-order
unification issues. Before resolving with the goal the auxiliary @{term "($)"} in this argument are
removed and replaced by the calculated instantiations for the schematic variables in the rule.
Argument \<open>(?g $ ?f $ ?x)\<close> is unified with a schematic variable in a goal and hence three distinct
schematic variables replacing g, a, b are introduced.
Note that this is a mere effect of ordinary rule composition. Hence, the auxiliary @{term "($)"} in
these arguments remain in the result.
.
\<close>
local
fun check_pattern rule arg = let val all_vars = [] |> fold_aterms (fn Var v => cons v | _ => I) arg val dups = duplicates (op =) all_vars
in ifnot (null dups) then error ("fo_arg_resolve_tac: schematic variables in first-order-patterns have to be unique:\n" ^
@{make_string} rule ^ "\n duplicates: " ^ @{make_string} (map (Term.string_of_vname o fst) dups)) else ()
end
in fun fo_arg_resolve_tac ctxt rule = let
val (head, args) = Thm.concl_of rule |> HOLogic.dest_Trueprop |> Term.strip_comb val exists_fun_app = exists_Const (fn (n, _) => (n = @{const_name "fun_app"})); val (n, arg_pat) = case get_last_index' exists_fun_app args of
NONE => error ("fo_arg_resolve_tac: expecting one argument with pattern containing '$'")
| SOME x => x; val _ = check_pattern rule arg_pat val nprems = Thm.nprems_of rule; fun unfold_fun_app ctxt = Conv.fconv_rule
(Conv.concl_conv (~1)
(Conv.arg_conv (* Trueprop *)
(nth_arg_conv (n + 1)
(Conv.bottom_conv (K (Conv.try_conv (Conv.rewr_conv @{thm "fun_app_def"}))) ctxt)))) val rule' = unfold_fun_app ctxt rule in
fn ctxt => CSUBGOAL (fn (ct, i) => fn st => let val t = Thm.term_of ct
fun match_arg t = t |> concl_of_subgoal_open |> concl_of_subgoal_open
|> HOLogic.dest_Trueprop |> Term.strip_comb |> snd |> (fn ts => nth ts n)
fun abs [] t = t
| abs ((x,T)::bs) t = abs bs (Abs (x, T, t))
fun fo_refl_tac ctxt i st = SUBGOAL (fn (t, i) => let val concl = concl_of_subgoal_open t val @{term_pat "Trueprop (?lhs = ?rhs)"} = concl val (has_comb, pat) = mk_pattern rhs val _ = ifnot has_comb thenraise Bind else () fun reify ctxt = Conv.every_conv [Drule.beta_eta_conversion, gen_reify_comb_conv I ctxt pat] fun gconv_reify i st =
PRIMITIVE (Conv.gconv_rule
(Conv.params_conv (~1)
(K (Conv.concl_conv (~1) (Conv.arg_conv (Conv.arg1_conv (reify ctxt))))) ctxt) i) st handle CTERM _ => no_tac st in
EVERY [
gconv_reify i, print_subgoal_tac "reify" ctxt i,
resolve_tac ctxt [refl] i
] end) i st handle Bind => no_tac st
fun fo_resolve_tac ctxt rules = let fun check rule = let val (prem::_) = Thm.prems_of rule val @{term_pat "Trueprop (?lhs = ?rhs)"} = prem val (Var _) = lhs val has_comb = fst (mk_pattern rhs) inifnot has_comb thenraise Bind else () end handle Bind => raise TERM ("fo_resolve_tac: major premise of rule has to have format '?x = (... $ ...)'", [Thm.prop_of rule]) val _ = map check rules in
EVERY' [resolve_tac ctxt rules, fo_refl_tac ctxt ORELSE' (print_subgoal_tac "fo_refl_tac failed: " ctxt THEN' (K no_tac))] end
fun prune_unused_bounds_tac ctxt maxidx all_bounds used_bounds t i = let fun add_var_app bounds t vars = case t of
(_ $ _) =>
(case strip_comb t of
(Var v, ts) => ((v, ts, bounds)::vars) |> fold (add_var_app bounds) ts
| (t, ts) => vars |> fold (add_var_app bounds) (t::ts))
| Abs (x,T, bdy) => add_var_app ((x,T)::bounds) bdy vars
| Var v => (v, [], bounds)::vars
| _ => vars
val vars = add_var_app [] t [] in case duplicates (op =) ((map (#1 o #1)) vars) of
(dups as (_::_)) =>
(warning ("prune_unused_bounds_tac: schematic variables not distinct, pruning skipped: "^
@{make_string} dups); all_tac)
| [] => let fun make_inst (((v, i), T), args, bounds) = let val (argTs, rangeT) = strip_type T val nbounds = length bounds val used_bounds = map (fn i => i + nbounds) used_bounds val all_bounds = map (fn i => i + nbounds) all_bounds fun strip_args _ [] [] = ([], [])
| strip_args pos (aT::argTs) [] = letval (argTs', args') = strip_args (pos - 1) argTs [] in (aT::argTs', Bound pos::args') end
| strip_args pos (aT::argTs) (arg::args) = let val res' as (argTs', args') = strip_args (pos - 1) argTs args in case arg of
Bound n => if member (op =) used_bounds n orelse not (member (op =) all_bounds n) then (aT::argTs', Bound pos::args') else res'
| _ => (aT::argTs', Bound pos:: args') end val (argTs', args') = strip_args (length argTs - 1) argTs args val T' = argTs' ---> rangeT val bdy = list_comb (Var ((v, maxidx + 1), T'), args') fun abs [] t = t
| abs (aT::aTs) t = Abs ("_", aT, abs aTs t) val abs_bdy = Thm.cterm_of ctxt (abs argTs bdy) in if length argTs' < length argTs then [(((v,i), T), abs_bdy)] else [] end val insts = map make_inst vars |> flat val _ = verbose_msg 2 ctxt (fn _ => "prune_unused_var_tac: pruning schematic variables: " ^
@{make_string} (map (apfst (Thm.cterm_of ctxt o Var)) insts))
in if null insts then all_tac else
EVERY [
PRIMITIVE (Thm.instantiate (TVars.empty, Vars.make insts)),
Simplifier.simp_tac (put_simpset HOL_basic_ss ctxt addsimps @{thms triv_forall_equality}) i] end end
fun prune_unused_bounds_from_concr_tac get_concr ctxt st i = CSUBGOAL (fn (cgoal, i) => let val t = Thm.term_of cgoal val (bounds, concl) = Utils.strip_concl_of_subgoal_open t
val concr = get_concr (HOLogic.dest_Trueprop concl)
val nbounds = length bounds val used_bounds = Term.loose_bnos concr val all_bounds = 0 upto (nbounds - 1) val _ = if length used_bounds = nbounds then (verbose_msg 2 ctxt (fn _ => "prune_unused_bounds_from_concr_tac: nothing to be done"); raise THM ("nothing to be done", i, [])) else () val maxidx = Thm.maxidx_of_cterm cgoal in
EVERY
[prune_unused_bounds_tac ctxt maxidx all_bounds used_bounds concl i,
Utils.verbose_print_subgoal_tac 4"after prune_unused_bounds_tac" ctxt i] end) st i handle THM ("nothing to be done", _, _) => K all_tac st i
fun THIN_tac prune_tac ctxt = CSUBGOAL (fn (ct, i) => case Utils.concl_of_subgoal_open (Thm.term_of ct) of
@{term_pat "(THIN ?P)"} =>
EVERY' [
resolve_tac ctxt @{thms THIN_I},
Goal.norm_hhf_tac ctxt,
prune_tac ctxt] i
| _ => no_tac
)
fun conjs [] = @{term True}
| conjs [P] = P
| conjs (P::Ps) = \<^instantiate>\<open>P = P and Q = \<open>conjs Ps\<close> in term \<open>P \<and> Q\<close>\<close>
fun conjs_cterm [] = @{cterm True}
| conjs_cterm [P] = P
| conjs_cterm (P::Ps) = \<^instantiate>\<open>P = P and Q = \<open>conjs_cterm Ps\<close> in cterm \<open>P \<and> Q\<close>\<close>
end(* structure Utils *)
(* Memoization using a serialized cache. *) signature Memo = sig type arg; val memo: (arg -> 'a) -> (arg -> 'a); end;
functor Memo(Table: TABLE) = struct type arg = Table.key; fun memo f = let val table = Synchronized.var "" Table.empty; in fn a =>
Synchronized.change_result table (fn tab => case Table.lookup tab a of
SOME r => (r, tab)
| NONE => let val r = f a; in (r, Table.update (a, r) tab) end) end; end; structure String_Memo = Memo(Symtab);
(* Insist the the given tactic solves a subgoal. *) fun SOLVES tac = SOLVED' (K tac) 1 fun SOLVES_debug ctxt msg tac =
SOLVES tac ORELSE (print_tac ctxt msg THEN no_tac)
(* Given a list of tactics, try them all, backtracking when necessary. *) fun APPEND_LIST tacs = fold_rev (curry op APPEND) tacs no_tac;
(* Profiling *)
signature Profile_Args = sig structure Key:KEY type from (* input of function *) type to (* output of function *) val make_string_from: int -> from -> string(* for tracing with verbosity level *) val make_string_to: int -> to -> string(* for tracing with verbosity level *) val make_string_key: int -> Key.key -> string(* for tracing with verbosity level *) val name:string(* name for profiling category, derived names for enabled / verbosity*) end
functor Profile(Args: Profile_Args) = struct structure Table = Table(Args.Key) structure Thy_Data = Theory_Data( type T = (Timing.timing * (Args.from * Args.to)) Table.table; val empty = Table.empty; val merge = Table.merge (K true);
) structure Prf_Data = Proof_Data( type T = (Timing.timing * (Args.from * Args.to)) Table.table Synchronized.var; fun init thy = Synchronized.var Args.name (Thy_Data.get thy);
) val enabled = Attrib.setup_config_bool
(Binding.make (Args.name ^ "_enabled", Binding.pos_of @{binding here})) (K false); val verbosity = Attrib.setup_config_int
(Binding.make (Args.name ^ "_verbosity", Binding.pos_of @{binding here})) (K 0); fun get ctxt = Synchronized.value (Prf_Data.get ctxt); fun transfer ctxt thy = Thy_Data.put (Synchronized.value (Prf_Data.get ctxt)) thy; fun transfer' ctxt0 ctxt1 = letval _ = Synchronized.change (Prf_Data.get ctxt1) (K (Synchronized.value (Prf_Data.get ctxt0))) in ctxt1 end fun lookup ctxt key = Table.lookup (Synchronized.value (Prf_Data.get ctxt)) key; fun tracing_msg ctxt maybe_key t x r = let val verb = Config.get ctxt verbosity fun nl pref msg = if msg = ""then""else pref ^ msg ^ "\n"; val key_msg = case maybe_key of SOME key => Args.make_string_key verb key | NONE => "" in if verb > 0then
tracing (Args.name ^ ": " ^ key_msg ^ "\n" ^
nl "input: " (Args.make_string_from verb x) ^
nl "result: " (Args.make_string_to verb r) ^
Timing.message t) else ()
end fun timeit ctxt maybe_key f x = if Config.get ctxt enabled then let val (t, result) = Timing.timing (Exn.result f) x; in case result of
Exn.Res r => let val _ = maybe_key |> Option.app (fn key =>
Synchronized.change (Prf_Data.get ctxt) (Table.update (key, (t, (x, r))))) val _ = tracing_msg ctxt maybe_key t x r in r end
| _ => Exn.release result end else f x; end
(*lexicographic product*) fun triple_ord a_ord b_ord c_ord ((x, y, z), (x', y', z')) =
(case a_ord (x, x') of EQUAL => prod_ord b_ord c_ord ((y, z), (y', z')) | ord => ord);
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.