4 Sledgehammer's machine-learning-based relevance filter (MaSh). |
4 Sledgehammer's machine-learning-based relevance filter (MaSh). |
5 *) |
5 *) |
6 |
6 |
7 signature SLEDGEHAMMER_FILTER_MASH = |
7 signature SLEDGEHAMMER_FILTER_MASH = |
8 sig |
8 sig |
|
9 type status = ATP_Problem_Generate.status |
|
10 type stature = ATP_Problem_Generate.stature |
|
11 type params = Sledgehammer_Provers.params |
|
12 type prover_result = Sledgehammer_Provers.prover_result |
|
13 |
|
14 val fact_name_of : string -> string |
|
15 val all_non_tautological_facts_of : |
|
16 theory -> (((unit -> string) * stature) * thm) list |
|
17 val theory_ord : theory * theory -> order |
|
18 val thm_ord : thm * thm -> order |
|
19 val thms_by_thy : ('a * thm) list -> (string * thm list) list |
|
20 val has_thy : theory -> thm -> bool |
|
21 val parent_thms : (string * thm list) list -> theory -> string list |
|
22 val features_of : theory -> status * thm -> string list |
|
23 val isabelle_dependencies_of : string list -> thm -> string list |
|
24 val goal_of_thm : theory -> thm -> thm |
|
25 val iter_facts : |
|
26 Proof.context -> params -> int -> thm |
|
27 -> (((unit -> string) * stature) * thm) list |
|
28 -> ((string * stature) * thm) list |
|
29 val run_prover : |
|
30 Proof.context -> params -> ((string * stature) * thm) list -> thm |
|
31 -> prover_result |
|
32 val generate_accessibility : theory -> bool -> string -> unit |
|
33 val generate_features : theory -> bool -> string -> unit |
|
34 val generate_isa_dependencies : theory -> bool -> string -> unit |
|
35 val generate_atp_dependencies : |
|
36 Proof.context -> params -> theory -> bool -> string -> unit |
|
37 |
9 val reset : unit -> unit |
38 val reset : unit -> unit |
10 val can_suggest : unit -> bool |
39 val can_suggest : unit -> bool |
11 val can_learn_thy : theory -> bool |
40 val can_learn_thy : theory -> bool |
12 val learn_thy : theory -> real -> unit |
41 val learn_thy : theory -> real -> unit |
13 val learn_proof : theory -> term -> thm list -> unit |
42 val learn_proof : theory -> term -> thm list -> unit |
14 end; |
43 end; |
15 |
44 |
16 structure Sledgehammer_Filter_MaSh : SLEDGEHAMMER_FILTER_MASH = |
45 structure Sledgehammer_Filter_MaSh : SLEDGEHAMMER_FILTER_MASH = |
17 struct |
46 struct |
18 |
47 |
|
48 open ATP_Util |
|
49 open ATP_Problem_Generate |
|
50 open Sledgehammer_Util |
|
51 open Sledgehammer_Fact |
|
52 open Sledgehammer_Filter_Iter |
|
53 open Sledgehammer_Provers |
|
54 |
|
55 |
|
56 (*** Low-level communication with MaSh ***) |
|
57 |
19 fun mash_reset () = |
58 fun mash_reset () = |
20 tracing "MaSh RESET" |
59 tracing "MaSh RESET" |
21 |
60 |
22 fun mash_add fact (access, feats, deps) = |
61 fun mash_add fact (access, feats, deps) = |
23 tracing ("MaSh ADD " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^ |
62 tracing ("MaSh ADD " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^ |
28 |
67 |
29 fun mash_suggest fact (access, feats) = |
68 fun mash_suggest fact (access, feats) = |
30 tracing ("MaSh SUGGEST " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^ |
69 tracing ("MaSh SUGGEST " ^ fact ^ ": " ^ space_implode " " access ^ "; " ^ |
31 space_implode " " feats) |
70 space_implode " " feats) |
32 |
71 |
|
72 |
|
73 (*** Isabelle helpers ***) |
|
74 |
|
75 val fact_name_of = prefix fact_prefix o ascii_of |
|
76 |
|
77 fun escape_meta_char c = |
|
78 if Char.isAlphaNum c orelse c = #"_" orelse c = #"." orelse c = #"(" orelse |
|
79 c = #")" orelse c = #"," then |
|
80 String.str c |
|
81 else |
|
82 (* fixed width, in case more digits follow *) |
|
83 "\\" ^ stringN_of_int 3 (Char.ord c) |
|
84 |
|
85 val escape_meta = String.translate escape_meta_char |
|
86 |
|
87 val thy_prefix = "y_" |
|
88 |
|
89 val fact_name_of = escape_meta |
|
90 val thy_name_of = prefix thy_prefix o escape_meta |
|
91 val const_name_of = prefix const_prefix o escape_meta |
|
92 val type_name_of = prefix type_const_prefix o escape_meta |
|
93 val class_name_of = prefix class_prefix o escape_meta |
|
94 |
|
95 val thy_name_of_thm = theory_of_thm #> Context.theory_name |
|
96 |
|
97 local |
|
98 |
|
99 fun has_bool @{typ bool} = true |
|
100 | has_bool (Type (_, Ts)) = exists has_bool Ts |
|
101 | has_bool _ = false |
|
102 |
|
103 fun has_fun (Type (@{type_name fun}, _)) = true |
|
104 | has_fun (Type (_, Ts)) = exists has_fun Ts |
|
105 | has_fun _ = false |
|
106 |
|
107 val is_conn = member (op =) |
|
108 [@{const_name Trueprop}, @{const_name HOL.conj}, @{const_name HOL.disj}, |
|
109 @{const_name HOL.implies}, @{const_name Not}, |
|
110 @{const_name All}, @{const_name Ex}, @{const_name Ball}, @{const_name Bex}, |
|
111 @{const_name HOL.eq}] |
|
112 |
|
113 val has_bool_arg_const = |
|
114 exists_Const (fn (c, T) => |
|
115 not (is_conn c) andalso exists has_bool (binder_types T)) |
|
116 |
|
117 fun higher_inst_const thy (c, T) = |
|
118 case binder_types T of |
|
119 [] => false |
|
120 | Ts => length (binder_types (Sign.the_const_type thy c)) <> length Ts |
|
121 |
|
122 val binders = [@{const_name All}, @{const_name Ex}] |
|
123 |
|
124 in |
|
125 |
|
126 fun is_fo_term thy t = |
|
127 let |
|
128 val t = |
|
129 t |> Envir.beta_eta_contract |
|
130 |> transform_elim_prop |
|
131 |> Object_Logic.atomize_term thy |
|
132 in |
|
133 Term.is_first_order binders t andalso |
|
134 not (exists_subterm (fn Var (_, T) => has_bool T orelse has_fun T |
|
135 | _ => false) t orelse |
|
136 has_bool_arg_const t orelse exists_Const (higher_inst_const thy) t) |
|
137 end |
|
138 |
|
139 end |
|
140 |
|
141 fun interesting_terms_types_and_classes term_max_depth type_max_depth t = |
|
142 let |
|
143 val bad_types = [@{type_name prop}, @{type_name bool}, @{type_name fun}] |
|
144 val bad_consts = atp_widely_irrelevant_consts |
|
145 fun do_add_type (Type (s, Ts)) = |
|
146 (not (member (op =) bad_types s) ? insert (op =) (type_name_of s)) |
|
147 #> fold do_add_type Ts |
|
148 | do_add_type (TFree (_, S)) = union (op =) (map class_name_of S) |
|
149 | do_add_type (TVar (_, S)) = union (op =) (map class_name_of S) |
|
150 fun add_type T = type_max_depth >= 0 ? do_add_type T |
|
151 fun mk_app s args = |
|
152 if member (op <>) args "" then s ^ "(" ^ space_implode "," args ^ ")" |
|
153 else s |
|
154 fun patternify ~1 _ = "" |
|
155 | patternify depth t = |
|
156 case strip_comb t of |
|
157 (Const (s, _), args) => |
|
158 mk_app (const_name_of s) (map (patternify (depth - 1)) args) |
|
159 | _ => "" |
|
160 fun add_term_patterns ~1 _ = I |
|
161 | add_term_patterns depth t = |
|
162 insert (op =) (patternify depth t) |
|
163 #> add_term_patterns (depth - 1) t |
|
164 val add_term = add_term_patterns term_max_depth |
|
165 fun add_patterns t = |
|
166 let val (head, args) = strip_comb t in |
|
167 (case head of |
|
168 Const (s, T) => |
|
169 not (member (op =) bad_consts s) ? (add_term t #> add_type T) |
|
170 | Free (_, T) => add_type T |
|
171 | Var (_, T) => add_type T |
|
172 | Abs (_, T, body) => add_type T #> add_patterns body |
|
173 | _ => I) |
|
174 #> fold add_patterns args |
|
175 end |
|
176 in [] |> add_patterns t |> sort string_ord end |
|
177 |
|
178 fun is_likely_tautology th = |
|
179 null (interesting_terms_types_and_classes 0 ~1 (prop_of th)) andalso |
|
180 not (Thm.eq_thm_prop (@{thm ext}, th)) |
|
181 |
|
182 fun is_too_meta thy th = |
|
183 fastype_of (Object_Logic.atomize_term thy (prop_of th)) <> @{typ bool} |
|
184 |
|
185 fun all_non_tautological_facts_of thy = |
|
186 all_facts_of thy |
|
187 |> filter_out ((is_likely_tautology orf is_too_meta thy) o snd) |
|
188 |
|
189 fun theory_ord p = |
|
190 if Theory.eq_thy p then EQUAL |
|
191 else if Theory.subthy p then LESS |
|
192 else if Theory.subthy (swap p) then GREATER |
|
193 else EQUAL |
|
194 |
|
195 val thm_ord = theory_ord o pairself theory_of_thm |
|
196 |
|
197 fun thms_by_thy ths = |
|
198 ths |> map (snd #> `thy_name_of_thm) |
|
199 |> AList.group (op =) |
|
200 |> sort (int_ord o pairself (length o Theory.ancestors_of o theory_of_thm |
|
201 o hd o snd)) |
|
202 |> map (apsnd (sort thm_ord)) |
|
203 |
|
204 fun has_thy thy th = (Context.theory_name thy = thy_name_of_thm th) |
|
205 |
|
206 fun parent_thms thy_ths thy = |
|
207 Theory.parents_of thy |
|
208 |> map Context.theory_name |
|
209 |> map_filter (AList.lookup (op =) thy_ths) |
|
210 |> map List.last |
|
211 |> map (fact_name_of o Thm.get_name_hint) |
|
212 |
|
213 fun is_exists (s, _) = (s = @{const_name Ex} orelse s = @{const_name Ex1}) |
|
214 |
|
215 val max_depth = 1 |
|
216 |
|
217 (* TODO: Generate type classes for types? *) |
|
218 fun features_of thy (status, th) = |
|
219 let val t = Thm.prop_of th in |
|
220 thy_name_of (thy_name_of_thm th) :: |
|
221 interesting_terms_types_and_classes max_depth max_depth t |
|
222 |> not (has_no_lambdas t) ? cons "lambdas" |
|
223 |> exists_Const is_exists t ? cons "skolems" |
|
224 |> not (is_fo_term thy t) ? cons "ho" |
|
225 |> (case status of |
|
226 General => I |
|
227 | Induction => cons "induction" |
|
228 | Intro => cons "intro" |
|
229 | Inductive => cons "inductive" |
|
230 | Elim => cons "elim" |
|
231 | Simp => cons "simp" |
|
232 | Def => cons "def") |
|
233 end |
|
234 |
|
235 fun isabelle_dependencies_of all_facts = |
|
236 thms_in_proof (SOME all_facts) |
|
237 #> map fact_name_of #> sort string_ord |
|
238 |
|
239 val freezeT = Type.legacy_freeze_type |
|
240 |
|
241 fun freeze (t $ u) = freeze t $ freeze u |
|
242 | freeze (Abs (s, T, t)) = Abs (s, freezeT T, freeze t) |
|
243 | freeze (Var ((s, _), T)) = Free (s, freezeT T) |
|
244 | freeze (Const (s, T)) = Const (s, freezeT T) |
|
245 | freeze (Free (s, T)) = Free (s, freezeT T) |
|
246 | freeze t = t |
|
247 |
|
248 fun goal_of_thm thy = prop_of #> freeze #> cterm_of thy #> Goal.init |
|
249 |
|
250 fun iter_facts ctxt ({provers, relevance_thresholds, ...} : params) max_relevant |
|
251 goal = |
|
252 let |
|
253 val prover_name = hd provers |
|
254 val (_, hyp_ts, concl_t) = ATP_Util.strip_subgoal ctxt goal 1 |
|
255 val is_built_in_const = |
|
256 Sledgehammer_Provers.is_built_in_const_for_prover ctxt prover_name |
|
257 val relevance_fudge = |
|
258 Sledgehammer_Provers.relevance_fudge_for_prover ctxt prover_name |
|
259 val relevance_override = {add = [], del = [], only = false} |
|
260 in |
|
261 iterative_relevant_facts ctxt relevance_thresholds max_relevant |
|
262 is_built_in_const relevance_fudge |
|
263 relevance_override [] hyp_ts concl_t |
|
264 end |
|
265 |
|
266 fun run_prover ctxt (params as {provers, ...}) facts goal = |
|
267 let |
|
268 val problem = |
|
269 {state = Proof.init ctxt, goal = goal, subgoal = 1, subgoal_count = 1, |
|
270 facts = facts |> map Sledgehammer_Provers.Untranslated_Fact} |
|
271 val prover = |
|
272 Sledgehammer_Minimize.get_minimizing_prover ctxt |
|
273 Sledgehammer_Provers.Normal (hd provers) |
|
274 in prover params (K (K (K ""))) problem end |
|
275 |
|
276 fun generate_accessibility thy include_thy file_name = |
|
277 let |
|
278 val path = file_name |> Path.explode |
|
279 val _ = File.write path "" |
|
280 fun do_thm th prevs = |
|
281 let |
|
282 val s = th ^ ": " ^ space_implode " " prevs ^ "\n" |
|
283 val _ = File.append path s |
|
284 in [th] end |
|
285 val thy_ths = |
|
286 all_non_tautological_facts_of thy |
|
287 |> not include_thy ? filter_out (has_thy thy o snd) |
|
288 |> thms_by_thy |
|
289 fun do_thy ths = |
|
290 let |
|
291 val thy = theory_of_thm (hd ths) |
|
292 val parents = parent_thms thy_ths thy |
|
293 val ths = ths |> map (fact_name_of o Thm.get_name_hint) |
|
294 in fold do_thm ths parents; () end |
|
295 in List.app (do_thy o snd) thy_ths end |
|
296 |
|
297 fun generate_features thy include_thy file_name = |
|
298 let |
|
299 val path = file_name |> Path.explode |
|
300 val _ = File.write path "" |
|
301 val facts = |
|
302 all_non_tautological_facts_of thy |
|
303 |> not include_thy ? filter_out (has_thy thy o snd) |
|
304 fun do_fact ((_, (_, status)), th) = |
|
305 let |
|
306 val name = Thm.get_name_hint th |
|
307 val feats = features_of thy (status, th) |
|
308 val s = fact_name_of name ^ ": " ^ space_implode " " feats ^ "\n" |
|
309 in File.append path s end |
|
310 in List.app do_fact facts end |
|
311 |
|
312 fun generate_isa_dependencies thy include_thy file_name = |
|
313 let |
|
314 val path = file_name |> Path.explode |
|
315 val _ = File.write path "" |
|
316 val ths = |
|
317 all_non_tautological_facts_of thy |
|
318 |> not include_thy ? filter_out (has_thy thy o snd) |
|
319 |> map snd |
|
320 val all_names = ths |> map Thm.get_name_hint |
|
321 fun do_thm th = |
|
322 let |
|
323 val name = Thm.get_name_hint th |
|
324 val deps = isabelle_dependencies_of all_names th |
|
325 val s = fact_name_of name ^ ": " ^ space_implode " " deps ^ "\n" |
|
326 in File.append path s end |
|
327 in List.app do_thm ths end |
|
328 |
|
329 fun generate_atp_dependencies ctxt (params as {max_relevant, ...}) thy |
|
330 include_thy file_name = |
|
331 let |
|
332 val path = file_name |> Path.explode |
|
333 val _ = File.write path "" |
|
334 val facts = |
|
335 all_non_tautological_facts_of thy |
|
336 |> not include_thy ? filter_out (has_thy thy o snd) |
|
337 val ths = facts |> map snd |
|
338 val all_names = ths |> map Thm.get_name_hint |
|
339 fun is_dep dep (_, th) = fact_name_of (Thm.get_name_hint th) = dep |
|
340 fun add_isa_dep facts dep accum = |
|
341 if exists (is_dep dep) accum then |
|
342 accum |
|
343 else case find_first (is_dep dep) facts of |
|
344 SOME ((name, status), th) => accum @ [((name (), status), th)] |
|
345 | NONE => accum (* shouldn't happen *) |
|
346 fun fix_name ((_, stature), th) = |
|
347 ((th |> Thm.get_name_hint |> fact_name_of, stature), th) |
|
348 fun do_thm th = |
|
349 let |
|
350 val name = Thm.get_name_hint th |
|
351 val goal = goal_of_thm thy th |
|
352 val deps = |
|
353 case isabelle_dependencies_of all_names th of |
|
354 [] => [] |
|
355 | isa_dep as [_] => isa_dep (* can hardly beat that *) |
|
356 | isa_deps => |
|
357 let |
|
358 val facts = |
|
359 facts |> filter (fn (_, th') => thm_ord (th', th) = LESS) |
|
360 val facts = |
|
361 facts |> iter_facts ctxt params (the max_relevant) goal |
|
362 |> fold (add_isa_dep facts) isa_deps |
|
363 |> map fix_name |
|
364 in |
|
365 case run_prover ctxt params facts goal of |
|
366 {outcome = NONE, used_facts, ...} => |
|
367 used_facts |> map fst |> sort string_ord |
|
368 | _ => isa_deps |
|
369 end |
|
370 val s = fact_name_of name ^ ": " ^ space_implode " " deps ^ "\n" |
|
371 in File.append path s end |
|
372 in List.app do_thm ths end |
|
373 |
|
374 |
|
375 (*** High-level communication with MaSh ***) |
|
376 |
33 fun reset () = |
377 fun reset () = |
34 () |
378 () |
35 |
379 |
36 fun can_suggest () = |
380 fun can_suggest () = |
37 true |
381 true |