more efficient Z3 proof reconstruction for rewrite steps with conjunctions and disjunctions, similar to Old_SMT
authorboehmes
Fri, 16 Jan 2015 23:23:31 +0100
changeset 59381 de4218223e00
parent 59379 c7f6f01ede15
child 59382 a78e71fcd146
more efficient Z3 proof reconstruction for rewrite steps with conjunctions and disjunctions, similar to Old_SMT
src/HOL/SMT.thy
src/HOL/Tools/SMT/conj_disj_perm.ML
src/HOL/Tools/SMT/z3_replay.ML
src/HOL/Tools/SMT/z3_replay_literals.ML
src/HOL/Tools/SMT/z3_replay_methods.ML
--- a/src/HOL/SMT.thy	Thu Jan 15 13:39:41 2015 +0100
+++ b/src/HOL/SMT.thy	Fri Jan 16 23:23:31 2015 +0100
@@ -163,9 +163,9 @@
 ML_file "Tools/SMT/verit_proof.ML"
 ML_file "Tools/SMT/verit_isar.ML"
 ML_file "Tools/SMT/verit_proof_parse.ML"
+ML_file "Tools/SMT/conj_disj_perm.ML"
 ML_file "Tools/SMT/z3_interface.ML"
 ML_file "Tools/SMT/z3_replay_util.ML"
-ML_file "Tools/SMT/z3_replay_literals.ML"
 ML_file "Tools/SMT/z3_replay_rules.ML"
 ML_file "Tools/SMT/z3_replay_methods.ML"
 ML_file "Tools/SMT/z3_replay.ML"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Tools/SMT/conj_disj_perm.ML	Fri Jan 16 23:23:31 2015 +0100
@@ -0,0 +1,127 @@
+(*  Title:      HOL/Tools/SMT/conj_disj_perm.ML
+    Author:     Sascha Boehme, TU Muenchen
+
+Tactic to prove equivalence of permutations of conjunctions and disjunctions.
+*)
+
+signature CONJ_DISJ_PERM =
+sig
+  val conj_disj_perm_tac: int -> tactic
+end
+
+structure Conj_Disj_Perm: CONJ_DISJ_PERM =
+struct
+
+fun with_assumption ct f =
+  let val ct' = Thm.apply @{cterm HOL.Trueprop} ct
+  in Thm.implies_intr ct' (f (Thm.assume ct')) end
+
+fun eq_from_impls thm1 thm2 = thm2 INCR_COMP (thm1 INCR_COMP @{thm iffI})
+
+fun add_lit thm = Termtab.update (HOLogic.dest_Trueprop (Thm.prop_of thm), thm)
+
+val ndisj1_rule = @{lemma "~(P | Q) ==> ~P" by auto}
+val ndisj2_rule = @{lemma "~(P | Q) ==> ~Q" by auto}
+
+fun explode_thm thm =
+  (case HOLogic.dest_Trueprop (Thm.prop_of thm) of
+    @{const HOL.conj} $ _ $ _ => explode_conj_thm @{thm conjunct1} @{thm conjunct2} thm
+  | @{const HOL.Not} $ (@{const HOL.disj} $ _ $ _) => explode_conj_thm ndisj1_rule ndisj2_rule thm
+  | @{const HOL.Not} $ (@{const HOL.Not} $ _) => explode_thm (thm RS @{thm notnotD})
+  | _ => add_lit thm)
+
+and explode_conj_thm rule1 rule2 thm lits =
+  explode_thm (thm RS rule1) (explode_thm (thm RS rule2) (add_lit thm lits))
+
+val not_false_rule = @{lemma "~False" by auto}
+fun explode thm = explode_thm thm (add_lit not_false_rule (add_lit @{thm TrueI} Termtab.empty))
+
+fun find_dual_lit lits (@{const HOL.Not} $ t, thm) = Termtab.lookup lits t |> Option.map (pair thm)
+  | find_dual_lit _ _ = NONE
+
+fun find_dual_lits lits = Termtab.get_first (find_dual_lit lits) lits
+
+val not_not_rule = @{lemma "P ==> ~~P" by auto}
+val ndisj_rule = @{lemma "~P ==> ~Q ==> ~(P | Q)" by auto}
+
+fun join lits t =
+  (case Termtab.lookup lits t of
+    SOME thm => thm
+  | NONE => join_term lits t)
+
+and join_term lits (@{const HOL.conj} $ t $ u) = @{thm conjI} OF (map (join lits) [t, u])
+  | join_term lits (@{const HOL.Not} $ (@{const HOL.disj} $ t $ u)) =
+      ndisj_rule OF (map (join lits o HOLogic.mk_not) [t, u])
+  | join_term lits (@{const HOL.Not} $ (@{const HOL.Not} $ t)) = join lits t RS not_not_rule
+  | join_term _ t = raise TERM ("join_term", [t])
+
+fun prove_conj_disj_imp ct cu = with_assumption ct (fn thm => join (explode thm) (Thm.term_of cu))
+
+fun prove_conj_disj_eq (clhs, crhs) =
+  let
+    val thm1 = prove_conj_disj_imp clhs crhs
+    val thm2 = prove_conj_disj_imp crhs clhs
+  in eq_from_impls thm1 thm2 end
+
+val not_not_false_rule = @{lemma "~~False ==> P" by auto}
+val not_true_rule = @{lemma "~True ==> P" by auto}
+
+fun prove_any_imp ct =
+  (case Thm.term_of ct of
+    @{const HOL.False} => @{thm FalseE}
+  | @{const HOL.Not} $ (@{const HOL.Not} $ @{const HOL.False}) => not_not_false_rule
+  | @{const HOL.Not} $ @{const HOL.True} => not_true_rule
+  | _ => raise CTERM ("prove_any_imp", [ct]))
+
+fun prove_contradiction_imp ct =
+  with_assumption ct (fn thm =>
+    let val lits = explode thm
+    in
+      (case Termtab.lookup lits @{const HOL.False} of
+        SOME thm' => thm' RS @{thm FalseE}
+      | NONE =>
+          (case Termtab.lookup lits (@{const HOL.Not} $ @{const HOL.True}) of
+            SOME thm' => thm' RS not_true_rule
+          | NONE =>
+              (case find_dual_lits lits of
+                SOME (not_lit_thm, lit_thm) => @{thm notE} OF [not_lit_thm, lit_thm]
+              | NONE => raise CTERM ("prove_contradiction", [ct]))))
+    end)
+
+fun prove_contradiction_eq to_right (clhs, crhs) =
+  let
+    val thm1 = if to_right then prove_contradiction_imp clhs else prove_any_imp clhs
+    val thm2 = if to_right then prove_any_imp crhs else prove_contradiction_imp crhs
+  in eq_from_impls thm1 thm2 end
+
+val contrapos_rule = @{lemma "(~P) = (~Q) ==> P = Q" by auto}
+fun contrapos prove cp = contrapos_rule OF [prove (apply2 (Thm.apply @{cterm HOL.Not}) cp)]
+
+datatype kind = True | False | Conj | Disj | Other
+
+fun choose t _ _ _ @{const HOL.True} = t
+  | choose _ f _ _ @{const HOL.False} = f
+  | choose _ _ c _ (@{const HOL.conj} $ _ $ _) = c
+  | choose _ _ _ d (@{const HOL.disj} $ _ $ _) = d
+  | choose _ _ _ _ _ = Other
+
+fun kind_of (@{const HOL.Not} $ t) = choose False True Disj Conj t
+  | kind_of t = choose True False Conj Disj t
+
+fun prove_conj_disj_perm ct cp =
+  (case apply2 (kind_of o Thm.term_of) cp of
+    (Conj, Conj) => prove_conj_disj_eq cp
+  | (Disj, Disj) => contrapos prove_conj_disj_eq cp
+  | (Conj, False) => prove_contradiction_eq true cp
+  | (False, Conj) => prove_contradiction_eq false cp
+  | (Disj, True) => contrapos (prove_contradiction_eq true) cp
+  | (True, Disj) => contrapos (prove_contradiction_eq false) cp
+  | _ => raise CTERM ("prove_conj_disj_perm", [ct]))
+
+val conj_disj_perm_tac = CSUBGOAL (fn (ct, i) => 
+  (case Thm.term_of ct of
+    @{const HOL.Trueprop} $ (@{const HOL.eq(bool)} $ _ $ _) =>
+      rtac (prove_conj_disj_perm ct (Thm.dest_binop (Thm.dest_arg ct))) i
+  | _ => no_tac))
+
+end
--- a/src/HOL/Tools/SMT/z3_replay.ML	Thu Jan 15 13:39:41 2015 +0100
+++ b/src/HOL/Tools/SMT/z3_replay.ML	Fri Jan 16 23:23:31 2015 +0100
@@ -83,7 +83,8 @@
   fun rewrite_conv _ [] = Conv.all_conv
     | rewrite_conv ctxt eqs = Simplifier.full_rewrite (empty_simpset ctxt addsimps eqs)
 
-  val prep_rules = [@{thm Let_def}, remove_trigger, remove_fun_app, Z3_Replay_Literals.rewrite_true]
+  val rewrite_true_rule = @{lemma "True == ~ False" by simp}
+  val prep_rules = [@{thm Let_def}, remove_trigger, remove_fun_app, rewrite_true_rule]
 
   fun rewrite _ [] = I
     | rewrite ctxt eqs = Conv.fconv_rule (rewrite_conv ctxt eqs)
@@ -95,7 +96,7 @@
 
 fun add_asserted outer_ctxt rewrite_rules assms steps ctxt =
   let
-    val eqs = map (rewrite ctxt [Z3_Replay_Literals.rewrite_true]) rewrite_rules
+    val eqs = map (rewrite ctxt [rewrite_true_rule]) rewrite_rules
     val eqs' = union Thm.eq_thm eqs prep_rules
 
     val assms_net =
@@ -154,8 +155,8 @@
 
 end
 
-fun make_discharge_rules rules = rules @ [@{thm allI}, @{thm refl}, @{thm reflexive},
-  Z3_Replay_Literals.true_thm]
+val true_thm = @{lemma "~False" by simp}
+fun make_discharge_rules rules = rules @ [@{thm allI}, @{thm refl}, @{thm reflexive}, true_thm]
 
 val intro_def_rules = @{lemma
   "(~ P | P) & (P | ~ P)"
--- a/src/HOL/Tools/SMT/z3_replay_literals.ML	Thu Jan 15 13:39:41 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,351 +0,0 @@
-(*  Title:      HOL/Tools/SMT/z3_replay_literals.ML
-    Author:     Sascha Boehme, TU Muenchen
-
-Proof tools related to conjunctions and disjunctions.
-*)
-
-signature Z3_REPLAY_LITERALS =
-sig
-  (*literal table*)
-  type littab = thm Termtab.table
-  val make_littab: thm list -> littab
-  val insert_lit: thm -> littab -> littab
-  val delete_lit: thm -> littab -> littab
-  val lookup_lit: littab -> term -> thm option
-  val get_first_lit: (term -> bool) -> littab -> thm option
-
-  (*rules*)
-  val true_thm: thm
-  val rewrite_true: thm
-
-  (*properties*)
-  val is_conj: term -> bool
-  val is_disj: term -> bool
-  val exists_lit: bool -> (term -> bool) -> term -> bool
-  val negate: cterm -> cterm
-
-  (*proof tools*)
-  val explode: bool -> bool -> bool -> term list -> thm -> thm list
-  val join: bool -> littab -> term -> thm
-  val prove_conj_disj_eq: cterm -> thm
-end;
-
-structure Z3_Replay_Literals: Z3_REPLAY_LITERALS =
-struct
-
-(* literal table *)
-
-type littab = thm Termtab.table
-
-fun make_littab thms = fold (Termtab.update o `SMT_Util.prop_of) thms Termtab.empty
-
-fun insert_lit thm = Termtab.update (`SMT_Util.prop_of thm)
-fun delete_lit thm = Termtab.delete (SMT_Util.prop_of thm)
-fun lookup_lit lits = Termtab.lookup lits
-fun get_first_lit f =
-  Termtab.get_first (fn (t, thm) => if f t then SOME thm else NONE)
-
-
-(* rules *)
-
-val true_thm = @{lemma "~False" by simp}
-val rewrite_true = @{lemma "True == ~ False" by simp}
-
-
-(* properties and term operations *)
-
-val is_neg = (fn @{const Not} $ _ => true | _ => false)
-fun is_neg' f = (fn @{const Not} $ t => f t | _ => false)
-val is_dneg = is_neg' is_neg
-val is_conj = (fn @{const HOL.conj} $ _ $ _ => true | _ => false)
-val is_disj = (fn @{const HOL.disj} $ _ $ _ => true | _ => false)
-
-fun dest_disj_term' f = (fn
-    @{const Not} $ (@{const HOL.disj} $ t $ u) => SOME (f t, f u)
-  | _ => NONE)
-
-val dest_conj_term = (fn @{const HOL.conj} $ t $ u => SOME (t, u) | _ => NONE)
-val dest_disj_term =
-  dest_disj_term' (fn @{const Not} $ t => t | t => @{const Not} $ t)
-
-fun exists_lit is_conj P =
-  let
-    val dest = if is_conj then dest_conj_term else dest_disj_term
-    fun exists t = P t orelse
-      (case dest t of
-        SOME (t1, t2) => exists t1 orelse exists t2
-      | NONE => false)
-  in exists end
-
-val negate = Thm.apply (Thm.cterm_of @{theory} @{const Not})
-
-
-(* proof tools *)
-
-(** explosion of conjunctions and disjunctions **)
-
-local
-  val precomp = Z3_Replay_Util.precompose2
-
-  fun destc ct = Thm.dest_binop (Thm.dest_arg ct)
-  val dest_conj1 = precomp destc @{thm conjunct1}
-  val dest_conj2 = precomp destc @{thm conjunct2}
-  fun dest_conj_rules t =
-    dest_conj_term t |> Option.map (K (dest_conj1, dest_conj2))
-
-  fun destd f ct = f (Thm.dest_binop (Thm.dest_arg (Thm.dest_arg ct)))
-  val dn1 = apfst Thm.dest_arg and dn2 = apsnd Thm.dest_arg
-  val dest_disj1 = precomp (destd I) @{lemma "~(P | Q) ==> ~P" by fast}
-  val dest_disj2 = precomp (destd dn1) @{lemma "~(~P | Q) ==> P" by fast}
-  val dest_disj3 = precomp (destd I) @{lemma "~(P | Q) ==> ~Q" by fast}
-  val dest_disj4 = precomp (destd dn2) @{lemma "~(P | ~Q) ==> Q" by fast}
-
-  fun dest_disj_rules t =
-    (case dest_disj_term' is_neg t of
-      SOME (true, true) => SOME (dest_disj2, dest_disj4)
-    | SOME (true, false) => SOME (dest_disj2, dest_disj3)
-    | SOME (false, true) => SOME (dest_disj1, dest_disj4)
-    | SOME (false, false) => SOME (dest_disj1, dest_disj3)
-    | NONE => NONE)
-
-  fun destn ct = [Thm.dest_arg (Thm.dest_arg (Thm.dest_arg ct))]
-  val dneg_rule = Z3_Replay_Util.precompose destn @{thm notnotD}
-in
-
-(*
-  explode a term into literals and collect all rules to be able to deduce
-  particular literals afterwards
-*)
-fun explode_term is_conj =
-  let
-    val dest = if is_conj then dest_conj_term else dest_disj_term
-    val dest_rules = if is_conj then dest_conj_rules else dest_disj_rules
-
-    fun add (t, rs) = Termtab.map_default (t, rs)
-      (fn rs' => if length rs' < length rs then rs' else rs)
-
-    fun explode1 rules t =
-      (case dest t of
-        SOME (t1, t2) =>
-          let val (rule1, rule2) = the (dest_rules t)
-          in
-            explode1 (rule1 :: rules) t1 #>
-            explode1 (rule2 :: rules) t2 #>
-            add (t, rev rules)
-          end
-      | NONE => add (t, rev rules))
-
-    fun explode0 (@{const Not} $ (@{const Not} $ t)) =
-          Termtab.make [(t, [dneg_rule])]
-      | explode0 t = explode1 [] t Termtab.empty
-
-  in explode0 end
-
-(*
-  extract a literal by applying previously collected rules
-*)
-fun extract_lit thm rules = fold Z3_Replay_Util.compose rules thm
-
-
-(*
-  explode a theorem into its literals
-*)
-fun explode is_conj full keep_intermediate stop_lits =
-  let
-    val dest_rules = if is_conj then dest_conj_rules else dest_disj_rules
-    val tab = fold (Termtab.update o rpair ()) stop_lits Termtab.empty
-
-    fun explode1 thm =
-      if Termtab.defined tab (SMT_Util.prop_of thm) then cons thm
-      else
-        (case dest_rules (SMT_Util.prop_of thm) of
-          SOME (rule1, rule2) =>
-            explode2 rule1 thm #>
-            explode2 rule2 thm #>
-            keep_intermediate ? cons thm
-        | NONE => cons thm)
-
-    and explode2 dest_rule thm =
-      if full orelse
-        exists_lit is_conj (Termtab.defined tab) (SMT_Util.prop_of thm)
-      then explode1 (Z3_Replay_Util.compose dest_rule thm)
-      else cons (Z3_Replay_Util.compose dest_rule thm)
-
-    fun explode0 thm =
-      if not is_conj andalso is_dneg (SMT_Util.prop_of thm)
-      then [Z3_Replay_Util.compose dneg_rule thm]
-      else explode1 thm []
-
-  in explode0 end
-
-end
-
-
-(** joining of literals to conjunctions or disjunctions **)
-
-local
-  fun on_cprem i f thm = f (Thm.cprem_of thm i)
-  fun on_cprop f thm = f (Thm.cprop_of thm)
-  fun precomp2 f g thm = (on_cprem 1 f thm, on_cprem 2 g thm, f, g, thm)
-  fun comp2 (cv1, cv2, f, g, rule) thm1 thm2 =
-    Thm.instantiate ([], [(cv1, on_cprop f thm1), (cv2, on_cprop g thm2)]) rule
-    |> Z3_Replay_Util.discharge thm1 |> Z3_Replay_Util.discharge thm2
-
-  fun d1 ct = Thm.dest_arg ct and d2 ct = Thm.dest_arg (Thm.dest_arg ct)
-
-  val conj_rule = precomp2 d1 d1 @{thm conjI}
-  fun comp_conj ((_, thm1), (_, thm2)) = comp2 conj_rule thm1 thm2
-
-  val disj1 = precomp2 d2 d2 @{lemma "~P ==> ~Q ==> ~(P | Q)" by fast}
-  val disj2 = precomp2 d2 d1 @{lemma "~P ==> Q ==> ~(P | ~Q)" by fast}
-  val disj3 = precomp2 d1 d2 @{lemma "P ==> ~Q ==> ~(~P | Q)" by fast}
-  val disj4 = precomp2 d1 d1 @{lemma "P ==> Q ==> ~(~P | ~Q)" by fast}
-
-  fun comp_disj ((false, thm1), (false, thm2)) = comp2 disj1 thm1 thm2
-    | comp_disj ((false, thm1), (true, thm2)) = comp2 disj2 thm1 thm2
-    | comp_disj ((true, thm1), (false, thm2)) = comp2 disj3 thm1 thm2
-    | comp_disj ((true, thm1), (true, thm2)) = comp2 disj4 thm1 thm2
-
-  fun dest_conj (@{const HOL.conj} $ t $ u) = ((false, t), (false, u))
-    | dest_conj t = raise TERM ("dest_conj", [t])
-
-  val neg = (fn @{const Not} $ t => (true, t) | t => (false, @{const Not} $ t))
-  fun dest_disj (@{const Not} $ (@{const HOL.disj} $ t $ u)) = (neg t, neg u)
-    | dest_disj t = raise TERM ("dest_disj", [t])
-
-  val precomp = Z3_Replay_Util.precompose
-  val dnegE = precomp (single o d2 o d1) @{thm notnotD}
-  val dnegI = precomp (single o d1) @{lemma "P ==> ~~P" by fast}
-  fun as_dneg f t = f (@{const Not} $ (@{const Not} $ t))
-
-  val precomp2 = Z3_Replay_Util.precompose2
-  fun dni f = apsnd f o Thm.dest_binop o f o d1
-  val negIffE = precomp2 (dni d1) @{lemma "~(P = (~Q)) ==> Q = P" by fast}
-  val negIffI = precomp2 (dni I) @{lemma "P = Q ==> ~(Q = (~P))" by fast}
-  val iff_const = @{const HOL.eq (bool)}
-  fun as_negIff f (@{const HOL.eq (bool)} $ t $ u) =
-        f (@{const Not} $ (iff_const $ u $ (@{const Not} $ t)))
-    | as_negIff _ _ = NONE
-in
-
-fun join is_conj littab t =
-  let
-    val comp = if is_conj then comp_conj else comp_disj
-    val dest = if is_conj then dest_conj else dest_disj
-
-    val lookup = lookup_lit littab
-
-    fun lookup_rule t =
-      (case t of
-        @{const Not} $ (@{const Not} $ t) => (Z3_Replay_Util.compose dnegI, lookup t)
-      | @{const Not} $ (@{const HOL.eq (bool)} $ t $ (@{const Not} $ u)) =>
-          (Z3_Replay_Util.compose negIffI, lookup (iff_const $ u $ t))
-      | @{const Not} $ ((eq as Const (@{const_name HOL.eq}, _)) $ t $ u) =>
-          let fun rewr lit = lit COMP @{thm not_sym}
-          in (rewr, lookup (@{const Not} $ (eq $ u $ t))) end
-      | _ =>
-          (case as_dneg lookup t of
-            NONE => (Z3_Replay_Util.compose negIffE, as_negIff lookup t)
-          | x => (Z3_Replay_Util.compose dnegE, x)))
-
-    fun join1 (s, t) =
-      (case lookup t of
-        SOME lit => (s, lit)
-      | NONE =>
-          (case lookup_rule t of
-            (rewrite, SOME lit) => (s, rewrite lit)
-          | (_, NONE) => (s, comp (apply2 join1 (dest t)))))
-
-  in snd (join1 (if is_conj then (false, t) else (true, t))) end
-
-end
-
-
-(** proving equality of conjunctions or disjunctions **)
-
-fun iff_intro thm1 thm2 = thm2 COMP (thm1 COMP @{thm iffI})
-
-local
-  val cp1 = @{lemma "(~P) = (~Q) ==> P = Q" by simp}
-  val cp2 = @{lemma "(~P) = Q ==> P = (~Q)" by fastforce}
-  val cp3 = @{lemma "P = (~Q) ==> (~P) = Q" by simp}
-in
-fun contrapos1 prove (ct, cu) = prove (negate ct, negate cu) COMP cp1
-fun contrapos2 prove (ct, cu) = prove (negate ct, Thm.dest_arg cu) COMP cp2
-fun contrapos3 prove (ct, cu) = prove (Thm.dest_arg ct, negate cu) COMP cp3
-end
-
-local
-  val contra_rule = @{lemma "P ==> ~P ==> False" by (rule notE)}
-  fun contra_left conj thm =
-    let
-      val rules = explode_term conj (SMT_Util.prop_of thm)
-      fun contra_lits (t, rs) =
-        (case t of
-          @{const Not} $ u => Termtab.lookup rules u |> Option.map (pair rs)
-        | _ => NONE)
-    in
-      (case Termtab.lookup rules @{const False} of
-        SOME rs => extract_lit thm rs
-      | NONE =>
-          the (Termtab.get_first contra_lits rules)
-          |> apply2 (extract_lit thm)
-          |> (fn (nlit, plit) => nlit COMP (plit COMP contra_rule)))
-    end
-
-  val falseE_v = Thm.dest_arg (Thm.dest_arg (Thm.cprop_of @{thm FalseE}))
-  fun contra_right ct = Thm.instantiate ([], [(falseE_v, ct)]) @{thm FalseE}
-in
-
-fun contradict conj ct =
-  iff_intro (Z3_Replay_Util.under_assumption (contra_left conj) ct) (contra_right ct)
-
-end
-
-local
-  fun prove_eq l r (cl, cr) =
-    let
-      fun explode' is_conj = explode is_conj true (l <> r) []
-      fun make_tab is_conj thm = make_littab (true_thm :: explode' is_conj thm)
-      fun prove is_conj ct tab = join is_conj tab (Thm.term_of ct)
-
-      val thm1 = Z3_Replay_Util.under_assumption (prove r cr o make_tab l) cl
-      val thm2 = Z3_Replay_Util.under_assumption (prove l cl o make_tab r) cr
-    in iff_intro thm1 thm2 end
-
-  datatype conj_disj = CONJ | DISJ | NCON | NDIS
-  fun kind_of t =
-    if is_conj t then SOME CONJ
-    else if is_disj t then SOME DISJ
-    else if is_neg' is_conj t then SOME NCON
-    else if is_neg' is_disj t then SOME NDIS
-    else NONE
-in
-
-fun prove_conj_disj_eq ct =
-  let val cp as (cl, cr) = Thm.dest_binop (Thm.dest_arg ct)
-  in
-    (case (kind_of (Thm.term_of cl), Thm.term_of cr) of
-      (SOME CONJ, @{const False}) => contradict true cl
-    | (SOME DISJ, @{const Not} $ @{const False}) =>
-        contrapos2 (contradict false o fst) cp
-    | (kl, _) =>
-        (case (kl, kind_of (Thm.term_of cr)) of
-          (SOME CONJ, SOME CONJ) => prove_eq true true cp
-        | (SOME CONJ, SOME NDIS) => prove_eq true false cp
-        | (SOME CONJ, _) => prove_eq true true cp
-        | (SOME DISJ, SOME DISJ) => contrapos1 (prove_eq false false) cp
-        | (SOME DISJ, SOME NCON) => contrapos2 (prove_eq false true) cp
-        | (SOME DISJ, _) => contrapos1 (prove_eq false false) cp
-        | (SOME NCON, SOME NCON) => contrapos1 (prove_eq true true) cp
-        | (SOME NCON, SOME DISJ) => contrapos3 (prove_eq true false) cp
-        | (SOME NCON, NONE) => contrapos3 (prove_eq true false) cp
-        | (SOME NDIS, SOME NDIS) => prove_eq false false cp
-        | (SOME NDIS, SOME CONJ) => prove_eq false true cp
-        | (SOME NDIS, NONE) => prove_eq false true cp
-        | _ => raise CTERM ("prove_conj_disj_eq", [ct])))
-  end
-
-end
-
-end;
--- a/src/HOL/Tools/SMT/z3_replay_methods.ML	Thu Jan 15 13:39:41 2015 +0100
+++ b/src/HOL/Tools/SMT/z3_replay_methods.ML	Fri Jan 16 23:23:31 2015 +0100
@@ -447,8 +447,11 @@
     CONVERSION (HOLogic.Trueprop_conv (Conv.binop_conv (if_context_conv ctxt)))
     THEN' rtac @{thm refl})
 
+fun prove_conj_disj_perm ctxt t = prove ctxt t (fn _ => Conj_Disj_Perm.conj_disj_perm_tac)
+
 fun rewrite ctxt _ = try_provers ctxt Z3_Proof.Rewrite [
   ("rules", apply_rule ctxt),
+  ("conj_disj_perm", prove_conj_disj_perm ctxt),
   ("prop_rewrite", prove_prop_rewrite ctxt),
   ("arith_rewrite", focus_eq prove_arith_rewrite ctxt),
   ("if_rewrite", lift_ite_rewrite ctxt)] []