File ‹Tools/SMT/alethe/alethe_replay.ML›
signature ALETHE_REPLAY =
sig
val replay: string -> (string -> Proof.context -> thm list -> term list -> term list -> term -> tactic_args option -> thm) ->
Proof.context -> SMT_Translate.replay_data -> string list -> thm
end;
structure Alethe_Replay: ALETHE_REPLAY =
struct
open SMT_Config
fun debug_msg ctxt = alethe_debug_msg ctxt "alethe_replay"
fun debug_cond_msg ctxt cond verbosity msg = (if cond then debug_msg ctxt verbosity msg else ())
fun subst_only_free pairs =
let
fun substf u =
(case Termtab.lookup pairs u of
SOME u' => u'
| NONE =>
(case u of
(Abs(a,T,t)) => Abs(a, T, substf t)
| (t$u') => substf t $ substf u'
| u => u))
in (not (Termtab.is_empty pairs)) ? substf end;
fun subst_free_if_nonempty concl_transformation =
(not (null concl_transformation)) ? Term.subst_free concl_transformation
fun add_box_symbols ctxt t ct =
let
fun add_alethe_Box_after_all_negations_conv ctxt ct =
(case Thm.term_of ct of
@{term Not} $ _ =>
Conv.try_conv (Conv.arg_conv (add_alethe_Box_after_all_negations_conv ctxt) )
| _ =>
Conv.try_conv (Conv.top_conv (K (Conv.rewr_conv @{thm SMT.alethe_Box})) ctxt)) ct
fun add_box_symbols @{term True} ct =
(case Thm.term_of ct of
@{term Not} $ _ =>
Conv.try_conv (Conv.arg_conv (add_alethe_Box_after_all_negations_conv ctxt))
| _ =>
Conv.try_conv (Conv.top_conv (K (Conv.rewr_conv @{thm SMT.alethe_Box})) ctxt)) ct
| add_box_symbols (u $ v) ct =
(Conv.fun_conv (add_box_symbols u)
then_conv Conv.arg_conv (add_box_symbols v)) ct
| add_box_symbols _ ct = Conv.all_conv ct
in
ct
|> (Thm.beta_conversion true then_conv HOLogic.Trueprop_conv (add_box_symbols (HOLogic.dest_Trueprop t)))
end
fun apply_replay_method f unchanged_prems (prems, prems_as_thms_with_context_assms) step_args
context_assignments ((prop_skeleton, concl), ctxt) tactic_args keep_proposition_structure =
let
val prems1 = unchanged_prems @ map (SMT_Replay.varify ctxt) prems
val prems2 = prems_as_thms_with_context_assms
|> (if keep_proposition_structure
then map (fn (t, thm) => Conv.fconv_rule (add_box_symbols ctxt t) thm)
else map snd)
val concl =
if keep_proposition_structure
then
(add_box_symbols ctxt prop_skeleton (Thm.cterm_of ctxt concl)
|> Thm.prop_of
|> (fn _ $ s => s))
else concl
val _ = debug_msg ctxt high (fn () => \<^print> ("Apply a replay method to solve ((prems1,prems2),concl)", ((prems1,prems2),concl)))
in (f ctxt (prems1 @ prems2) step_args context_assignments concl tactic_args) end
fun replay_thm solver method_for rewrite_rules ll_defs ctxt assumed unchanged_prems prems prems_as_thms_with_context_assms
concl_transformation global_transformation step_args context_assignments args
(Alethe_Node.Alethe_Replay_Node {id, rule, concl, prop_skeleton, ...}) =
if rule = Alethe_Proof.input_rule then
(case Symtab.lookup assumed id of
SOME (_, thm) => thm
| _ => raise Fail ("assumption " ^ @{make_string} id ^ " not found"))
else
let
val rewrite = let val thy = Proof_Context.theory_of (Simplifier.empty_simpset ctxt) in
Raw_Simplifier.rewrite_term thy rewrite_rules []
#> not (null ll_defs andalso Alethe_Proof.keep_raw_lifting rule) ? SMTLIB_Isar.unlift_term ll_defs
end
val concl_rewriter = (if Alethe_Proof.keep_app_symbols rule then
filter (curry Term.could_unify (Thm.concl_of @{thm SMT.fun_app_def}) o Thm.concl_of) rewrite_rules
else rewrite_rules)
val post = let val thy = Proof_Context.theory_of (Simplifier.empty_simpset ctxt) in
Raw_Simplifier.rewrite_term thy concl_rewriter []
#> Object_Logic.atomize_term ctxt
#> not (null ll_defs) ? SMTLIB_Isar.unlift_term ll_defs
#> SMTLIB_Isar.unskolemize_names ctxt
#> HOLogic.mk_Trueprop
end
val concl = concl
|> subst_free_if_nonempty concl_transformation
|> subst_only_free global_transformation
|> post
val _ = debug_msg ctxt high (fn () => \<^print> ("Rewritten atomized conclusion with lambda lifting definitions (ll_defs) and rewrite_rules", concl))
val args = if rule = Alethe_Proof.refl_rule orelse rule = Alethe_Proof.cong_rule orelse rule = Alethe_Proof.normalized_input_rule
then SOME (Solver_Name solver)
else args
val needs_boxes = Alethe_Proof.keep_proposition_structure rule andalso
SMT_Config.alethe_use_prop_skeleton ctxt
in
apply_replay_method (method_for rule) unchanged_prems
(prems, prems_as_thms_with_context_assms)
(map rewrite step_args)
(map rewrite context_assignments)
((prop_skeleton, concl), ctxt)
args
needs_boxes
|> Simplifier.simplify (Simplifier.add_simps (@{thm SMT.alethe_Box_def2} :: rewrite_rules)
(Simplifier.empty_simpset ctxt))
end
| replay_thm _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ = raise Fail "unreachable code to silence the compiler"
fun replay_theorem_step solver method_for rewrite_rules all_assms ll_defs assumed (inputs : thm list) (all_local_assumptions : thm list)
(step as Alethe_Node.Alethe_Replay_Node {id, rule, prems = non_skolem_prems, step_args, context_assignments,
subproof = (fixes, assms, input, subproof), concl, args, prop_skeleton, ...})
(globally_known_facts, stats, ctxt, concl_transformation, global_transformation) =
let
val _ = debug_msg ctxt low (fn () => \<^print> ("Replaying theorem step", id))
val _ = debug_msg ctxt middle (fn () => \<^print> ("(conclusion, propositional skeleton)", (concl, prop_skeleton)))
val ctxt = Variable.variant_fixes [] ctxt
|> (fn (_, ctxt) => fold Variable.declare_term [SMTLIB_Isar.unskolemize_names ctxt concl] ctxt)
val (names, sub_ctxt) = Variable.variant_fixes (map fst fixes) ctxt
||> fold Variable.declare_term (map Free fixes)
val _ = debug_cond_msg ctxt (fixes <> []) middle (fn () => \<^print> ("Obtained new variables from the subproof and added their names to a subcontext",(fixes,names)))
val export_vars = concl_transformation @
(ListPair.zip (map Free fixes, map Free (ListPair.zip (names, map snd fixes))))
val _ = debug_cond_msg ctxt (export_vars <> []) high (fn () => \<^print> ("Current mapping from variable names to the possibly new names that Isabelle chose",export_vars))
val remove_lambdas =
let val thy = Proof_Context.theory_of (Simplifier.empty_simpset ctxt) in
Raw_Simplifier.rewrite_term thy (if (Alethe_Proof.keep_raw_lifting rule) andalso not (null rewrite_rules) then tl rewrite_rules else rewrite_rules) []
#> Object_Logic.atomize_term ctxt
#> not (null ll_defs orelse Alethe_Proof.keep_raw_lifting rule) ? SMTLIB_Isar.unlift_term ll_defs
#> SMTLIB_Isar.unskolemize_names ctxt
#> HOLogic.mk_Trueprop
end
val term_rewriter2 = subst_only_free global_transformation o subst_free_if_nonempty export_vars o remove_lambdas
val term_rewriter = SMTLIB_Isar.unskolemize_names ctxt o term_rewriter2
fun is_refl thm = Thm.concl_of thm |> (fn (_ $ t) => t | _ => raise TERM ("",[])) |> HOLogic.dest_eq |> (op =) handle TERM _=> false
fun mk_thms sctxt t = (Assumption.add_assumes (map (Thm.cterm_of sctxt) t) sctxt |>> filter_out is_refl)
fun is_mapping (\<^term>‹Trueprop› $ (Const(\<^const_name>‹HOL.eq›, _) $ _ $ _ )) = true |
is_mapping _ = false
val remove_non_mappings = List.filter is_mapping
val rewritten_assms = map term_rewriter assms
val rewritten_input = map term_rewriter input
val rewritten_context_assignments = context_assignments |> remove_non_mappings |> map term_rewriter2
val rewritten_step_args = map term_rewriter step_args
val _ = debug_cond_msg ctxt (not (null step_args)) high (fn () => \<^print> ("Transformed step arguments (before,after)",(step_args,rewritten_step_args)))
val (assms_as_thm, sub_ctxt2) = mk_thms sub_ctxt rewritten_assms
val (input_as_thm, sub_ctxt2) = mk_thms sub_ctxt2 rewritten_input
val (context_assignments_as_thm, sub_ctxt2) = mk_thms sub_ctxt2 rewritten_context_assignments
val updated_local_assumptions = all_local_assumptions @ assms_as_thm @ context_assignments_as_thm
val _ = debug_cond_msg ctxt (not (null rewritten_assms)) high (fn () => \<^print> ("Transformed assumptions, i.e. top-level assumes (before,after)",(assms,assms_as_thm)))
val _ = debug_cond_msg ctxt (not (null rewritten_input)) high (fn () => \<^print> ("Transformed input, i.e. assumes in subproofs (before,after)",(input,input_as_thm)))
val _ = debug_cond_msg ctxt (not (null rewritten_context_assignments)) high (fn () => \<^print> ("Transformed context assignments (before,after)",(context_assignments,context_assignments_as_thm)))
val _ = debug_cond_msg ctxt (not (null updated_local_assumptions)) low (fn () => \<^print> ("All assumptions holding after the current step", updated_local_assumptions))
val _ = debug_cond_msg ctxt (not (null subproof)) low (fn () => \<^print> ("Interrupting the replay of the current step " ^ id ^ " to replay its subproof"))
val replay = replay_theorem_step solver method_for rewrite_rules all_assms ll_defs assumed (input_as_thm @ inputs) updated_local_assumptions
val (locally_known_facts, stats, _, _, sub_global_rew) =
fold replay subproof (globally_known_facts, stats, sub_ctxt2, export_vars, global_transformation)
val _ = debug_cond_msg ctxt (not (null subproof)) high (fn () => \<^print> ("Filled table with mapping from names (id or for skolems var_def) to " ^
"theorems with all steps the current step can access",Symtab.keys locally_known_facts ))
val _ = debug_cond_msg ctxt (not (null subproof)) low (fn () => \<^print> ("Finished processing the subproof, returning the original step",id))
val export_thm = singleton (Proof_Context.export sub_ctxt2 ctxt)
val subst_transform = (Raw_Simplifier.rewrite_term (Proof_Context.theory_of (Simplifier.empty_simpset ctxt)) ((if (Alethe_Proof.keep_raw_lifting rule) andalso not (null rewrite_rules) then tl rewrite_rules else rewrite_rules)) []
o (not (null ll_defs) ? SMTLIB_Isar.unlift_term ll_defs) o subst_free_if_nonempty concl_transformation o subst_only_free global_transformation)
val id_to_thm = (Symtab.lookup (if (null subproof) then globally_known_facts else locally_known_facts))
val prems_skolem_def =
(case args of
SOME (Alethe_Node.Sko_Def_Prems (a, b)) => a @ b
| _ => [])
val prems_as_thms_with_context_assms =
non_skolem_prems
|> map_filter id_to_thm
|> map (apsnd export_thm)
val skolem_rule_prems_as_thms_with_context_assms =
(if Alethe_Proof.is_skolemization rule
then prems_skolem_def |> map_filter (Symtab.lookup globally_known_facts)
else [])
val step_args = map subst_transform step_args
val args =
(case args of
SOME (Alethe_Node.Insts tab) => SOME (Alethe_Node.Insts (Symtab.map (K subst_transform) tab))
| _ => args)
val context_assignments = map subst_transform context_assignments
val _ = debug_cond_msg ctxt (length non_skolem_prems <> length prems_as_thms_with_context_assms) low (fn () =>
\<^print> ("Warning, there were premises that are not accessible to the current step (i.e., that are not in the context). This should not happen. These were ignored."))
val _ = debug_cond_msg ctxt (not (null non_skolem_prems)) middle (fn () =>
\<^print> ("Export premises that are not skolem definitions, to the current context." ^
"This will automatically add context assertions and assumes to the goal.",(non_skolem_prems,prems_as_thms_with_context_assms)))
val _ = debug_cond_msg ctxt (not (null step_args)) middle (fn () => \<^print> ("Processed step_args",step_args))
val _ = debug_cond_msg ctxt (not (null context_assignments)) middle (fn () => \<^print> ("Processed context_assignments", context_assignments))
val missing_assumptions =
if SMT_Config.alethe_no_provided_assms ctxt andalso
(rule = Alethe_Proof.local_input_rule orelse rule = Alethe_Proof.normalized_input_rule orelse rule = Alethe_Proof.input_rule)
then all_assms
else []
val all_local_assumptions =
if Alethe_Replay_Methods.requires_subproof_assms non_skolem_prems rule then updated_local_assumptions else []
val local_inputs =
if Alethe_Replay_Methods.requires_local_input non_skolem_prems rule then input_as_thm @ inputs else []
val _ = debug_cond_msg ctxt (not (null missing_assumptions)) low (fn () => \<^print> ("Assumptions could not be mapped to the current input rule by name" ^
"(possibly because you are checking an external proof), so all assumptions were added",missing_assumptions))
val _ = debug_cond_msg ctxt (not (null all_local_assumptions)) middle (fn () => \<^print> ("Added mapping from context_assignment as premises to steps (refl,sko_forall,sko_ex,cong)",all_local_assumptions))
val _ = debug_cond_msg ctxt (not (null local_inputs)) middle (fn () => \<^print> ("Added the assumptions of the current subproof rule as premises",local_inputs))
val _ = debug_msg ctxt low (fn () => \<^print> ("Calling reconstruction method for rule",id))
val replay = (Timing.timing (replay_thm solver method_for rewrite_rules ll_defs
ctxt assumed [] (missing_assumptions @ all_local_assumptions @ local_inputs)
(prems_as_thms_with_context_assms @ skolem_rule_prems_as_thms_with_context_assms) concl_transformation
global_transformation step_args context_assignments args))
val ({elapsed, ...}, thm) =
SMT_Config.with_time_limit ctxt (rule ^ "," ^ id) SMT_Config.reconstruction_step_timeout replay step
handle ERROR exn => Exn.reraise (ERROR (" in step " ^ id ^ " " ^ exn))
val _ = debug_msg ctxt low (fn () => \<^print> ("Successfully checked step", id))
val name =
(case rule of
"rare_rewrite" => "rare_rewrite" ^ "_" ^ HOLogic.dest_string (hd step_args)
| _ => rule)
val stats' = Symtab.cons_list (name, Time.toNanoseconds elapsed) stats
val globally_known_facts = Symtab.update (id, (prop_skeleton, thm)) globally_known_facts
val _ = debug_msg ctxt low (fn () => \<^print> ("Add resulting theorem to globally known facts", (id,(prop_skeleton,thm))))
in (globally_known_facts, stats', ctxt, concl_transformation, sub_global_rew) end
| replay_theorem_step _ _ _ _ _ _ _ _ _ _ = raise Fail "unreachable code to silence the compiler"
fun replay_definition_step rewrite_rules ll_defs
(Alethe_Node.Alethe_Definition_Node {id, skolem_name, skolem_term, ...}) state =
let
val (proofs, stats, ctxt, concl_transformation, global_transformation) = state
val global_transformer = subst_only_free global_transformation
val rewrite = let val thy = Proof_Context.theory_of ctxt in
Raw_Simplifier.rewrite_term thy rewrite_rules []
#> not (null ll_defs) ? SMTLIB_Isar.unlift_term ll_defs
end
val start0 = Timing.start ()
val declaration = (rewrite o global_transformer) skolem_term
val (name, ctxt) = yield_singleton Variable.variant_fixes skolem_name ctxt
||> Variable.declare_term (Free (skolem_name, fastype_of declaration))
val old_names = Free (skolem_name, fastype_of declaration)
val new_names = Free (name, fastype_of declaration)
fun update_mapping (a, b) tab =
if a <> b andalso Termtab.lookup tab a = NONE
then Termtab.update_new (a, b) tab else tab
val global_transformation = global_transformation
|> update_mapping (old_names, new_names)
val global_transformer = subst_only_free global_transformation
val generate_definition =
(fn (name, term) => (HOLogic.mk_Trueprop
(Const(\<^const_name>‹HOL.eq›, fastype_of term --> fastype_of term --> @{typ bool}) $
Free (name, fastype_of term) $ term)))
#> global_transformer
#> Thm.cterm_of ctxt
val decls = generate_definition (skolem_name, declaration)
val (def, ctxt) = yield_singleton Assumption.add_assumes decls ctxt
val proofs = Symtab.update (id, (declaration, @{thm sym} OF [def])) proofs
val total = Time.toNanoseconds (#elapsed (Timing.result start0))
val stats = Symtab.cons_list ("choice", total) stats
in (proofs, stats, ctxt, concl_transformation, global_transformation) end
| replay_definition_step _ _ _ _ = raise Fail "unreachable code to silence the compiler"
fun prove_ll_def_from_assms assms ll_defs rewrite_rules stats ctxt term =
let
val rewrite = let val thy = Proof_Context.theory_of (Simplifier.empty_simpset ctxt) in
Raw_Simplifier.rewrite_term thy rewrite_rules []
#> not (null ll_defs) ? SMTLIB_Isar.unlift_term ll_defs
end
val replay = Timing.timing (SMT_Replay_Methods.prove ctxt (rewrite term))
val replay_ll_assumption_tac =
Method.insert_tac ctxt assms THEN' K (unfold_tac ctxt @{thms SMT.alethe_id_def})
THEN' (assume_tac ctxt
ORELSE' (Alethe_Replay_Methods.REPEAT' (resolve_tac ctxt @{thms allI})
THEN' Alethe_Replay_Methods.REPEAT' (resolve_tac ctxt @{thms refl})))
val ({elapsed, ...}, thm) =
SMT_Config.with_time_limit ctxt "assumption" SMT_Config.reconstruction_step_timeout replay
(fn _ => replay_ll_assumption_tac)
val stats' = Symtab.cons_list (Alethe_Proof.input_rule, Time.toNanoseconds elapsed) stats
in
(thm, stats')
end
fun replay_step solver method_for rewrite_rules all_assms ll_defs assumed inputs all_local_assumptions
(step as Alethe_Node.Alethe_Replay_Node {...}) state =
replay_theorem_step solver method_for rewrite_rules all_assms ll_defs assumed inputs all_local_assumptions step state
| replay_step _ _ rewrite_rules _ ll_defs _ _ _
(step as Alethe_Node.Alethe_Definition_Node {...}) state =
replay_definition_step rewrite_rules ll_defs step state
fun replay solver method_for outer_ctxt
({ctxt = ctxt, typs, terms, rewrite_rules, assms, ll_defs, ...} : SMT_Translate.replay_data)
raw_proof_steps =
let
val _ = if solver = "cvc5_prover" andalso not (SMT_Config.use_alethe_proof_from_cvc ctxt)
then (raise SMT_Failure.SMT (SMT_Failure.Other_Failure ("reconstruction with CVC is experimental.\n" ^
"You must activate it with [[smt_cvc_alethe = true]] and use cvc5 (not included as component) .")))
else ()
val _ = debug_msg ctxt low (fn () => \<^print> ("Replaying proof"))
val rewrite_rules =
filter_out (fn thm => Term.could_unify (Thm.prop_of @{thm alethe_eq_true_simplify},
Thm.prop_of thm))
rewrite_rules
val num_ll_defs = length ll_defs
val index_of_id = Integer.add (~ num_ll_defs)
val start0 = Timing.start ()
val (parsed_proof_steps, ctxt_after_parsing) =
Alethe_Proof.parse_replay typs terms raw_proof_steps ctxt
val parsing_time = Time.toNanoseconds (#elapsed (Timing.result start0))
val _ = debug_msg ctxt middle (fn () => \<^print> ("Finished parsing proof steps"))
val start = Timing.start ()
fun add_used_asserts_in_step (Alethe_Node.Alethe_Replay_Node {prems,
subproof = (_, _, _, subproof), ...}) =
union (op =) (map_filter (try (snd o SMTLIB_Interface.role_and_index_of_assert_name)) prems @
maps (fn x => add_used_asserts_in_step x []) subproof) |
add_used_asserts_in_step (Alethe_Node.Alethe_Definition_Node _) = (fn x => x)
val used_assert_ids = fold add_used_asserts_in_step parsed_proof_steps []
val real_assms =
map_filter (fn id => let val i = index_of_id id in if i >= 0 andalso i < length assms then
let val concl = Thm.prop_of (snd (nth assms i))
|> Raw_Simplifier.rewrite_term (Proof_Context.theory_of
(Simplifier.add_simps rewrite_rules (Simplifier.empty_simpset ctxt))) rewrite_rules []
in SOME (SMTLIB_Interface.assert_name_of_role_and_index SMT_Util.Axiom id,
Alethe_Proof.input_rule, concl, @{term "Trueprop True"}) end
else NONE end) used_assert_ids
val _ = debug_msg ctxt high (fn () => \<^print> ("These are genuine assumptions of the proof",real_assms))
fun normalize_tac ctxt = let val thy = Proof_Context.theory_of (Simplifier.empty_simpset ctxt) in
Raw_Simplifier.rewrite_term thy rewrite_rules [] end
val used_lldefs =
map_filter (fn id => let val i = index_of_id id in if i < 0 andalso not (ll_defs = [])
then SOME (id, normalize_tac ctxt (nth ll_defs id)) else NONE end)
used_assert_ids
val _ = debug_msg ctxt high (fn () => \<^print> ("These assumptions were lambda lifting definitions that were actually used: ",used_lldefs))
val add_assert = SMT_Replay.add_asserted Symtab.update Symtab.empty (fn x => x)
(fn r => r = Alethe_Proof.input_rule)
val ((_, _), (ctxt_with_asserts, assumed)) =
add_assert outer_ctxt rewrite_rules (map (apfst fst) assms)
real_assms ctxt_after_parsing
val ctxt_with_asserts = ctxt_with_asserts
|> put_simpset (SMT_Replay.make_simpset ctxt_with_asserts [])
|> Config.put SAT.solver (Config.get ctxt_after_parsing SMT_Config.sat_solver)
val (assumed, stats) = fold (fn (ll_def_id, ll_def_term) => fn (assumed, stats) =>
let
val (thm, stats) = prove_ll_def_from_assms (map snd assms) ll_defs rewrite_rules stats ctxt ll_def_term
val name = SMTLIB_Interface.assert_name_of_role_and_index SMT_Util.Axiom ll_def_id
in
(Symtab.update (name, (@{term "Trueprop True"}, thm)) assumed, stats)
end)
used_lldefs (assumed, Symtab.cons_list ("parsing", parsing_time) Symtab.empty)
val _ = debug_msg ctxt middle (fn () => \<^print> ("Finished replaying the assumptions"))
val len = Alethe_Proof.number_of_steps parsed_proof_steps
fun steps_with_depth _ [] = []
| steps_with_depth i (p :: ps) =
let val i' = i + Alethe_Proof.number_of_steps [p] in (i', p) :: steps_with_depth i' ps end
val actual_steps = steps_with_depth 0 parsed_proof_steps
val print_runtime_statistics = SMT_Replay.intermediate_statistics ctxt_with_asserts start len
fun blockwise f (i, x) (next, y) =
(if i > next then print_runtime_statistics i else ();
(if i > next then i + 10 else next, f x y))
val global_transformation : term Termtab.table = Termtab.empty
val (_, (proofs, stats, ctxt5, _, _)) =
fold (blockwise (replay_step solver method_for rewrite_rules (map snd assms) ll_defs assumed [] [])) actual_steps
(1, (assumed, stats, ctxt_with_asserts, [], global_transformation))
val id =
(case split_last actual_steps of
(_, (_, Alethe_Node.Alethe_Replay_Node {id, ...})) => id
| _ => raise Fail "last proof step is not a replay node")
val thm_with_defs =
Symtab.lookup proofs id |> the |> snd
|> singleton (Proof_Context.export ctxt5 outer_ctxt)
val total = Time.toMilliseconds (#elapsed (Timing.result start))
val _ = debug_msg ctxt middle (fn () => \<^print> ("Last step (id " ^ id ^ ")", thm_with_defs))
val _ = if solver = "cvc5_prover" then
SMT_Replay.spying (SMT_Config.spy_cvc ctxt) ctxt
(fn () => SMT_Replay.print_stats (Symtab.dest stats)) "$ISABELLE_SMT_CVC_SPY"
else
SMT_Replay.spying (SMT_Config.spy_verit ctxt) ctxt
(fn () => SMT_Replay.print_stats (Symtab.dest stats)) "$ISABELLE_SMT_VERIT_SPY"
val _ = print_runtime_statistics len
val _ = SMT_Config.statistics_msg ctxt5
(Pretty.string_of o SMT_Replay.pretty_statistics "cvc" total) stats
in
if SMT_Config.check_smt_is_slicing ctxt
then thm_with_defs
else CVC5_Replay_Methods.discharge ctxt [thm_with_defs] @{term False}
end
end