87 |
87 |
88 fun map_criteria f {goal, limit, rem_dups, criteria} = |
88 fun map_criteria f {goal, limit, rem_dups, criteria} = |
89 {goal = goal, limit = limit, rem_dups = rem_dups, criteria = f criteria}; |
89 {goal = goal, limit = limit, rem_dups = rem_dups, criteria = f criteria}; |
90 |
90 |
91 |
91 |
92 |
|
93 (** theorems, either internal or external (without proof) **) |
|
94 |
|
95 datatype theorem = |
|
96 Internal of Facts.ref * thm | |
|
97 External of Facts.ref * term; (* FIXME: Facts.ref not appropriate *) |
|
98 |
|
99 fun prop_of (Internal (_, thm)) = Thm.full_prop_of thm |
|
100 | prop_of (External (_, prop)) = prop; |
|
101 |
|
102 fun nprems_of (Internal (_, thm)) = Thm.nprems_of thm |
|
103 | nprems_of (External (_, prop)) = Logic.count_prems prop; |
|
104 |
|
105 fun size_of (Internal (_, thm)) = size_of_term (Thm.prop_of thm) |
|
106 | size_of (External (_, prop)) = size_of_term prop; |
|
107 |
|
108 fun major_prem_of (Internal (_, thm)) = Thm.major_prem_of thm |
|
109 | major_prem_of (External (_, prop)) = |
|
110 Logic.strip_assums_concl (hd (Logic.strip_imp_prems prop)); |
|
111 |
|
112 fun fact_ref_of (Internal (fact_ref, _)) = fact_ref |
|
113 | fact_ref_of (External (fact_ref, _)) = fact_ref; |
|
114 |
|
115 |
|
116 |
|
117 (** search criterion filters **) |
92 (** search criterion filters **) |
118 |
93 |
119 (*generated filters are to be of the form |
94 (*generated filters are to be of the form |
120 input: theorem |
95 input: (Facts.ref * thm) |
121 output: (p:int, s:int, t:int) option, where |
96 output: (p:int, s:int, t:int) option, where |
122 NONE indicates no match |
97 NONE indicates no match |
123 p is the primary sorting criterion |
98 p is the primary sorting criterion |
124 (eg. size of term) |
99 (eg. size of term) |
125 s is the secondary sorting criterion |
100 s is the secondary sorting criterion |
162 end; |
137 end; |
163 |
138 |
164 |
139 |
165 (* filter_name *) |
140 (* filter_name *) |
166 |
141 |
167 fun filter_name str_pat theorem = |
142 fun filter_name str_pat (thmref, _) = |
168 if match_string str_pat (Facts.name_of_ref (fact_ref_of theorem)) |
143 if match_string str_pat (Facts.name_of_ref thmref) |
169 then SOME (0, 0, 0) else NONE; |
144 then SOME (0, 0, 0) else NONE; |
170 |
145 |
171 |
146 |
172 (* filter intro/elim/dest/solves rules *) |
147 (* filter intro/elim/dest/solves rules *) |
173 |
148 |
174 fun filter_dest ctxt goal theorem = |
149 fun filter_dest ctxt goal (_, thm) = |
175 let |
150 let |
176 val extract_dest = |
151 val extract_dest = |
177 (fn theorem => if nprems_of theorem = 0 then [] else [prop_of theorem], |
152 (fn thm => if Thm.no_prems thm then [] else [Thm.full_prop_of thm], |
178 hd o Logic.strip_imp_prems); |
153 hd o Logic.strip_imp_prems); |
179 val prems = Logic.prems_of_goal goal 1; |
154 val prems = Logic.prems_of_goal goal 1; |
180 |
155 |
181 fun try_subst prem = is_matching_thm extract_dest ctxt true prem theorem; |
156 fun try_subst prem = is_matching_thm extract_dest ctxt true prem thm; |
182 val successful = prems |> map_filter try_subst; |
157 val successful = prems |> map_filter try_subst; |
183 in |
158 in |
184 (*if possible, keep best substitution (one with smallest size)*) |
159 (*if possible, keep best substitution (one with smallest size)*) |
185 (*dest rules always have assumptions, so a dest with one |
160 (*dest rules always have assumptions, so a dest with one |
186 assumption is as good as an intro rule with none*) |
161 assumption is as good as an intro rule with none*) |
187 if not (null successful) |
162 if not (null successful) then |
188 then SOME (size_of theorem, nprems_of theorem - 1, foldl1 Int.min successful) else NONE |
163 SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm - 1, foldl1 Int.min successful) |
189 end; |
164 else NONE |
190 |
165 end; |
191 fun filter_intro ctxt goal theorem = |
166 |
192 let |
167 fun filter_intro ctxt goal (_, thm) = |
193 val extract_intro = (single o prop_of, Logic.strip_imp_concl); |
168 let |
|
169 val extract_intro = (single o Thm.full_prop_of, Logic.strip_imp_concl); |
194 val concl = Logic.concl_of_goal goal 1; |
170 val concl = Logic.concl_of_goal goal 1; |
195 val ss = is_matching_thm extract_intro ctxt true concl theorem; |
171 in |
196 in |
172 (case is_matching_thm extract_intro ctxt true concl thm of |
197 if is_some ss then SOME (size_of theorem, nprems_of theorem, the ss) else NONE |
173 SOME ss => SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, ss) |
198 end; |
174 | NONE => NONE) |
199 |
175 end; |
200 fun filter_elim ctxt goal theorem = |
176 |
201 if nprems_of theorem > 0 then |
177 fun filter_elim ctxt goal (_, thm) = |
|
178 if Thm.nprems_of thm > 0 then |
202 let |
179 let |
203 val rule = prop_of theorem; |
180 val rule = Thm.full_prop_of thm; |
204 val prems = Logic.prems_of_goal goal 1; |
181 val prems = Logic.prems_of_goal goal 1; |
205 val goal_concl = Logic.concl_of_goal goal 1; |
182 val goal_concl = Logic.concl_of_goal goal 1; |
206 val rule_mp = hd (Logic.strip_imp_prems rule); |
183 val rule_mp = hd (Logic.strip_imp_prems rule); |
207 val rule_concl = Logic.strip_imp_concl rule; |
184 val rule_concl = Logic.strip_imp_concl rule; |
208 fun combine t1 t2 = Const ("*combine*", dummyT --> dummyT) $ (t1 $ t2); (* FIXME ?? *) |
185 fun combine t1 t2 = Const ("*combine*", dummyT --> dummyT) $ (t1 $ t2); (* FIXME ?? *) |
211 fun try_subst prem = is_matching_thm (single, I) ctxt true (goal_tree prem) rule_tree; |
188 fun try_subst prem = is_matching_thm (single, I) ctxt true (goal_tree prem) rule_tree; |
212 val successful = prems |> map_filter try_subst; |
189 val successful = prems |> map_filter try_subst; |
213 in |
190 in |
214 (*elim rules always have assumptions, so an elim with one |
191 (*elim rules always have assumptions, so an elim with one |
215 assumption is as good as an intro rule with none*) |
192 assumption is as good as an intro rule with none*) |
216 if is_nontrivial (Proof_Context.theory_of ctxt) (major_prem_of theorem) |
193 if is_nontrivial (Proof_Context.theory_of ctxt) (Thm.major_prem_of thm) |
217 andalso not (null successful) |
194 andalso not (null successful) then |
218 then SOME (size_of theorem, nprems_of theorem - 1, foldl1 Int.min successful) else NONE |
195 SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm - 1, foldl1 Int.min successful) |
|
196 else NONE |
219 end |
197 end |
220 else NONE; |
198 else NONE; |
221 |
199 |
222 fun filter_solves ctxt goal = |
200 fun filter_solves ctxt goal = |
223 let |
201 let |
233 if Thm.no_prems thm then rtac thm 1 goal' |
211 if Thm.no_prems thm then rtac thm 1 goal' |
234 else |
212 else |
235 (limited_etac thm THEN_ALL_NEW (Goal.norm_hhf_tac ctxt' THEN' Method.assm_tac ctxt')) |
213 (limited_etac thm THEN_ALL_NEW (Goal.norm_hhf_tac ctxt' THEN' Method.assm_tac ctxt')) |
236 1 goal'; |
214 1 goal'; |
237 in |
215 in |
238 fn Internal (_, thm) => |
216 fn (_, thm) => |
239 if is_some (Seq.pull (try_thm thm)) |
217 if is_some (Seq.pull (try_thm thm)) |
240 then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, 0) else NONE |
218 then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, 0) |
241 | External _ => NONE |
219 else NONE |
242 end; |
220 end; |
243 |
221 |
244 |
222 |
245 (* filter_simp *) |
223 (* filter_simp *) |
246 |
224 |
247 fun filter_simp ctxt t (Internal (_, thm)) = |
225 fun filter_simp ctxt t (_, thm) = |
248 let |
226 let |
249 val mksimps = Simplifier.mksimps ctxt; |
227 val mksimps = Simplifier.mksimps ctxt; |
250 val extract_simp = |
228 val extract_simp = |
251 (map Thm.full_prop_of o mksimps, #1 o Logic.dest_equals o Logic.strip_imp_concl); |
229 (map Thm.full_prop_of o mksimps, #1 o Logic.dest_equals o Logic.strip_imp_concl); |
252 val ss = is_matching_thm extract_simp ctxt false t thm; |
230 in |
253 in |
231 (case is_matching_thm extract_simp ctxt false t thm of |
254 if is_some ss |
232 SOME ss => SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, ss) |
255 then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, the ss) |
233 | NONE => NONE) |
256 else NONE |
234 end; |
257 end |
|
258 | filter_simp _ _ (External _) = NONE; |
|
259 |
235 |
260 |
236 |
261 (* filter_pattern *) |
237 (* filter_pattern *) |
262 |
238 |
263 fun get_names t = Term.add_const_names t (Term.add_free_names t []); |
239 fun get_names t = Term.add_const_names t (Term.add_free_names t []); |
272 |
248 |
273 fun filter_pattern ctxt pat = |
249 fun filter_pattern ctxt pat = |
274 let |
250 let |
275 val pat_consts = get_names pat; |
251 val pat_consts = get_names pat; |
276 |
252 |
277 fun check (theorem, NONE) = check (theorem, SOME (get_names (prop_of theorem))) |
253 fun check ((x, thm), NONE) = check ((x, thm), SOME (get_names (Thm.full_prop_of thm))) |
278 | check (theorem, c as SOME thm_consts) = |
254 | check ((_, thm), c as SOME thm_consts) = |
279 (if subset (op =) (pat_consts, thm_consts) andalso |
255 (if subset (op =) (pat_consts, thm_consts) andalso |
280 Pattern.matches_subterm (Proof_Context.theory_of ctxt) (pat, prop_of theorem) |
256 Pattern.matches_subterm (Proof_Context.theory_of ctxt) (pat, Thm.full_prop_of thm) |
281 then SOME (size_of theorem, nprems_of theorem, 0) else NONE, c); |
257 then SOME (size_of_term (Thm.prop_of thm), Thm.nprems_of thm, 0) else NONE, c); |
282 in check end; |
258 in check end; |
283 |
259 |
284 |
260 |
285 (* interpret criteria as filters *) |
261 (* interpret criteria as filters *) |
286 |
262 |
318 in |
294 in |
319 |
295 |
320 fun filter_criterion ctxt opt_goal (b, c) = |
296 fun filter_criterion ctxt opt_goal (b, c) = |
321 (if b then I else (apfst opt_not)) o filter_crit ctxt opt_goal c; |
297 (if b then I else (apfst opt_not)) o filter_crit ctxt opt_goal c; |
322 |
298 |
323 fun sorted_filter filters theorems = |
299 fun sorted_filter filters thms = |
324 let |
300 let |
325 fun eval_filters theorem = app_filters theorem (SOME (0, 0, 0), NONE, filters); |
301 fun eval_filters thm = app_filters thm (SOME (0, 0, 0), NONE, filters); |
326 |
302 |
327 (*filters return: (thm size, number of assumptions, substitution size) option, so |
303 (*filters return: (thm size, number of assumptions, substitution size) option, so |
328 sort according to size of thm first, then number of assumptions, |
304 sort according to size of thm first, then number of assumptions, |
329 then by the substitution size, then by term order *) |
305 then by the substitution size, then by term order *) |
330 fun result_ord (((p0, s0, t0), thm0), ((p1, s1, t1), thm1)) = |
306 fun result_ord (((p0, s0, t0), (_, thm0)), ((p1, s1, t1), (_, thm1))) = |
331 prod_ord int_ord (prod_ord int_ord (prod_ord int_ord Term_Ord.term_ord)) |
307 prod_ord int_ord (prod_ord int_ord (prod_ord int_ord Term_Ord.term_ord)) |
332 ((p1, (s1, (t1, prop_of thm1))), (p0, (s0, (t0, prop_of thm0)))); |
308 ((p1, (s1, (t1, Thm.full_prop_of thm1))), (p0, (s0, (t0, Thm.full_prop_of thm0)))); |
333 in |
309 in |
334 grouped 100 Par_List.map eval_filters theorems |
310 grouped 100 Par_List.map eval_filters thms |
335 |> map_filter I |> sort result_ord |> map #2 |
311 |> map_filter I |> sort result_ord |> map #2 |
336 end; |
312 end; |
337 |
313 |
338 fun lazy_filter filters = |
314 fun lazy_filter filters = |
339 let |
315 let |
366 |
342 |
367 fun rem_cdups nicer xs = |
343 fun rem_cdups nicer xs = |
368 let |
344 let |
369 fun rem_c rev_seen [] = rev rev_seen |
345 fun rem_c rev_seen [] = rev rev_seen |
370 | rem_c rev_seen [x] = rem_c (x :: rev_seen) [] |
346 | rem_c rev_seen [x] = rem_c (x :: rev_seen) [] |
371 | rem_c rev_seen ((x as (t, _)) :: (y as (t', _)) :: xs) = |
347 | rem_c rev_seen ((x as ((n, thm), _)) :: (y as ((n', thm'), _)) :: rest) = |
372 if prop_of t aconv prop_of t' |
348 if Thm.eq_thm_prop (thm, thm') |
373 then rem_c rev_seen ((if nicer (fact_ref_of t) (fact_ref_of t') then x else y) :: xs) |
349 then rem_c rev_seen ((if nicer n n' then x else y) :: rest) |
374 else rem_c (x :: rev_seen) (y :: xs); |
350 else rem_c (x :: rev_seen) (y :: rest); |
375 in rem_c [] xs end; |
351 in rem_c [] xs end; |
376 |
352 |
377 in |
353 in |
378 |
354 |
379 fun nicer_shortest ctxt = |
355 fun nicer_shortest ctxt = |
459 Proof_Context.get_fact ctxt (Facts.named "local.assms") |
435 Proof_Context.get_fact ctxt (Facts.named "local.assms") |
460 handle ERROR _ => []; |
436 handle ERROR _ => []; |
461 val add_prems = Seq.hd o TRY (Method.insert_tac assms 1); |
437 val add_prems = Seq.hd o TRY (Method.insert_tac assms 1); |
462 val opt_goal' = Option.map add_prems opt_goal; |
438 val opt_goal' = Option.map add_prems opt_goal; |
463 in |
439 in |
464 filter ctxt (map Internal (all_facts_of ctxt)) |
440 filter ctxt (all_facts_of ctxt) |
465 {goal = opt_goal', limit = opt_limit, rem_dups = rem_dups, criteria = raw_criteria} |
441 {goal = opt_goal', limit = opt_limit, rem_dups = rem_dups, criteria = raw_criteria} |
466 |> apsnd (map (fn Internal f => f)) |
|
467 end; |
442 end; |
468 |
443 |
469 in |
444 in |
470 |
445 |
471 val find_theorems = gen_find_theorems filter_theorems; |
446 val find_theorems = gen_find_theorems filter_theorems; |
487 in |
462 in |
488 [Pretty.mark (Proof_Context.markup_fact ctxt name) (Pretty.str name), |
463 [Pretty.mark (Proof_Context.markup_fact ctxt name) (Pretty.str name), |
489 Pretty.str (Facts.string_of_selection sel), Pretty.str ":", Pretty.brk 1] |
464 Pretty.str (Facts.string_of_selection sel), Pretty.str ":", Pretty.brk 1] |
490 end; |
465 end; |
491 |
466 |
492 fun pretty_theorem ctxt (Internal (thmref, thm)) = |
|
493 Pretty.block (pretty_ref ctxt thmref @ [Display.pretty_thm ctxt thm]) |
|
494 | pretty_theorem ctxt (External (thmref, prop)) = |
|
495 Pretty.block (pretty_ref ctxt thmref @ [Syntax.unparse_term ctxt prop]); |
|
496 |
|
497 in |
467 in |
498 |
468 |
499 fun pretty_thm ctxt (thmref, thm) = pretty_theorem ctxt (Internal (thmref, thm)); |
469 fun pretty_thm ctxt (thmref, thm) = |
|
470 Pretty.block (pretty_ref ctxt thmref @ [Display.pretty_thm ctxt thm]); |
500 |
471 |
501 fun pretty_theorems state opt_limit rem_dups raw_criteria = |
472 fun pretty_theorems state opt_limit rem_dups raw_criteria = |
502 let |
473 let |
503 val ctxt = Proof.context_of state; |
474 val ctxt = Proof.context_of state; |
504 val opt_goal = try Proof.simple_goal state |> Option.map #goal; |
475 val opt_goal = try Proof.simple_goal state |> Option.map #goal; |
505 val criteria = map (apsnd (read_criterion ctxt)) raw_criteria; |
476 val criteria = map (apsnd (read_criterion ctxt)) raw_criteria; |
506 |
477 |
507 val (opt_found, theorems) = |
478 val (opt_found, theorems) = |
508 filter_theorems ctxt (map Internal (all_facts_of ctxt)) |
479 filter_theorems ctxt (all_facts_of ctxt) |
509 {goal = opt_goal, limit = opt_limit, rem_dups = rem_dups, criteria = criteria}; |
480 {goal = opt_goal, limit = opt_limit, rem_dups = rem_dups, criteria = criteria}; |
510 val returned = length theorems; |
481 val returned = length theorems; |
511 |
482 |
512 val tally_msg = |
483 val tally_msg = |
513 (case opt_found of |
484 (case opt_found of |