76 open Order_Procedure |
76 open Order_Procedure |
77 |
77 |
78 fun expect _ (SOME x) = x |
78 fun expect _ (SOME x) = x |
79 | expect f NONE = f () |
79 | expect f NONE = f () |
80 |
80 |
81 fun matches_skeleton t s = t = Term.dummy orelse |
|
82 (case (t, s) of |
|
83 (t0 $ t1, s0 $ s1) => matches_skeleton t0 s0 andalso matches_skeleton t1 s1 |
|
84 | _ => t aconv s) |
|
85 |
|
86 fun dest_binop t = |
|
87 let |
|
88 val binop_skel = Term.dummy $ Term.dummy $ Term.dummy |
|
89 val not_binop_skel = Logic_Sig.Not $ binop_skel |
|
90 in |
|
91 if matches_skeleton not_binop_skel t |
|
92 then (case t of (_ $ (t1 $ t2 $ t3)) => (false, (t1, t2, t3))) |
|
93 else if matches_skeleton binop_skel t |
|
94 then (case t of (t1 $ t2 $ t3) => (true, (t1, t2, t3))) |
|
95 else raise TERM ("Not a binop literal", [t]) |
|
96 end |
|
97 |
|
98 fun find_term t = Library.find_first (fn (t', _) => t' aconv t) |
|
99 |
|
100 fun reify_order_atom (eq, le, lt) t reifytab = |
|
101 let |
|
102 val (b, (t0, t1, t2)) = |
|
103 (dest_binop t) handle TERM (_, _) => raise TERM ("Can't reify order literal", [t]) |
|
104 val binops = [(eq, EQ), (le, LEQ), (lt, LESS)] |
|
105 in |
|
106 case find_term t0 binops of |
|
107 SOME (_, reified_bop) => |
|
108 reifytab |
|
109 |> Reifytab.get_var t1 ||> Reifytab.get_var t2 |
|
110 |> (fn (v1, (v2, vartab')) => |
|
111 ((b, reified_bop (Int_of_integer v1, Int_of_integer v2)), vartab')) |
|
112 |>> Atom |
|
113 | NONE => raise TERM ("Can't reify order literal", [t]) |
|
114 end |
|
115 |
|
116 fun reify consts reify_atom t reifytab = |
|
117 let |
|
118 fun reify' (t1 $ t2) reifytab = |
|
119 let |
|
120 val (t0, ts) = strip_comb (t1 $ t2) |
|
121 val consts_of_arity = filter (fn (_, (_, ar)) => length ts = ar) consts |
|
122 in |
|
123 (case find_term t0 consts_of_arity of |
|
124 SOME (_, (reified_op, _)) => fold_map reify' ts reifytab |>> reified_op |
|
125 | NONE => reify_atom (t1 $ t2) reifytab) |
|
126 end |
|
127 | reify' t reifytab = reify_atom t reifytab |
|
128 in |
|
129 reify' t reifytab |
|
130 end |
|
131 |
|
132 fun list_curry0 f = (fn [] => f, 0) |
81 fun list_curry0 f = (fn [] => f, 0) |
133 fun list_curry1 f = (fn [x] => f x, 1) |
82 fun list_curry1 f = (fn [x] => f x, 1) |
134 fun list_curry2 f = (fn [x, y] => f x y, 2) |
83 fun list_curry2 f = (fn [x, y] => f x y, 2) |
135 |
|
136 fun reify_order_conj ord_ops = |
|
137 let |
|
138 val consts = map (apsnd (list_curry2 o curry)) [(Logic_Sig.conj, And), (Logic_Sig.disj, Or)] |
|
139 in |
|
140 reify consts (reify_order_atom ord_ops) |
|
141 end |
|
142 |
84 |
143 fun dereify_term consts reifytab t = |
85 fun dereify_term consts reifytab t = |
144 let |
86 let |
145 fun dereify_term' (App (t1, t2)) = (dereify_term' t1) $ (dereify_term' t2) |
87 fun dereify_term' (App (t1, t2)) = (dereify_term' t1) $ (dereify_term' t2) |
146 | dereify_term' (Const s) = |
88 | dereify_term' (Const s) = |
251 val dereify = dereify_order_fm ord_ops reifytab |
193 val dereify = dereify_order_fm ord_ops reifytab |
252 in |
194 in |
253 replay_prf_trm (replay_conv convs) dereify ctxt thmtab assmtab |
195 replay_prf_trm (replay_conv convs) dereify ctxt thmtab assmtab |
254 end |
196 end |
255 |
197 |
256 fun is_binop_term t = |
198 fun strip_Not (nt $ t) = if nt = Logic_Sig.Not then t else nt $ t |
257 let |
199 | strip_Not t = t |
258 fun is_included t = forall (curry (op <>) (t |> fastype_of |> domain_type)) excluded_types |
200 |
259 in |
201 fun limit_not_less [_, _, lt] ctxt decomp_prems = |
260 (case dest_binop (Logic_Sig.dest_Trueprop t) of |
|
261 (_, (binop, t1, t2)) => |
|
262 is_included binop andalso |
|
263 (* Exclude terms with schematic variables since the solver can't deal with them. |
|
264 More specifically, the solver uses Assumption.assume which does not allow schematic |
|
265 variables in the assumed cterm. |
|
266 *) |
|
267 Term.add_var_names (binop $ t1 $ t2) [] = [] |
|
268 ) handle TERM (_, _) => false |
|
269 end |
|
270 |
|
271 fun partition_matches ctxt term_of pats ys = |
|
272 let |
|
273 val thy = Proof_Context.theory_of ctxt |
|
274 |
|
275 fun find_match t env = |
|
276 Library.get_first (try (fn pat => Pattern.match thy (pat, t) env)) pats |
|
277 |
|
278 fun filter_matches xs = fold (fn x => fn (mxs, nmxs, env) => |
|
279 case find_match (term_of x) env of |
|
280 SOME env' => (x::mxs, nmxs, env') |
|
281 | NONE => (mxs, x::nmxs, env)) xs ([], [], (Vartab.empty, Vartab.empty)) |
|
282 |
|
283 fun partition xs = |
|
284 case filter_matches xs of |
|
285 ([], _, _) => [] |
|
286 | (mxs, nmxs, env) => (env, mxs) :: partition nmxs |
|
287 in |
|
288 partition ys |
|
289 end |
|
290 |
|
291 fun limit_not_less [_, _, lt] ctxt prems = |
|
292 let |
202 let |
293 val thy = Proof_Context.theory_of ctxt |
203 val thy = Proof_Context.theory_of ctxt |
294 val trace = Config.get ctxt order_trace_cfg |
204 val trace = Config.get ctxt order_trace_cfg |
295 val limit = Config.get ctxt order_split_limit_cfg |
205 val limit = Config.get ctxt order_split_limit_cfg |
296 |
206 |
297 fun is_not_less_term t = |
207 fun is_not_less_term t = |
298 (case dest_binop (Logic_Sig.dest_Trueprop t) of |
208 case try (strip_Not o Logic_Sig.dest_Trueprop) t of |
299 (false, (t0, _, _)) => Pattern.matches thy (lt, t0) |
209 SOME (binop $ _ $ _) => Pattern.matches thy (lt, binop) |
300 | _ => false) |
210 | NONE => false |
301 handle TERM _ => false |
211 |
302 |
212 val not_less_prems = filter (is_not_less_term o Thm.prop_of o fst) decomp_prems |
303 val not_less_prems = filter (is_not_less_term o Thm.prop_of) prems |
|
304 val _ = if trace andalso length not_less_prems > limit |
213 val _ = if trace andalso length not_less_prems > limit |
305 then tracing "order split limit exceeded" |
214 then tracing "order split limit exceeded" |
306 else () |
215 else () |
307 in |
216 in |
308 filter_out (is_not_less_term o Thm.prop_of) prems @ |
217 filter_out (is_not_less_term o Thm.prop_of o fst) decomp_prems @ |
309 take limit not_less_prems |
218 take limit not_less_prems |
310 end |
219 end |
|
220 |
|
221 fun decomp [eq, le, lt] ctxt t = |
|
222 let |
|
223 fun is_excluded t = exists (fn ty => ty = fastype_of t) excluded_types |
|
224 |
|
225 fun decomp'' (binop $ t1 $ t2) = |
|
226 let |
|
227 open Order_Procedure |
|
228 val thy = Proof_Context.theory_of ctxt |
|
229 fun try_match pat = try (Pattern.match thy (pat, binop)) (Vartab.empty, Vartab.empty) |
|
230 in if is_excluded t1 then NONE |
|
231 else case (try_match eq, try_match le, try_match lt) of |
|
232 (SOME env, _, _) => SOME (true, EQ, (t1, t2), env) |
|
233 | (_, SOME env, _) => SOME (true, LEQ, (t1, t2), env) |
|
234 | (_, _, SOME env) => SOME (true, LESS, (t1, t2), env) |
|
235 | _ => NONE |
|
236 end |
|
237 | decomp'' _ = NONE |
|
238 |
|
239 fun decomp' (nt $ t) = |
|
240 if nt = Logic_Sig.Not |
|
241 then decomp'' t |> Option.map (fn (b, c, p, e) => (not b, c, p, e)) |
|
242 else decomp'' (nt $ t) |
|
243 | decomp' t = decomp'' t |
|
244 |
|
245 in |
|
246 try Logic_Sig.dest_Trueprop t |> Option.mapPartial decomp' |
|
247 end |
|
248 |
|
249 fun maximal_envs envs = |
|
250 let |
|
251 fun test_opt p (SOME x) = p x |
|
252 | test_opt _ NONE = false |
|
253 |
|
254 fun leq_env (tyenv1, tenv1) (tyenv2, tenv2) = |
|
255 Vartab.forall (fn (v, ty) => |
|
256 Vartab.lookup tyenv2 v |> test_opt (fn ty2 => ty2 = ty)) tyenv1 |
|
257 andalso |
|
258 Vartab.forall (fn (v, (ty, t)) => |
|
259 Vartab.lookup tenv2 v |> test_opt (fn (ty2, t2) => ty2 = ty andalso t2 aconv t)) tenv1 |
|
260 |
|
261 fun fold_env (i, env) es = fold_index (fn (i2, env2) => fn es => |
|
262 if i = i2 then es else if leq_env env env2 then (i, i2) :: es else es) envs es |
|
263 |
|
264 val env_order = fold_index fold_env envs [] |
|
265 |
|
266 val graph = fold_index (fn (i, env) => fn g => Int_Graph.new_node (i, env) g) |
|
267 envs Int_Graph.empty |
|
268 val graph = fold Int_Graph.add_edge env_order graph |
|
269 |
|
270 val strong_conns = Int_Graph.strong_conn graph |
|
271 val maximals = |
|
272 filter (fn comp => length comp = length (Int_Graph.all_succs graph comp)) strong_conns |
|
273 in |
|
274 map (Int_Graph.all_preds graph) maximals |
|
275 end |
311 |
276 |
312 fun order_tac raw_order_proc octxt simp_prems = |
277 fun order_tac raw_order_proc octxt simp_prems = |
313 Subgoal.FOCUS (fn {prems=prems, context=ctxt, ...} => |
278 Subgoal.FOCUS (fn {prems=prems, context=ctxt, ...} => |
314 let |
279 let |
315 val trace = Config.get ctxt order_trace_cfg |
280 val trace = Config.get ctxt order_trace_cfg |
316 |
281 |
317 val binop_prems = filter (is_binop_term o Thm.prop_of) (prems @ simp_prems) |
282 fun these' _ [] = [] |
318 val strip_binop = (fn (x, _, _) => x) o snd o dest_binop |
283 | these' f (x :: xs) = case f x of NONE => these' f xs | SOME y => (x, y) :: these' f xs |
319 val binop_of = strip_binop o Logic_Sig.dest_Trueprop o Thm.prop_of |
284 |
320 |
285 val prems = simp_prems @ prems |
321 (* Due to local_setup, the operators of the order may contain schematic term and type |
286 |> filter (fn p => null (Term.add_vars (Thm.prop_of p) [])) |
322 variables. We partition the premises according to distinct instances of those operators. |
287 |> map (Conv.fconv_rule Thm.eta_conversion) |
323 *) |
288 val decomp_prems = these' (decomp (#ops octxt) ctxt o Thm.prop_of) prems |
324 val part_prems = partition_matches ctxt binop_of (#ops octxt) binop_prems |
289 |
325 |> (case #kind octxt of |
290 fun env_of (_, (_, _, _, env)) = env |
326 Order => map (fn (env, prems) => |
291 val env_groups = maximal_envs (map env_of decomp_prems) |
327 (env, limit_not_less (#ops octxt) ctxt prems)) |
292 |
328 | _ => I) |
293 fun order_tac' (_, []) = no_tac |
|
294 | order_tac' (env, decomp_prems) = |
|
295 let |
|
296 val [eq, le, lt] = #ops octxt |> map (Envir.eta_contract o Envir.subst_term env) |
|
297 |
|
298 val decomp_prems = case #kind octxt of |
|
299 Order => limit_not_less (#ops octxt) ctxt decomp_prems |
|
300 | _ => decomp_prems |
|
301 |
|
302 fun reify_prem (_, (b, ctor, (x, y), _)) (ps, reifytab) = |
|
303 (Reifytab.get_var x ##>> Reifytab.get_var y) reifytab |
|
304 |>> (fn vp => (b, ctor (apply2 Int_of_integer vp)) :: ps) |
|
305 val (reified_prems, reifytab) = fold_rev reify_prem decomp_prems ([], Reifytab.empty) |
|
306 |
|
307 val reified_prems_conj = foldl1 (fn (x, a) => And (x, a)) (map Atom reified_prems) |
|
308 val prems_conj_thm = map fst decomp_prems |
|
309 |> foldl1 (fn (x, a) => Logic_Sig.conjI OF [x, a]) |
|
310 |> Conv.fconv_rule Thm.eta_conversion |
|
311 val prems_conj = prems_conj_thm |> Thm.prop_of |
329 |
312 |
330 fun order_tac' (_, []) = no_tac |
|
331 | order_tac' (env, prems) = |
|
332 let |
|
333 val [eq, le, lt] = #ops octxt |
|
334 val subst_contract = Envir.eta_contract o Envir.subst_term env |
|
335 val ord_ops = (subst_contract eq, |
|
336 subst_contract le, |
|
337 subst_contract lt) |
|
338 |
|
339 val _ = if trace then @{print} (ord_ops, prems) else (ord_ops, prems) |
|
340 |
|
341 val prems_conj_thm = foldl1 (fn (x, a) => Logic_Sig.conjI OF [x, a]) prems |
|
342 |> Conv.fconv_rule Thm.eta_conversion |
|
343 val prems_conj = prems_conj_thm |> Thm.prop_of |
|
344 val (reified_prems_conj, reifytab) = |
|
345 reify_order_conj ord_ops (Logic_Sig.dest_Trueprop prems_conj) Reifytab.empty |
|
346 |
|
347 val proof = raw_order_proc reified_prems_conj |
313 val proof = raw_order_proc reified_prems_conj |
348 |
314 |
|
315 val pretty_term_list = |
|
316 Pretty.list "" "" o map (Syntax.pretty_term (Config.put show_types true ctxt)) |
|
317 val pretty_thm_list = Pretty.list "" "" o map (Thm.pretty_thm ctxt) |
|
318 fun pretty_type_of t = Pretty.block [ Pretty.str "::", Pretty.brk 1, |
|
319 Pretty.quote (Syntax.pretty_typ ctxt (Term.fastype_of t)) ] |
|
320 fun pretty_trace () = |
|
321 [ ("order kind:", Pretty.str (@{make_string} (#kind octxt))) |
|
322 , ("order operators:", Pretty.block [ pretty_term_list [eq, le, lt], Pretty.brk 1 |
|
323 , pretty_type_of le ]) |
|
324 , ("premises:", pretty_thm_list prems) |
|
325 , ("selected premises:", pretty_thm_list (map fst decomp_prems)) |
|
326 , ("reified premises:", Pretty.str (@{make_string} reified_prems)) |
|
327 , ("contradiction:", Pretty.str (@{make_string} (Option.isSome proof))) |
|
328 ] |> map (fn (t, pp) => Pretty.block [Pretty.str t, Pretty.brk 1, pp]) |
|
329 |> Pretty.big_list "order solver called with the parameters" |
|
330 val _ = if trace then tracing (Pretty.string_of (pretty_trace ())) else () |
|
331 |
349 val assmtab = Termtab.make [(prems_conj, prems_conj_thm)] |
332 val assmtab = Termtab.make [(prems_conj, prems_conj_thm)] |
350 val replay = replay_order_prf_trm ord_ops octxt ctxt reifytab assmtab |
333 val replay = replay_order_prf_trm (eq, le, lt) octxt ctxt reifytab assmtab |
351 in |
334 in |
352 case proof of |
335 case proof of |
353 NONE => no_tac |
336 NONE => no_tac |
354 | SOME p => SOLVED' (resolve_tac ctxt [replay p]) 1 |
337 | SOME p => SOLVED' (resolve_tac ctxt [replay p]) 1 |
355 end |
338 end |
356 in |
339 in |
357 FIRST (map order_tac' part_prems) |
340 map (fn is => ` (env_of o hd) (map (nth decomp_prems) is) |> order_tac') env_groups |
|
341 |> FIRST |
358 end) |
342 end) |
359 |
343 |
360 val ad_absurdum_tac = SUBGOAL (fn (A, i) => |
344 val ad_absurdum_tac = SUBGOAL (fn (A, i) => |
361 case try (Logic_Sig.dest_Trueprop o Logic.strip_assums_concl) A of |
345 case try (Logic_Sig.dest_Trueprop o Logic.strip_assums_concl) A of |
362 SOME (nt $ _) => |
346 SOME (nt $ _) => |
363 if nt = Logic_Sig.Not |
347 if nt = Logic_Sig.Not |
364 then resolve0_tac [Logic_Sig.notI] i |
348 then resolve0_tac [Logic_Sig.notI] i |
365 else resolve0_tac [Logic_Sig.ccontr] i |
349 else resolve0_tac [Logic_Sig.ccontr] i |
366 | SOME _ => resolve0_tac [Logic_Sig.ccontr] i |
350 | _ => resolve0_tac [Logic_Sig.ccontr] i) |
367 | NONE => resolve0_tac [Logic_Sig.ccontr] i) |
|
368 |
351 |
369 fun tac raw_order_proc octxt simp_prems ctxt = |
352 fun tac raw_order_proc octxt simp_prems ctxt = |
370 EVERY' [ |
353 ad_absurdum_tac THEN' order_tac raw_order_proc octxt simp_prems ctxt |
371 ad_absurdum_tac, |
|
372 CONVERSION Thm.eta_conversion, |
|
373 order_tac raw_order_proc octxt simp_prems ctxt |
|
374 ] |
|
375 |
354 |
376 end |
355 end |
377 |
356 |
378 functor Order_Tac(structure Base_Tac : BASE_ORDER_TAC) = struct |
357 functor Order_Tac(structure Base_Tac : BASE_ORDER_TAC) = struct |
379 |
358 |