6 Proof methods for replaying SMT proofs. |
6 Proof methods for replaying SMT proofs. |
7 *) |
7 *) |
8 |
8 |
9 signature SMT_REPLAY_METHODS = |
9 signature SMT_REPLAY_METHODS = |
10 sig |
10 sig |
|
11 (*Printing*) |
11 val pretty_goal: Proof.context -> string -> string -> thm list -> term -> Pretty.T |
12 val pretty_goal: Proof.context -> string -> string -> thm list -> term -> Pretty.T |
12 val trace_goal: Proof.context -> string -> thm list -> term -> unit |
13 val trace_goal: Proof.context -> string -> thm list -> term -> unit |
13 val trace: Proof.context -> (unit -> string) -> unit |
14 val trace: Proof.context -> (unit -> string) -> unit |
14 |
15 |
|
16 (*Replaying*) |
15 val replay_error: Proof.context -> string -> string -> thm list -> term -> 'a |
17 val replay_error: Proof.context -> string -> string -> thm list -> term -> 'a |
16 val replay_rule_error: Proof.context -> string -> thm list -> term -> 'a |
18 val replay_rule_error: string -> Proof.context -> string -> thm list -> term -> 'a |
17 |
19 |
18 (*theory lemma methods*) |
20 (*theory lemma methods*) |
19 type th_lemma_method = Proof.context -> thm list -> term -> thm |
21 type th_lemma_method = Proof.context -> thm list -> term -> thm |
20 val add_th_lemma_method: string * th_lemma_method -> Context.generic -> |
22 val add_th_lemma_method: string * th_lemma_method -> Context.generic -> |
21 Context.generic |
23 Context.generic |
22 val get_th_lemma_method: Proof.context -> th_lemma_method Symtab.table |
24 val get_th_lemma_method: Proof.context -> th_lemma_method Symtab.table |
23 val discharge: int -> thm list -> thm -> thm |
25 val discharge: int -> thm list -> thm -> thm |
24 val match_instantiate: Proof.context -> term -> thm -> thm |
26 val match_instantiate: Proof.context -> term -> thm -> thm |
25 val prove: Proof.context -> term -> (Proof.context -> int -> tactic) -> thm |
27 val prove: Proof.context -> term -> (Proof.context -> int -> tactic) -> thm |
26 |
28 |
|
29 val prove_arith_rewrite: ((term -> int * term Termtab.table -> |
|
30 term * (int * term Termtab.table)) -> term -> int * term Termtab.table -> |
|
31 term * (int * term Termtab.table)) -> Proof.context -> term -> thm |
|
32 |
27 (*abstraction*) |
33 (*abstraction*) |
28 type abs_context = int * term Termtab.table |
34 type abs_context = int * term Termtab.table |
29 type 'a abstracter = term -> abs_context -> 'a * abs_context |
35 type 'a abstracter = term -> abs_context -> 'a * abs_context |
30 val add_arith_abstracter: (term abstracter -> term option abstracter) -> |
36 val add_arith_abstracter: (term abstracter -> term option abstracter) -> |
31 Context.generic -> Context.generic |
37 Context.generic -> Context.generic |
34 val abstract_conj: term -> abs_context -> term * abs_context |
40 val abstract_conj: term -> abs_context -> term * abs_context |
35 val abstract_disj: term -> abs_context -> term * abs_context |
41 val abstract_disj: term -> abs_context -> term * abs_context |
36 val abstract_not: (term -> abs_context -> term * abs_context) -> |
42 val abstract_not: (term -> abs_context -> term * abs_context) -> |
37 term -> abs_context -> term * abs_context |
43 term -> abs_context -> term * abs_context |
38 val abstract_unit: term -> abs_context -> term * abs_context |
44 val abstract_unit: term -> abs_context -> term * abs_context |
|
45 val abstract_bool: term -> abs_context -> term * abs_context |
|
46 (* also abstracts over equivalences and conjunction and implication*) |
|
47 val abstract_bool_shallow: term -> abs_context -> term * abs_context |
|
48 (* abstracts down to equivalence symbols *) |
|
49 val abstract_bool_shallow_equivalence: term -> abs_context -> term * abs_context |
39 val abstract_prop: term -> abs_context -> term * abs_context |
50 val abstract_prop: term -> abs_context -> term * abs_context |
40 val abstract_term: term -> abs_context -> term * abs_context |
51 val abstract_term: term -> abs_context -> term * abs_context |
|
52 val abstract_eq: (term -> int * term Termtab.table -> term * (int * term Termtab.table)) -> |
|
53 term -> int * term Termtab.table -> term * (int * term Termtab.table) |
|
54 val abstract_neq: (term -> int * term Termtab.table -> term * (int * term Termtab.table)) -> |
|
55 term -> int * term Termtab.table -> term * (int * term Termtab.table) |
41 val abstract_arith: Proof.context -> term -> abs_context -> term * abs_context |
56 val abstract_arith: Proof.context -> term -> abs_context -> term * abs_context |
|
57 (* also abstracts over if-then-else *) |
|
58 val abstract_arith_shallow: Proof.context -> term -> abs_context -> term * abs_context |
42 |
59 |
43 val prove_abstract: Proof.context -> thm list -> term -> |
60 val prove_abstract: Proof.context -> thm list -> term -> |
44 (Proof.context -> thm list -> int -> tactic) -> |
61 (Proof.context -> thm list -> int -> tactic) -> |
45 (abs_context -> (term list * term) * abs_context) -> thm |
62 (abs_context -> (term list * term) * abs_context) -> thm |
46 val prove_abstract': Proof.context -> term -> (Proof.context -> thm list -> int -> tactic) -> |
63 val prove_abstract': Proof.context -> term -> (Proof.context -> thm list -> int -> tactic) -> |
47 (abs_context -> term * abs_context) -> thm |
64 (abs_context -> term * abs_context) -> thm |
48 val try_provers: Proof.context -> string -> (string * (term -> 'a)) list -> thm list -> term -> |
65 val try_provers: string -> Proof.context -> string -> (string * (term -> 'a)) list -> thm list -> |
49 'a |
66 term -> 'a |
50 |
67 |
51 (*shared tactics*) |
68 (*shared tactics*) |
|
69 val cong_unfolding_trivial: Proof.context -> thm list -> term -> thm |
52 val cong_basic: Proof.context -> thm list -> term -> thm |
70 val cong_basic: Proof.context -> thm list -> term -> thm |
53 val cong_full: Proof.context -> thm list -> term -> thm |
71 val cong_full: Proof.context -> thm list -> term -> thm |
54 val cong_unfolding_first: Proof.context -> thm list -> term -> thm |
72 val cong_unfolding_first: Proof.context -> thm list -> term -> thm |
|
73 val arith_th_lemma: Proof.context -> thm list -> term -> thm |
|
74 val arith_th_lemma_wo: Proof.context -> thm list -> term -> thm |
|
75 val arith_th_lemma_wo_shallow: Proof.context -> thm list -> term -> thm |
|
76 val arith_th_lemma_tac_with_wo: Proof.context -> thm list -> int -> tactic |
|
77 |
|
78 val dest_thm: thm -> term |
|
79 val prop_tac: Proof.context -> thm list -> int -> tactic |
55 |
80 |
56 val certify_prop: Proof.context -> term -> cterm |
81 val certify_prop: Proof.context -> term -> cterm |
|
82 val dest_prop: term -> term |
57 |
83 |
58 end; |
84 end; |
59 |
85 |
60 structure SMT_Replay_Methods: SMT_REPLAY_METHODS = |
86 structure SMT_Replay_Methods: SMT_REPLAY_METHODS = |
61 struct |
87 struct |
265 | abstract_unit (t as (Const(\<^const_name>\<open>HOL.eq\<close>, _) $ t1 $ t2)) = |
291 | abstract_unit (t as (Const(\<^const_name>\<open>HOL.eq\<close>, _) $ t1 $ t2)) = |
266 if fastype_of t1 = \<^typ>\<open>bool\<close> then |
292 if fastype_of t1 = \<^typ>\<open>bool\<close> then |
267 abstract_sub t (abstract_unit t1 ##>> abstract_unit t2 #>> |
293 abstract_sub t (abstract_unit t1 ##>> abstract_unit t2 #>> |
268 HOLogic.mk_eq) |
294 HOLogic.mk_eq) |
269 else abstract_lit t |
295 else abstract_lit t |
270 | abstract_unit (t as (\<^const>\<open>HOL.Not\<close> $ Const(\<^const_name>\<open>HOL.eq\<close>, _) $ t1 $ t2)) = |
296 | abstract_unit (t as (\<^const>\<open>HOL.Not\<close> $ (Const(\<^const_name>\<open>HOL.eq\<close>, _) $ t1 $ t2))) = |
271 if fastype_of t1 = \<^typ>\<open>bool\<close> then |
297 if fastype_of t1 = \<^typ>\<open>bool\<close> then |
272 abstract_sub t (abstract_unit t1 ##>> abstract_unit t2 #>> |
298 abstract_sub t (abstract_unit t1 ##>> abstract_unit t2 #>> |
273 HOLogic.mk_eq #>> HOLogic.mk_not) |
299 HOLogic.mk_eq #>> HOLogic.mk_not) |
274 else abstract_lit t |
300 else abstract_lit t |
275 | abstract_unit (t as (\<^const>\<open>HOL.Not\<close> $ t1)) = |
301 | abstract_unit (t as (\<^const>\<open>HOL.Not\<close> $ t1)) = |
276 abstract_sub t (abstract_unit t1 #>> HOLogic.mk_not) |
302 abstract_sub t (abstract_unit t1 #>> HOLogic.mk_not) |
277 | abstract_unit t = abstract_lit t |
303 | abstract_unit t = abstract_lit t |
278 |
304 |
|
305 fun abstract_bool (t as (@{const HOL.disj} $ t1 $ t2)) = |
|
306 abstract_sub t (abstract_bool t1 ##>> abstract_bool t2 #>> |
|
307 HOLogic.mk_disj) |
|
308 | abstract_bool (t as (@{const HOL.conj} $ t1 $ t2)) = |
|
309 abstract_sub t (abstract_bool t1 ##>> abstract_bool t2 #>> |
|
310 HOLogic.mk_conj) |
|
311 | abstract_bool (t as (Const(@{const_name HOL.eq}, _) $ t1 $ t2)) = |
|
312 if fastype_of t1 = @{typ bool} then |
|
313 abstract_sub t (abstract_bool t1 ##>> abstract_bool t2 #>> |
|
314 HOLogic.mk_eq) |
|
315 else abstract_lit t |
|
316 | abstract_bool (t as (@{const HOL.Not} $ t1)) = |
|
317 abstract_sub t (abstract_bool t1 #>> HOLogic.mk_not) |
|
318 | abstract_bool (t as (@{const HOL.implies} $ t1 $ t2)) = |
|
319 abstract_sub t (abstract_bool t1 ##>> abstract_bool t2 #>> |
|
320 HOLogic.mk_imp) |
|
321 | abstract_bool t = abstract_lit t |
|
322 |
|
323 fun abstract_bool_shallow (t as (@{const HOL.disj} $ t1 $ t2)) = |
|
324 abstract_sub t (abstract_bool_shallow t1 ##>> abstract_bool_shallow t2 #>> |
|
325 HOLogic.mk_disj) |
|
326 | abstract_bool_shallow (t as (@{const HOL.Not} $ t1)) = |
|
327 abstract_sub t (abstract_bool_shallow t1 #>> HOLogic.mk_not) |
|
328 | abstract_bool_shallow t = abstract_term t |
|
329 |
|
330 fun abstract_bool_shallow_equivalence (t as (@{const HOL.disj} $ t1 $ t2)) = |
|
331 abstract_sub t (abstract_bool_shallow_equivalence t1 ##>> abstract_bool_shallow_equivalence t2 #>> |
|
332 HOLogic.mk_disj) |
|
333 | abstract_bool_shallow_equivalence (t as (Const(@{const_name HOL.eq}, _) $ t1 $ t2)) = |
|
334 if fastype_of t1 = @{typ bool} then |
|
335 abstract_sub t (abstract_lit t1 ##>> abstract_lit t2 #>> |
|
336 HOLogic.mk_eq) |
|
337 else abstract_lit t |
|
338 | abstract_bool_shallow_equivalence (t as (@{const HOL.Not} $ t1)) = |
|
339 abstract_sub t (abstract_bool_shallow_equivalence t1 #>> HOLogic.mk_not) |
|
340 | abstract_bool_shallow_equivalence t = abstract_lit t |
|
341 |
|
342 fun abstract_arith_shallow ctxt u = |
|
343 let |
|
344 fun abs (t as (Const (\<^const_name>\<open>HOL.The\<close>, _) $ Abs (_, _, _))) = |
|
345 abstract_sub t (abstract_term t) |
|
346 | abs (t as (c as Const _) $ Abs (s, T, t')) = |
|
347 abstract_sub t (abs t' #>> (fn u' => c $ Abs (s, T, u'))) |
|
348 | abs (t as (Const (\<^const_name>\<open>If\<close>, _)) $ _ $ _ $ _) = |
|
349 abstract_sub t (abstract_term t) |
|
350 | abs (t as \<^const>\<open>HOL.Not\<close> $ t1) = abstract_sub t (abs t1 #>> HOLogic.mk_not) |
|
351 | abs (t as \<^const>\<open>HOL.disj\<close> $ t1 $ t2) = |
|
352 abstract_sub t (abs t1 ##>> abs t2 #>> HOLogic.mk_disj) |
|
353 | abs (t as (c as Const (\<^const_name>\<open>uminus_class.uminus\<close>, _)) $ t1) = |
|
354 abstract_sub t (abs t1 #>> (fn u => c $ u)) |
|
355 | abs (t as (c as Const (\<^const_name>\<open>plus_class.plus\<close>, _)) $ t1 $ t2) = |
|
356 abstract_sub t (abs t1 ##>> abs t2 #>> (fn (u1, u2) => c $ u1 $ u2)) |
|
357 | abs (t as (c as Const (\<^const_name>\<open>minus_class.minus\<close>, _)) $ t1 $ t2) = |
|
358 abstract_sub t (abs t1 ##>> abs t2 #>> (fn (u1, u2) => c $ u1 $ u2)) |
|
359 | abs (t as (c as Const (\<^const_name>\<open>times_class.times\<close>, _)) $ t1 $ t2) = |
|
360 abstract_sub t (abs t1 ##>> abs t2 #>> (fn (u1, u2) => c $ u1 $ u2)) |
|
361 | abs (t as (Const (\<^const_name>\<open>z3div\<close>, _)) $ _ $ _) = |
|
362 abstract_sub t (abstract_term t) |
|
363 | abs (t as (Const (\<^const_name>\<open>z3mod\<close>, _)) $ _ $ _) = |
|
364 abstract_sub t (abstract_term t) |
|
365 | abs (t as (c as Const (\<^const_name>\<open>HOL.eq\<close>, _)) $ t1 $ t2) = |
|
366 abstract_sub t (abs t1 ##>> abs t2 #>> (fn (u1, u2) => c $ u1 $ u2)) |
|
367 | abs (t as (c as Const (\<^const_name>\<open>ord_class.less\<close>, _)) $ t1 $ t2) = |
|
368 abstract_sub t (abs t1 ##>> abs t2 #>> (fn (u1, u2) => c $ u1 $ u2)) |
|
369 | abs (t as (c as Const (\<^const_name>\<open>ord_class.less_eq\<close>, _)) $ t1 $ t2) = |
|
370 abstract_sub t (abs t1 ##>> abs t2 #>> (fn (u1, u2) => c $ u1 $ u2)) |
|
371 | abs t = abstract_sub t (fn cx => |
|
372 if can HOLogic.dest_number t then (t, cx) |
|
373 else |
|
374 (case apply_abstracters abs (get_arith_abstracters ctxt) t cx of |
|
375 (SOME u, cx') => (u, cx') |
|
376 | (NONE, _) => abstract_term t cx)) |
|
377 in abs u end |
279 |
378 |
280 (* theory lemmas *) |
379 (* theory lemmas *) |
281 |
380 |
282 fun try_provers ctxt rule [] thms t = replay_rule_error ctxt rule thms t |
381 fun try_provers prover_name ctxt rule [] thms t = replay_rule_error prover_name ctxt rule thms t |
283 | try_provers ctxt rule ((name, prover) :: named_provers) thms t = |
382 | try_provers prover_name ctxt rule ((name, prover) :: named_provers) thms t = |
284 (case (trace ctxt (K ("Trying prover " ^ quote name)); try prover t) of |
383 (case (trace ctxt (K ("Trying prover " ^ quote name)); try prover t) of |
285 SOME thm => thm |
384 SOME thm => thm |
286 | NONE => try_provers ctxt rule named_provers thms t) |
385 | NONE => try_provers prover_name ctxt rule named_provers thms t) |
|
386 |
|
387 (*theory-lemma*) |
|
388 |
|
389 fun arith_th_lemma_tac ctxt prems = |
|
390 Method.insert_tac ctxt prems |
|
391 THEN' SELECT_GOAL (Local_Defs.unfold0_tac ctxt @{thms z3div_def z3mod_def}) |
|
392 THEN' Arith_Data.arith_tac ctxt |
|
393 |
|
394 fun arith_th_lemma ctxt thms t = |
|
395 prove_abstract ctxt thms t arith_th_lemma_tac ( |
|
396 fold_map (abstract_arith ctxt o dest_thm) thms ##>> |
|
397 abstract_arith ctxt (dest_prop t)) |
|
398 |
|
399 fun arith_th_lemma_tac_with_wo ctxt prems = |
|
400 Method.insert_tac ctxt prems |
|
401 THEN' SELECT_GOAL (Local_Defs.unfold0_tac ctxt @{thms z3div_def z3mod_def int_distrib}) |
|
402 THEN' Simplifier.asm_full_simp_tac |
|
403 (empty_simpset ctxt addsimprocs [(*@{simproc linordered_ring_strict_eq_cancel_factor_poly}, |
|
404 @{simproc linordered_ring_strict_le_cancel_factor_poly}, |
|
405 @{simproc linordered_ring_strict_less_cancel_factor_poly}, |
|
406 @{simproc nat_eq_cancel_factor_poly}, |
|
407 @{simproc nat_le_cancel_factor_poly}, |
|
408 @{simproc nat_less_cancel_factor_poly}*)]) |
|
409 THEN' (fn i => TRY (Arith_Data.arith_tac ctxt i)) |
|
410 |
|
411 fun arith_th_lemma_wo ctxt thms t = |
|
412 prove_abstract ctxt thms t arith_th_lemma_tac_with_wo ( |
|
413 fold_map (abstract_arith ctxt o dest_thm) thms ##>> |
|
414 abstract_arith ctxt (dest_prop t)) |
|
415 |
|
416 fun arith_th_lemma_wo_shallow ctxt thms t = |
|
417 prove_abstract ctxt thms t arith_th_lemma_tac_with_wo ( |
|
418 fold_map (abstract_arith_shallow ctxt o dest_thm) thms ##>> |
|
419 abstract_arith_shallow ctxt (dest_prop t)) |
|
420 |
|
421 val _ = Theory.setup (Context.theory_map (add_th_lemma_method ("arith", arith_th_lemma))) |
287 |
422 |
288 |
423 |
289 (* congruence *) |
424 (* congruence *) |
290 |
425 |
291 fun certify_prop ctxt t = Thm.cterm_of ctxt (as_prop t) |
426 fun certify_prop ctxt t = Thm.cterm_of ctxt (as_prop t) |
316 Method.insert_tac ctxt thms |
451 Method.insert_tac ctxt thms |
317 THEN' (cong_full_core_tac ctxt' |
452 THEN' (cong_full_core_tac ctxt' |
318 ORELSE' dresolve_tac ctxt cong_dest_rules |
453 ORELSE' dresolve_tac ctxt cong_dest_rules |
319 THEN' cong_full_core_tac ctxt')) |
454 THEN' cong_full_core_tac ctxt')) |
320 |
455 |
|
456 local |
|
457 val reorder_for_simp = try (fn thm => |
|
458 let val t = Thm.prop_of (@{thm eq_reflection} OF [thm]) |
|
459 val thm = |
|
460 (case Logic.dest_equals t of |
|
461 (t1, t2) => |
|
462 if t1 aconv t2 then raise TERM("identical terms", [t1, t2]) |
|
463 else if Term.size_of_term t1 > Term.size_of_term t2 then @{thm eq_reflection} OF [thm] |
|
464 else @{thm eq_reflection} OF [@{thm sym} OF [thm]]) |
|
465 handle TERM("dest_equals", _) => @{thm eq_reflection} OF [thm] |
|
466 in thm end) |
|
467 in |
|
468 fun cong_unfolding_trivial ctxt thms t = |
|
469 prove ctxt t (fn _ => |
|
470 EVERY' (map (fn thm => K (unfold_tac ctxt [thm])) ((map_filter reorder_for_simp thms))) |
|
471 THEN' (fn i => TRY (resolve_tac ctxt @{thms refl} i))) |
|
472 |
321 fun cong_unfolding_first ctxt thms t = |
473 fun cong_unfolding_first ctxt thms t = |
322 let val reorder_for_simp = try (fn thm => |
474 let val ctxt = |
323 let val t = Thm.prop_of ( @{thm eq_reflection} OF [thm]) |
475 ctxt |
324 val thm = (case Logic.dest_equals t of |
476 |> empty_simpset |
325 (t1, t2) => if Term.size_of_term t1 > Term.size_of_term t2 then @{thm eq_reflection} OF [thm] |
477 |> put_simpset HOL_basic_ss |
326 else @{thm eq_reflection} OF [thm OF @{thms sym}]) |
478 |> (fn ctxt => ctxt addsimps @{thms not_not eq_commute}) |
327 handle TERM("dest_equals", _) => @{thm eq_reflection} OF [thm] |
|
328 in thm end) |
|
329 in |
479 in |
330 prove ctxt t (fn ctxt => |
480 prove ctxt t (fn _ => |
331 Raw_Simplifier.rewrite_goal_tac ctxt |
481 EVERY' (map (fn thm => K (unfold_tac ctxt [thm])) ((map_filter reorder_for_simp thms))) |
332 (map_filter reorder_for_simp thms) |
|
333 THEN' Method.insert_tac ctxt thms |
482 THEN' Method.insert_tac ctxt thms |
334 THEN' K (Clasimp.auto_tac ctxt)) |
483 THEN' (full_simp_tac ctxt) |
|
484 THEN' K (ALLGOALS (K (Clasimp.auto_tac ctxt)))) |
335 end |
485 end |
336 |
486 |
|
487 end |
|
488 |
|
489 |
|
490 fun arith_rewrite_tac ctxt _ = |
|
491 let val backup_tac = Arith_Data.arith_tac ctxt ORELSE' Clasimp.force_tac ctxt in |
|
492 (TRY o Simplifier.simp_tac ctxt) THEN_ALL_NEW backup_tac |
|
493 ORELSE' backup_tac |
|
494 end |
|
495 |
|
496 fun abstract_eq f (Const (\<^const_name>\<open>HOL.eq\<close>, _) $ t1 $ t2) = |
|
497 f t1 ##>> f t2 #>> HOLogic.mk_eq |
|
498 | abstract_eq _ t = abstract_term t |
|
499 |
|
500 fun abstract_neq f (Const (\<^const_name>\<open>HOL.eq\<close>, _) $ t1 $ t2) = |
|
501 f t1 ##>> f t2 #>> HOLogic.mk_eq |
|
502 | abstract_neq f (Const (\<^const_name>\<open>HOL.Not\<close>, _) $ (Const (\<^const_name>\<open>HOL.eq\<close>, _) $ t1 $ t2)) = |
|
503 f t1 ##>> f t2 #>> HOLogic.mk_eq #>> curry (op $) HOLogic.Not |
|
504 | abstract_neq f (Const (\<^const_name>\<open>HOL.disj\<close>, _) $ t1 $ t2) = |
|
505 f t1 ##>> f t2 #>> HOLogic.mk_disj |
|
506 | abstract_neq _ t = abstract_term t |
|
507 |
|
508 fun prove_arith_rewrite abstracter ctxt t = |
|
509 prove_abstract' ctxt t arith_rewrite_tac ( |
|
510 abstracter (abstract_arith ctxt) (dest_prop t)) |
|
511 |
|
512 fun prop_tac ctxt prems = |
|
513 Method.insert_tac ctxt prems |
|
514 THEN' SUBGOAL (fn (prop, i) => |
|
515 if Term.size_of_term prop > 100 then SAT.satx_tac ctxt i |
|
516 else (Classical.fast_tac ctxt ORELSE' Clasimp.force_tac ctxt) i) |
|
517 |
337 end; |
518 end; |