have each ATP filter out dangerous facts for themselves, based on their type system
1 (* Title: HOL/Tools/Sledgehammer/sledgehammer_run.ML
2 Author: Fabian Immler, TU Muenchen
4 Author: Jasmin Blanchette, TU Muenchen
9 signature SLEDGEHAMMER_RUN =
11 type relevance_override = Sledgehammer_Filter.relevance_override
12 type minimize_command = Sledgehammer_ATP_Reconstruct.minimize_command
13 type params = Sledgehammer_Provers.params
14 type prover = Sledgehammer_Provers.prover
16 val auto_minimize_min_facts : int Unsynchronized.ref
17 val get_minimizing_prover : Proof.context -> bool -> string -> prover
18 val run_sledgehammer :
19 params -> bool -> int -> relevance_override -> (string -> minimize_command)
20 -> Proof.state -> bool * Proof.state
23 structure Sledgehammer_Run : SLEDGEHAMMER_RUN =
26 open Sledgehammer_Util
27 open Sledgehammer_Filter
28 open Sledgehammer_ATP_Translate
29 open Sledgehammer_Provers
30 open Sledgehammer_Minimize
32 fun prover_description ctxt ({verbose, blocking, ...} : params) name num_facts i
36 " with " ^ string_of_int num_facts ^ " fact" ^ plural_s num_facts
39 " on " ^ (if n = 1 then "goal" else "subgoal " ^ string_of_int i) ^
43 ":\n" ^ Syntax.string_of_term ctxt (Thm.term_of (Thm.cprem_of goal i)))
45 val auto_minimize_min_facts = Unsynchronized.ref (!binary_min_facts)
47 fun get_minimizing_prover ctxt auto name
48 (params as {debug, verbose, explicit_apply, ...}) minimize_command
49 (problem as {state, subgoal, subgoal_count, facts, ...}) =
50 get_prover ctxt auto name params minimize_command problem
51 |> (fn result as {outcome, used_facts, run_time_in_msecs, message} =>
52 if is_some outcome then
56 val (used_facts, message) =
57 if length used_facts >= !auto_minimize_min_facts then
58 minimize_facts name params (SOME explicit_apply) (not verbose)
59 subgoal subgoal_count state
60 (filter_used_facts used_facts
61 (map (apsnd single o untranslated_fact) facts))
62 |>> Option.map (map fst)
64 (SOME used_facts, message)
68 (if debug andalso not (null used_facts) then
69 facts ~~ (0 upto length facts - 1)
70 |> map (fn (fact, j) =>
71 fact |> untranslated_fact |> apsnd (K j))
72 |> filter_used_facts used_facts
73 |> map (fn ((name, _), j) => name ^ "@" ^ string_of_int j)
75 |> enclose ("Fact" ^ plural_s (length facts) ^ " in " ^
76 quote name ^ " proof (of " ^
77 string_of_int (length facts) ^ "): ") "."
78 |> Output.urgent_message
81 {outcome = NONE, used_facts = used_facts,
82 run_time_in_msecs = run_time_in_msecs, message = message})
86 fun launch_prover (params as {debug, blocking, max_relevant, slicing, timeout,
88 auto minimize_command only
89 {state, goal, subgoal, subgoal_count, facts, smt_filter} name =
91 val ctxt = Proof.context_of state
92 val birth_time = Time.now ()
93 val death_time = Time.+ (birth_time, timeout)
96 |> the_default (default_max_relevant_for_prover ctxt slicing name)
97 val num_facts = length facts |> not only ? Integer.min max_relevant
99 prover_description ctxt params name num_facts subgoal subgoal_count goal
101 {state = state, goal = goal, subgoal = subgoal,
102 subgoal_count = subgoal_count, facts = facts |> take num_facts,
103 smt_filter = smt_filter}
106 |> get_minimizing_prover ctxt auto name params (minimize_command name)
107 |> (fn {outcome, message, ...} =>
108 (if is_some outcome then "none" else "some" (* sic *), message))
111 val (outcome_code, message) =
116 handle ERROR message => ("unknown", "Error: " ^ message ^ "\n")
118 if Exn.is_interrupt exn then
121 ("unknown", "Internal error:\n" ^
122 ML_Compiler.exn_message exn ^ "\n"))
124 (* The "expect" argument is deliberately ignored if the prover is
125 missing so that the "Metis_Examples" can be processed on any
127 if expect = "" orelse outcome_code = expect orelse
128 not (is_prover_installed ctxt name) then
130 else if blocking then
131 error ("Unexpected outcome: " ^ quote outcome_code ^ ".")
133 warning ("Unexpected outcome: " ^ quote outcome_code ^ ".");
134 in (outcome_code = "some", message) end
137 let val (success, message) = TimeLimit.timeLimit timeout go () in
138 (success, state |> success ? Proof.goal_message (fn () =>
139 Pretty.chunks [Pretty.str "",
140 Pretty.mark Markup.hilite (Pretty.str message)]))
142 else if blocking then
143 let val (success, message) = TimeLimit.timeLimit timeout go () in
144 List.app Output.urgent_message
145 (Async_Manager.break_into_chunks [desc ^ "\n" ^ message]);
149 (Async_Manager.launch das_Tool birth_time death_time desc (snd o go);
153 fun class_of_smt_solver ctxt name =
154 ctxt |> select_smt_solver name
155 |> SMT_Config.solver_class_of |> SMT_Utils.string_of_class
157 (* Makes backtraces more transparent and might be more efficient as well. *)
158 fun smart_par_list_map _ [] = []
159 | smart_par_list_map f [x] = [f x]
160 | smart_par_list_map f xs = Par_List.map f xs
162 fun dest_SMT_Weighted_Fact (SMT_Weighted_Fact p) = p
163 | dest_SMT_Weighted_Fact _ = raise Fail "dest_SMT_Weighted_Fact"
165 val auto_max_relevant_divisor = 2 (* FUDGE *)
167 fun run_sledgehammer (params as {debug, blocking, provers, type_sys,
168 relevance_thresholds, max_relevant, slicing,
170 auto i (relevance_override as {only, ...}) minimize_command state =
172 error "No prover is set."
173 else case subgoal_count state of
174 0 => (Output.urgent_message "No subgoal!"; (false, state))
177 val _ = Proof.assert_backward state
178 val print = if auto then K () else Output.urgent_message
180 state |> Proof.map_context (Config.put SMT_Config.verbose debug)
181 val ctxt = Proof.context_of state
182 val thy = Proof_Context.theory_of ctxt
183 val {facts = chained_ths, goal, ...} = Proof.goal state
184 val (_, hyp_ts, concl_t) = strip_subgoal goal i
185 val _ = () |> not blocking ? kill_provers
186 val _ = case find_first (not o is_prover_supported ctxt) provers of
187 SOME name => error ("No such prover: " ^ name ^ ".")
189 val _ = print "Sledgehammering..."
190 val (smts, atps) = provers |> List.partition (is_smt_prover ctxt)
191 fun launch_provers state get_facts translate maybe_smt_filter provers =
193 val facts = get_facts ()
194 val num_facts = length facts
195 val facts = facts ~~ (0 upto num_facts - 1)
196 |> map (translate num_facts)
198 {state = state, goal = goal, subgoal = i, subgoal_count = n,
200 smt_filter = maybe_smt_filter
201 (fn () => map_filter (try dest_SMT_Weighted_Fact) facts) i}
202 val launch = launch_prover params auto minimize_command only
205 fold (fn prover => fn (true, state) => (true, state)
206 | (false, _) => launch problem prover)
207 provers (false, state)
210 |> (if blocking then smart_par_list_map else map) (launch problem)
211 |> exists fst |> rpair state
213 fun get_facts label relevance_fudge provers =
215 val max_max_relevant =
219 0 |> fold (Integer.max
220 o default_max_relevant_for_prover ctxt slicing)
222 |> auto ? (fn n => n div auto_max_relevant_divisor)
223 val is_built_in_const =
224 is_built_in_const_for_prover ctxt (hd provers)
226 relevant_facts ctxt relevance_thresholds max_max_relevant
227 is_built_in_const relevance_fudge relevance_override
228 chained_ths hyp_ts concl_t
231 label ^ plural_s (length provers) ^ ": " ^
233 "Found no relevant facts."
235 "Including (up to) " ^ string_of_int (length facts) ^
236 " relevant fact" ^ plural_s (length facts) ^ ":\n" ^
237 (facts |> map (fst o fst) |> space_implode " ") ^ ".")
242 fun launch_atps accum =
246 launch_provers state (get_facts "ATP" atp_relevance_fudge o K atps)
247 (K (Untranslated_Fact o fst)) (K (K NONE)) atps
248 fun launch_smts accum =
253 val facts = get_facts "SMT solver" smt_relevance_fudge smts
254 val weight = SMT_Weighted_Fact oo weight_smt_fact thy
255 fun smt_filter facts =
256 (if debug then curry (op o) SOME
257 else TimeLimit.timeLimit timeout o try)
258 (SMT_Solver.smt_filter_preprocess state (facts ()))
260 smts |> map (`(class_of_smt_solver ctxt))
261 |> AList.group (op =)
262 |> map (launch_provers state (K facts) weight smt_filter o snd)
263 |> exists fst |> rpair state
265 fun launch_atps_and_smt_solvers () =
266 [launch_atps, launch_smts]
267 |> smart_par_list_map (fn f => f (false, state) |> K ())
268 handle ERROR msg => (print ("Error: " ^ msg); error msg)
271 |> (if blocking then launch_atps #> not auto ? launch_smts
272 else (fn p => Future.fork (tap launch_atps_and_smt_solvers) |> K p))
273 handle TimeLimit.TimeOut =>
274 (print "Sledgehammer ran out of time."; (false, state))