76 otherwise the default ordering ("by package") is used. |
76 otherwise the default ordering ("by package") is used. |
77 *) |
77 *) |
78 |
78 |
79 |
79 |
80 (* matching theorems *) |
80 (* matching theorems *) |
81 |
81 |
82 fun is_matching_thm (extract_thms, extract_term) ctxt po obj thm = |
82 fun is_nontrivial sg = is_Const o head_of o ObjectLogic.drop_judgment sg; |
|
83 |
|
84 (*extract terms from term_src, refine them to the parts that concern us, |
|
85 if po try match them against obj else vice versa. |
|
86 trivial matches are ignored. |
|
87 returns: smallest substitution size*) |
|
88 fun is_matching_thm (extract_terms, refine_term) ctxt po obj term_src = |
83 let |
89 let |
84 val sg = ProofContext.sign_of ctxt; |
90 val sg = ProofContext.sign_of ctxt; |
85 val tsig = Sign.tsig_of sg; |
91 val tsig = Sign.tsig_of sg; |
86 |
92 |
87 val is_nontrivial = is_Const o head_of o ObjectLogic.drop_judgment sg; |
|
88 |
|
89 fun matches pat = |
93 fun matches pat = |
90 is_nontrivial pat andalso |
94 is_nontrivial sg pat andalso |
91 Pattern.matches tsig (if po then (pat,obj) else (obj,pat)); |
95 Pattern.matches tsig (if po then (pat,obj) else (obj,pat)); |
92 |
96 |
93 fun substsize pat = |
97 fun substsize pat = |
94 let |
98 let |
95 val (_,subst) = Pattern.match tsig (if po then (pat,obj) else (obj,pat)) |
99 val (_,subst) = Pattern.match tsig (if po then (pat,obj) else (obj,pat)) |
96 in Vartab.foldl (op + o apsnd (size_of_term o snd o snd)) (0, subst) |
100 in Vartab.foldl (op + o apsnd (size_of_term o snd o snd)) (0, subst) |
97 end; |
101 end; |
98 |
102 |
99 fun bestmatch [] = NONE |
103 fun bestmatch [] = NONE |
100 | bestmatch (x :: xs) = SOME (nprems_of thm, foldl Int.min x xs); |
104 | bestmatch (x :: xs) = SOME (foldl Int.min x xs); |
101 |
105 |
102 val match_thm = matches o extract_term o Thm.prop_of; |
106 val match_thm = matches o refine_term; |
103 in |
107 in |
104 map (substsize o extract_term o Thm.prop_of) |
108 map (substsize o refine_term) |
105 (List.filter match_thm (extract_thms thm)) |> bestmatch |
109 (List.filter match_thm (extract_terms term_src)) |> bestmatch |
106 end; |
110 end; |
107 |
111 |
108 |
112 |
109 (* filter_name *) |
113 (* filter_name *) |
110 |
114 |
121 then SOME (0,0) else NONE; |
125 then SOME (0,0) else NONE; |
122 |
126 |
123 |
127 |
124 (* filter intro/elim/dest rules *) |
128 (* filter intro/elim/dest rules *) |
125 |
129 |
126 local |
130 fun filter_dest ctxt goal (_,thm) = |
127 |
131 let |
128 (*elimination rule: conclusion is a Var which does not appear in the major premise*) |
132 val extract_dest = |
129 fun is_elim ctxt thm = |
133 (fn thm => if Thm.no_prems thm then [] else [prop_of thm], |
130 let |
|
131 val sg = ProofContext.sign_of ctxt; |
|
132 val prop = Thm.prop_of thm; |
|
133 val concl = ObjectLogic.drop_judgment sg (Logic.strip_imp_concl prop); |
|
134 val major_prem = Library.take (1, Logic.strip_imp_prems prop); |
|
135 val prem_vars = Drule.vars_of_terms major_prem; |
|
136 in |
|
137 not (null major_prem) andalso |
|
138 Term.is_Var concl andalso |
|
139 not (Term.dest_Var concl mem prem_vars) |
|
140 end; |
|
141 |
|
142 fun filter_elim_dest check_thm ctxt goal (_,thm) = |
|
143 let |
|
144 val extract_elim = |
|
145 (fn thm => if Thm.no_prems thm then [] else [thm], |
|
146 hd o Logic.strip_imp_prems); |
134 hd o Logic.strip_imp_prems); |
147 val prems = Logic.prems_of_goal goal 1; |
135 val prems = Logic.prems_of_goal goal 1; |
148 |
136 |
149 fun try_subst prem = is_matching_thm extract_elim ctxt true prem thm; |
137 fun try_subst prem = is_matching_thm extract_dest ctxt true prem thm; |
150 |
138 |
151 (*keep successful substitutions*) |
139 (*keep successful substitutions*) |
152 val ss = prems |> List.map try_subst |
140 val ss = prems |> List.map try_subst |
153 |> List.filter isSome |
141 |> List.filter isSome |
154 |> List.map (#2 o valOf); |
142 |> List.map valOf; |
155 in |
143 in |
156 (*if possible, keep best substitution (one with smallest size)*) |
144 (*if possible, keep best substitution (one with smallest size)*) |
157 (*elim and dest rules always have assumptions, so an elim with one |
145 (*dest rules always have assumptions, so a dest with one |
158 assumption is as good as an intro rule with none*) |
146 assumption is as good as an intro rule with none*) |
159 if check_thm ctxt thm andalso not (null ss) |
147 if not (null ss) |
160 then SOME (nprems_of thm - 1, foldl Int.min (hd ss) (tl ss)) else NONE |
148 then SOME (nprems_of thm - 1, foldl Int.min (hd ss) (tl ss)) else NONE |
161 end; |
149 end; |
162 |
150 |
163 in |
|
164 |
|
165 fun filter_intro ctxt goal (_,thm) = |
151 fun filter_intro ctxt goal (_,thm) = |
166 let |
152 let |
167 val extract_intro = (single, Logic.strip_imp_concl); |
153 val extract_intro = (single o prop_of, Logic.strip_imp_concl); |
168 val concl = Logic.concl_of_goal goal 1; |
154 val concl = Logic.concl_of_goal goal 1; |
169 in |
155 val ss = is_matching_thm extract_intro ctxt true concl thm; |
170 is_matching_thm extract_intro ctxt true concl thm |
156 in |
171 end; |
157 if is_some ss then SOME (nprems_of thm, valOf ss) else NONE |
172 |
158 end; |
173 fun filter_elim ctxt = filter_elim_dest is_elim ctxt; |
159 |
174 fun filter_dest ctxt = filter_elim_dest (not oo is_elim) ctxt; |
160 fun filter_elim ctxt goal (_,thm) = |
175 |
161 if not (Thm.no_prems thm) then |
176 end; |
162 let |
|
163 val rule = prop_of thm; |
|
164 val prems = Logic.prems_of_goal goal 1; |
|
165 val goal_concl = Logic.concl_of_goal goal 1; |
|
166 val rule_mp = (hd o Logic.strip_imp_prems) rule; |
|
167 val rule_concl = Logic.strip_imp_concl rule; |
|
168 fun combine t1 t2 = Const ("combine", dummyT --> dummyT) $ (t1 $ t2); |
|
169 val rule_tree = combine rule_mp rule_concl; |
|
170 fun goal_tree prem = (combine prem goal_concl); |
|
171 fun try_subst prem = |
|
172 is_matching_thm (single, I) ctxt true (goal_tree prem) rule_tree; |
|
173 (*keep successful substitutions*) |
|
174 val ss = prems |> List.map try_subst |
|
175 |> List.filter isSome |
|
176 |> List.map valOf; |
|
177 in |
|
178 (*elim rules always have assumptions, so an elim with one |
|
179 assumption is as good as an intro rule with none*) |
|
180 if is_nontrivial (ProofContext.sign_of ctxt) (Thm.major_prem_of thm) |
|
181 andalso not (null ss) |
|
182 then SOME (nprems_of thm - 1, foldl Int.min (hd ss) (tl ss)) else NONE |
|
183 end |
|
184 else NONE |
177 |
185 |
178 |
186 |
179 (* filter_simp *) |
187 (* filter_simp *) |
180 |
188 |
181 fun filter_simp ctxt t (_,thm) = |
189 fun filter_simp ctxt t (_,thm) = |
182 let |
190 let |
183 val (_, {mk_rews = {mk, ...}, ...}) = |
191 val (_, {mk_rews = {mk, ...}, ...}) = |
184 MetaSimplifier.rep_ss (Simplifier.local_simpset_of ctxt); |
192 MetaSimplifier.rep_ss (Simplifier.local_simpset_of ctxt); |
185 val extract_simp = (mk, #1 o Logic.dest_equals o Logic.strip_imp_concl); |
193 val extract_simp = |
186 in is_matching_thm extract_simp ctxt false t thm end; |
194 ((List.map prop_of) o mk, #1 o Logic.dest_equals o Logic.strip_imp_concl); |
|
195 val ss = is_matching_thm extract_simp ctxt false t thm |
|
196 in |
|
197 if is_some ss then SOME (nprems_of thm, valOf ss) else NONE |
|
198 end; |
187 |
199 |
188 |
200 |
189 (* filter_pattern *) |
201 (* filter_pattern *) |
190 |
202 |
191 fun filter_pattern ctxt pat (_, thm) = |
203 fun filter_pattern ctxt pat (_, thm) = |
224 let |
236 let |
225 fun eval_filters filters thm = |
237 fun eval_filters filters thm = |
226 map (fn f => f thm) filters |> List.foldl opt_add (SOME (0,0)); |
238 map (fn f => f thm) filters |> List.foldl opt_add (SOME (0,0)); |
227 |
239 |
228 (*filters return: (number of assumptions, substitution size) option, so |
240 (*filters return: (number of assumptions, substitution size) option, so |
229 sort (desc. in both cases) according to whether a theorem has assumptions, |
241 sort (desc. in both cases) according to number of assumptions first, |
230 then by the substitution size*) |
242 then by the substitution size*) |
231 fun thm_ord (((p0,s0),_),((p1,s1),_)) = |
243 fun thm_ord (((p0,s0),_),((p1,s1),_)) = |
232 prod_ord (int_ord o pairself (fn 0 => 0 | x => 1)) |
244 prod_ord int_ord int_ord ((p1,s1),(p0,s0)); |
233 int_ord ((p1,s1),(p0,s0)); |
|
234 |
245 |
235 val processed = List.map (fn t => (eval_filters filters t, t)) thms; |
246 val processed = List.map (fn t => (eval_filters filters t, t)) thms; |
236 val filtered = List.filter (isSome o #1) processed; |
247 val filtered = List.filter (isSome o #1) processed; |
237 in |
248 in |
238 filtered |> List.map (apfst valOf) |> sort thm_ord |> map #2 |
249 filtered |> List.map (apfst valOf) |> sort thm_ord |> map #2 |