src/HOL/Tools/Argo/argo_tactic.ML
changeset 74323 5c452041fe83
parent 74282 c2ee8d993d6a
child 74375 ba880f3a4e52
equal deleted inserted replaced
74321:714e87ce6e9d 74323:5c452041fe83
   142 fun add_type T (tcx as (_, types, _)) =
   142 fun add_type T (tcx as (_, types, _)) =
   143   (case Typtab.lookup types T of
   143   (case Typtab.lookup types T of
   144     SOME ty => (ty, tcx)
   144     SOME ty => (ty, tcx)
   145   | NONE => add_new_type T tcx)
   145   | NONE => add_new_type T tcx)
   146 
   146 
   147 fun trans_type _ \<^typ>\<open>HOL.bool\<close> = pair Argo_Expr.Bool
   147 fun trans_type _ \<^Type>\<open>bool\<close> = pair Argo_Expr.Bool
   148   | trans_type ctxt (Type (\<^type_name>\<open>fun\<close>, [T1, T2])) =
   148   | trans_type ctxt \<^Type>\<open>fun T1 T2\<close> =
   149       trans_type ctxt T1 ##>> trans_type ctxt T2 #>> Argo_Expr.Func
   149       trans_type ctxt T1 ##>> trans_type ctxt T2 #>> Argo_Expr.Func
   150   | trans_type ctxt T = (fn tcx =>
   150   | trans_type ctxt T = (fn tcx =>
   151       (case ext_trans_type ctxt (trans_type ctxt) T tcx of
   151       (case ext_trans_type ctxt (trans_type ctxt) T tcx of
   152         SOME result => result
   152         SOME result => result
   153       | NONE => add_type T tcx))
   153       | NONE => add_type T tcx))
   162 fun add_term ctxt t (tcx as (_, _, terms)) =
   162 fun add_term ctxt t (tcx as (_, _, terms)) =
   163   (case Termtab.lookup terms t of
   163   (case Termtab.lookup terms t of
   164     SOME c => (Argo_Expr.mk_con c, tcx)
   164     SOME c => (Argo_Expr.mk_con c, tcx)
   165   | NONE => add_new_term ctxt t (Term.fastype_of t) tcx)
   165   | NONE => add_new_term ctxt t (Term.fastype_of t) tcx)
   166 
   166 
   167 fun mk_eq \<^typ>\<open>HOL.bool\<close> = Argo_Expr.mk_iff
   167 fun mk_eq \<^Type>\<open>bool\<close> = Argo_Expr.mk_iff
   168   | mk_eq _ = Argo_Expr.mk_eq
   168   | mk_eq _ = Argo_Expr.mk_eq
   169 
   169 
   170 fun trans_term _ \<^const>\<open>HOL.True\<close> = pair Argo_Expr.true_expr
   170 fun trans_term _ \<^Const_>\<open>True\<close> = pair Argo_Expr.true_expr
   171   | trans_term _ \<^const>\<open>HOL.False\<close> = pair Argo_Expr.false_expr
   171   | trans_term _ \<^Const_>\<open>False\<close> = pair Argo_Expr.false_expr
   172   | trans_term ctxt (\<^const>\<open>HOL.Not\<close> $ t) = trans_term ctxt t #>> Argo_Expr.mk_not
   172   | trans_term ctxt \<^Const_>\<open>Not for t\<close> = trans_term ctxt t #>> Argo_Expr.mk_not
   173   | trans_term ctxt (\<^const>\<open>HOL.conj\<close> $ t1 $ t2) =
   173   | trans_term ctxt \<^Const_>\<open>conj for t1 t2\<close> =
   174       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry Argo_Expr.mk_and2
   174       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry Argo_Expr.mk_and2
   175   | trans_term ctxt (\<^const>\<open>HOL.disj\<close> $ t1 $ t2) =
   175   | trans_term ctxt \<^Const_>\<open>disj for t1 t2\<close> =
   176       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry Argo_Expr.mk_or2
   176       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry Argo_Expr.mk_or2
   177   | trans_term ctxt (\<^const>\<open>HOL.implies\<close> $ t1 $ t2) =
   177   | trans_term ctxt \<^Const_>\<open>implies for t1 t2\<close> =
   178       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry Argo_Expr.mk_imp
   178       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry Argo_Expr.mk_imp
   179   | trans_term ctxt (Const (\<^const_name>\<open>HOL.If\<close>, _) $ t1 $ t2 $ t3) =
   179   | trans_term ctxt \<^Const_>\<open>If _ for t1 t2 t3\<close> =
   180       trans_term ctxt t1 ##>> trans_term ctxt t2 ##>> trans_term ctxt t3 #>>
   180       trans_term ctxt t1 ##>> trans_term ctxt t2 ##>> trans_term ctxt t3 #>>
   181       (fn ((u1, u2), u3) => Argo_Expr.mk_ite u1 u2 u3)
   181       (fn ((u1, u2), u3) => Argo_Expr.mk_ite u1 u2 u3)
   182   | trans_term ctxt (Const (\<^const_name>\<open>HOL.eq\<close>, T) $ t1 $ t2) =
   182   | trans_term ctxt \<^Const_>\<open>HOL.eq T for t1 t2\<close> =
   183       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry (mk_eq (Term.domain_type T))
   183       trans_term ctxt t1 ##>> trans_term ctxt t2 #>> uncurry (mk_eq T)
   184   | trans_term ctxt (t as (t1 $ t2)) = (fn tcx =>
   184   | trans_term ctxt (t as (t1 $ t2)) = (fn tcx =>
   185       (case ext_trans_term ctxt (trans_term ctxt) t tcx of
   185       (case ext_trans_term ctxt (trans_term ctxt) t tcx of
   186         SOME result => result
   186         SOME result => result
   187       | NONE => tcx |> trans_term ctxt t1 ||>> trans_term ctxt t2 |>> uncurry Argo_Expr.mk_app))
   187       | NONE => tcx |> trans_term ctxt t1 ||>> trans_term ctxt t2 |>> uncurry Argo_Expr.mk_app))
   188   | trans_term ctxt t = (fn tcx =>
   188   | trans_term ctxt t = (fn tcx =>
   256 
   256 
   257 fun mk_nary' d _ [] = d
   257 fun mk_nary' d _ [] = d
   258   | mk_nary' _ f ts = mk_nary f ts
   258   | mk_nary' _ f ts = mk_nary f ts
   259 
   259 
   260 fun mk_ite t1 t2 t3 =
   260 fun mk_ite t1 t2 t3 =
   261   let
   261   let val T = Term.fastype_of t2
   262     val T = Term.fastype_of t2
   262   in \<^Const>\<open>If T for t1 t2 t3\<close> end
   263     val ite = Const (\<^const_name>\<open>HOL.If\<close>, [\<^typ>\<open>HOL.bool\<close>, T, T] ---> T)
   263 
   264   in ite $ t1 $ t2 $ t3 end
   264 fun term_of _ (Argo_Expr.E (Argo_Expr.True, _)) = \<^Const>\<open>True\<close>
   265 
   265   | term_of _ (Argo_Expr.E (Argo_Expr.False, _)) = \<^Const>\<open>False\<close>
   266 fun term_of _ (Argo_Expr.E (Argo_Expr.True, _)) = \<^const>\<open>HOL.True\<close>
       
   267   | term_of _ (Argo_Expr.E (Argo_Expr.False, _)) = \<^const>\<open>HOL.False\<close>
       
   268   | term_of cx (Argo_Expr.E (Argo_Expr.Not, [e])) = HOLogic.mk_not (term_of cx e)
   266   | term_of cx (Argo_Expr.E (Argo_Expr.Not, [e])) = HOLogic.mk_not (term_of cx e)
   269   | term_of cx (Argo_Expr.E (Argo_Expr.And, es)) =
   267   | term_of cx (Argo_Expr.E (Argo_Expr.And, es)) =
   270       mk_nary' \<^const>\<open>HOL.True\<close> HOLogic.mk_conj (map (term_of cx) es)
   268       mk_nary' \<^Const>\<open>True\<close> HOLogic.mk_conj (map (term_of cx) es)
   271   | term_of cx (Argo_Expr.E (Argo_Expr.Or, es)) =
   269   | term_of cx (Argo_Expr.E (Argo_Expr.Or, es)) =
   272       mk_nary' \<^const>\<open>HOL.False\<close> HOLogic.mk_disj (map (term_of cx) es)
   270       mk_nary' \<^Const>\<open>False\<close> HOLogic.mk_disj (map (term_of cx) es)
   273   | term_of cx (Argo_Expr.E (Argo_Expr.Imp, [e1, e2])) =
   271   | term_of cx (Argo_Expr.E (Argo_Expr.Imp, [e1, e2])) =
   274       HOLogic.mk_imp (term_of cx e1, term_of cx e2)
   272       HOLogic.mk_imp (term_of cx e1, term_of cx e2)
   275   | term_of cx (Argo_Expr.E (Argo_Expr.Iff, [e1, e2])) =
   273   | term_of cx (Argo_Expr.E (Argo_Expr.Iff, [e1, e2])) =
   276       HOLogic.mk_eq (term_of cx e1, term_of cx e2)
   274       HOLogic.mk_eq (term_of cx e1, term_of cx e2)
   277   | term_of cx (Argo_Expr.E (Argo_Expr.Ite, [e1, e2, e3])) =
   275   | term_of cx (Argo_Expr.E (Argo_Expr.Ite, [e1, e2, e3])) =
   287   | term_of (cx as (ctxt, _)) e =
   285   | term_of (cx as (ctxt, _)) e =
   288       (case ext_term_of ctxt (term_of cx) e of
   286       (case ext_term_of ctxt (term_of cx) e of
   289         SOME t => t
   287         SOME t => t
   290       | NONE => raise Fail "bad expression")
   288       | NONE => raise Fail "bad expression")
   291 
   289 
   292 fun as_prop ct = Thm.apply \<^cterm>\<open>HOL.Trueprop\<close> ct
   290 fun as_prop ct = Thm.apply \<^cterm>\<open>Trueprop\<close> ct
   293 
   291 
   294 fun cterm_of ctxt cons e = Thm.cterm_of ctxt (term_of (ctxt, cons) e)
   292 fun cterm_of ctxt cons e = Thm.cterm_of ctxt (term_of (ctxt, cons) e)
   295 fun cprop_of ctxt cons e = as_prop (cterm_of ctxt cons e)
   293 fun cprop_of ctxt cons e = as_prop (cterm_of ctxt cons e)
   296 
   294 
   297 
   295 
   315   (fn {context, ...} => HEADGOAL (Classical.fast_tac context))
   313   (fn {context, ...} => HEADGOAL (Classical.fast_tac context))
   316 
   314 
   317 fun with_frees ctxt n mk =
   315 fun with_frees ctxt n mk =
   318   let
   316   let
   319     val ns = map (fn i => "P" ^ string_of_int i) (0 upto (n - 1))
   317     val ns = map (fn i => "P" ^ string_of_int i) (0 upto (n - 1))
   320     val ts = map (Free o rpair \<^typ>\<open>bool\<close>) ns
   318     val ts = map (Free o rpair \<^Type>\<open>bool\<close>) ns
   321     val t = mk_nary HOLogic.mk_disj (mk ts)
   319     val t = mk_nary HOLogic.mk_disj (mk ts)
   322   in prove_taut ctxt ns t end
   320   in prove_taut ctxt ns t end
   323 
   321 
   324 fun taut_and1_term ts = mk_nary HOLogic.mk_conj ts :: map HOLogic.mk_not ts
   322 fun taut_and1_term ts = mk_nary HOLogic.mk_conj ts :: map HOLogic.mk_not ts
   325 fun taut_and2_term i ts = [HOLogic.mk_not (mk_nary HOLogic.mk_conj ts), nth ts i]
   323 fun taut_and2_term i ts = [HOLogic.mk_not (mk_nary HOLogic.mk_conj ts), nth ts i]
   372   Conv.try_conv (Conv.arg_conv cv) then_conv
   370   Conv.try_conv (Conv.arg_conv cv) then_conv
   373   Conv.try_conv (Conv.rewr_conv rule then_conv cv)) ct
   371   Conv.try_conv (Conv.rewr_conv rule then_conv cv)) ct
   374 
   372 
   375 fun flat_conj_conv ct =
   373 fun flat_conj_conv ct =
   376   (case Thm.term_of ct of
   374   (case Thm.term_of ct of
   377     \<^const>\<open>HOL.conj\<close> $ _ $ _ => flatten_conv flat_conj_conv flatten_and_thm ct
   375     \<^Const_>\<open>conj for _ _\<close> => flatten_conv flat_conj_conv flatten_and_thm ct
   378   | _ => Conv.all_conv ct)
   376   | _ => Conv.all_conv ct)
   379 
   377 
   380 fun flat_disj_conv ct =
   378 fun flat_disj_conv ct =
   381   (case Thm.term_of ct of
   379   (case Thm.term_of ct of
   382     \<^const>\<open>HOL.disj\<close> $ _ $ _ => flatten_conv flat_disj_conv flatten_or_thm ct
   380     \<^Const_>\<open>disj for _ _\<close> => flatten_conv flat_disj_conv flatten_or_thm ct
   383   | _ => Conv.all_conv ct)
   381   | _ => Conv.all_conv ct)
   384 
   382 
   385 fun explode rule1 rule2 thm =
   383 fun explode rule1 rule2 thm =
   386   explode rule1 rule2 (thm RS rule1) @ explode rule1 rule2 (thm RS rule2) handle THM _ => [thm]
   384   explode rule1 rule2 (thm RS rule1) @ explode rule1 rule2 (thm RS rule2) handle THM _ => [thm]
   387 val explode_conj = explode @{thm conjunct1} @{thm conjunct2}
   385 val explode_conj = explode @{thm conjunct1} @{thm conjunct2}
   413     val lhs = under_assumption lf ct
   411     val lhs = under_assumption lf ct
   414     val rhs = rf (Thm.dest_arg (snd (Thm.dest_implies (Thm.cprop_of lhs))))
   412     val rhs = rf (Thm.dest_arg (snd (Thm.dest_implies (Thm.cprop_of lhs))))
   415   in mk_rewr (discharge2 lhs rhs rule) end
   413   in mk_rewr (discharge2 lhs rhs rule) end
   416 
   414 
   417 fun with_conj f g ct = iff_intro iff_conj_thm (f o explode_conj) g ct
   415 fun with_conj f g ct = iff_intro iff_conj_thm (f o explode_conj) g ct
   418 fun with_ndis f g ct = iff_intro iff_ndis_thm (f o explode_ndis) g (Thm.apply \<^cterm>\<open>HOL.Not\<close> ct)
   416 fun with_ndis f g ct = iff_intro iff_ndis_thm (f o explode_ndis) g (Thm.apply \<^cterm>\<open>Not\<close> ct)
   419 
   417 
   420 fun swap_indices n iss = map (fn i => find_index (fn is => member (op =) is i) iss) (0 upto (n - 1))
   418 fun swap_indices n iss = map (fn i => find_index (fn is => member (op =) is i) iss) (0 upto (n - 1))
   421 fun sort_nary w f g (n, iss) = w (f (map hd iss)) (under_assumption (f (swap_indices n iss) o g))
   419 fun sort_nary w f g (n, iss) = w (f (map hd iss)) (under_assumption (f (swap_indices n iss) o g))
   422 val sort_conj = sort_nary with_conj join_conj explode_conj
   420 val sort_conj = sort_nary with_conj join_conj explode_conj
   423 val sort_ndis = sort_nary with_ndis join_ndis explode_ndis 
   421 val sort_ndis = sort_nary with_ndis join_ndis explode_ndis 
   483 and replay_args_conv _ [] ct = Conv.all_conv ct
   481 and replay_args_conv _ [] ct = Conv.all_conv ct
   484   | replay_args_conv ctxt [c] ct = Conv.arg_conv (replay_conv ctxt c) ct
   482   | replay_args_conv ctxt [c] ct = Conv.arg_conv (replay_conv ctxt c) ct
   485   | replay_args_conv ctxt [c1, c2] ct = binop_conv (replay_conv ctxt c1) (replay_conv ctxt c2) ct
   483   | replay_args_conv ctxt [c1, c2] ct = binop_conv (replay_conv ctxt c1) (replay_conv ctxt c2) ct
   486   | replay_args_conv ctxt (c :: cs) ct =
   484   | replay_args_conv ctxt (c :: cs) ct =
   487       (case Term.head_of (Thm.term_of ct) of
   485       (case Term.head_of (Thm.term_of ct) of
   488         Const (\<^const_name>\<open>HOL.If\<close>, _) =>
   486         \<^Const_>\<open>If _\<close> =>
   489           let val (cs', c') = split_last cs
   487           let val (cs', c') = split_last cs
   490           in Conv.combination_conv (replay_args_conv ctxt (c :: cs')) (replay_conv ctxt c') ct end
   488           in Conv.combination_conv (replay_args_conv ctxt (c :: cs')) (replay_conv ctxt c') ct end
   491       | _ => binop_conv (replay_conv ctxt c) (replay_args_conv ctxt cs) ct)
   489       | _ => binop_conv (replay_conv ctxt c) (replay_args_conv ctxt cs) ct)
   492 
   490 
   493 fun replay_rewrite ctxt c thm = Conv.fconv_rule (HOLogic.Trueprop_conv (replay_conv ctxt c)) thm
   491 fun replay_rewrite ctxt c thm = Conv.fconv_rule (HOLogic.Trueprop_conv (replay_conv ctxt c)) thm
   519 
   517 
   520 (* proof replay for unit resolution *)
   518 (* proof replay for unit resolution *)
   521 
   519 
   522 val unit_rule = @{lemma "(P \<Longrightarrow> False) \<Longrightarrow> (\<not>P \<Longrightarrow> False) \<Longrightarrow> False" by fast}
   520 val unit_rule = @{lemma "(P \<Longrightarrow> False) \<Longrightarrow> (\<not>P \<Longrightarrow> False) \<Longrightarrow> False" by fast}
   523 val unit_rule_var = Thm.dest_arg (Thm.dest_arg1 (Thm.cprem_of unit_rule 1))
   521 val unit_rule_var = Thm.dest_arg (Thm.dest_arg1 (Thm.cprem_of unit_rule 1))
   524 val bogus_ct = \<^cterm>\<open>HOL.True\<close>
   522 val bogus_ct = \<^cterm>\<open>True\<close>
   525 
   523 
   526 fun replay_unit_res lit (pthm, plits) (nthm, nlits) =
   524 fun replay_unit_res lit (pthm, plits) (nthm, nlits) =
   527   let
   525   let
   528     val plit = the (AList.lookup (op =) plits lit)
   526     val plit = the (AList.lookup (op =) plits lit)
   529     val nlit = the (AList.lookup (op =) nlits (~lit))
   527     val nlit = the (AList.lookup (op =) nlits (~lit))
   542 val dneg_rule = @{lemma "\<not>\<not>P \<Longrightarrow> P" by auto}
   540 val dneg_rule = @{lemma "\<not>\<not>P \<Longrightarrow> P" by auto}
   543 
   541 
   544 fun replay_hyp i ct =
   542 fun replay_hyp i ct =
   545   if i < 0 then (Thm.assume ct, [(~i, ct)])
   543   if i < 0 then (Thm.assume ct, [(~i, ct)])
   546   else
   544   else
   547     let val cu = as_prop (Thm.apply \<^cterm>\<open>HOL.Not\<close> (Thm.apply \<^cterm>\<open>HOL.Not\<close> (Thm.dest_arg ct)))
   545     let val cu = as_prop (Thm.apply \<^cterm>\<open>Not\<close> (Thm.apply \<^cterm>\<open>Not\<close> (Thm.dest_arg ct)))
   548     in (discharge (Thm.assume cu) dneg_rule, [(~i, cu)]) end
   546     in (discharge (Thm.assume cu) dneg_rule, [(~i, cu)]) end
   549 
   547 
   550 
   548 
   551 (* proof replay for lemma *)
   549 (* proof replay for lemma *)
   552 
   550 
   600 val unclausify_rule1 = @{lemma "(\<not>P \<Longrightarrow> False) \<Longrightarrow> P" by auto}
   598 val unclausify_rule1 = @{lemma "(\<not>P \<Longrightarrow> False) \<Longrightarrow> P" by auto}
   601 val unclausify_rule2 = @{lemma "(P \<Longrightarrow> False) \<Longrightarrow> \<not>P" by auto}
   599 val unclausify_rule2 = @{lemma "(P \<Longrightarrow> False) \<Longrightarrow> \<not>P" by auto}
   602 
   600 
   603 fun unclausify (thm, lits) ls =
   601 fun unclausify (thm, lits) ls =
   604   (case (Thm.prop_of thm, lits) of
   602   (case (Thm.prop_of thm, lits) of
   605     (\<^const>\<open>HOL.Trueprop\<close> $ \<^const>\<open>HOL.False\<close>, [(_, ct)]) =>
   603     (\<^Const_>\<open>Trueprop for \<open>\<^Const_>\<open>False\<close>\<close>\<close>, [(_, ct)]) =>
   606       let val thm = Thm.implies_intr ct thm
   604       let val thm = Thm.implies_intr ct thm
   607       in (discharge thm unclausify_rule1 handle THM _ => discharge thm unclausify_rule2, ls) end
   605       in (discharge thm unclausify_rule1 handle THM _ => discharge thm unclausify_rule2, ls) end
   608   | _ => (thm, Ord_List.union lit_ord lits ls))
   606   | _ => (thm, Ord_List.union lit_ord lits ls))
   609 
   607 
   610 fun with_thms f tps = fold_map unclausify tps [] |>> f
   608 fun with_thms f tps = fold_map unclausify tps [] |>> f
   667 
   665 
   668 fun instantiate_elim_rule thm =
   666 fun instantiate_elim_rule thm =
   669   let val ct = Drule.strip_imp_concl (Thm.cprop_of thm)
   667   let val ct = Drule.strip_imp_concl (Thm.cprop_of thm)
   670   in
   668   in
   671     (case Thm.term_of ct of
   669     (case Thm.term_of ct of
   672       \<^const>\<open>HOL.Trueprop\<close> $ Var (_, \<^typ>\<open>HOL.bool\<close>) =>
   670       \<^Const_>\<open>Trueprop for \<open>Var (_, \<^Type>\<open>bool\<close>)\<close>\<close> =>
   673         instantiate (Thm.dest_arg ct) \<^cterm>\<open>HOL.False\<close> thm
   671         instantiate (Thm.dest_arg ct) \<^cterm>\<open>False\<close> thm
   674     | Var _ => instantiate ct \<^cprop>\<open>HOL.False\<close> thm
   672     | Var _ => instantiate ct \<^cprop>\<open>False\<close> thm
   675     | _ => thm)
   673     | _ => thm)
   676   end
   674   end
   677 
   675 
   678 fun atomize_conv ctxt ct =
   676 fun atomize_conv ctxt ct =
   679   (case Thm.term_of ct of
   677   (case Thm.term_of ct of
   680     \<^const>\<open>HOL.Trueprop\<close> $ _ => Conv.all_conv
   678     \<^Const_>\<open>Trueprop for _\<close> => Conv.all_conv
   681   | \<^const>\<open>Pure.imp\<close> $ _ $ _ =>
   679   | \<^Const_>\<open>Pure.imp for _ _\<close> =>
   682       Conv.binop_conv (atomize_conv ctxt) then_conv
   680       Conv.binop_conv (atomize_conv ctxt) then_conv
   683       Conv.rewr_conv @{thm atomize_imp}
   681       Conv.rewr_conv @{thm atomize_imp}
   684   | Const (\<^const_name>\<open>Pure.eq\<close>, _) $ _ $ _ =>
   682   | \<^Const>\<open>Pure.eq _ for _ _\<close> =>
   685       Conv.binop_conv (atomize_conv ctxt) then_conv
   683       Conv.binop_conv (atomize_conv ctxt) then_conv
   686       Conv.rewr_conv @{thm atomize_eq}
   684       Conv.rewr_conv @{thm atomize_eq}
   687   | Const (\<^const_name>\<open>Pure.all\<close>, _) $ Abs _ =>
   685   | \<^Const>\<open>Pure.all _ for \<open>Abs _\<close>\<close> =>
   688       Conv.binder_conv (atomize_conv o snd) ctxt then_conv
   686       Conv.binder_conv (atomize_conv o snd) ctxt then_conv
   689       Conv.rewr_conv @{thm atomize_all}
   687       Conv.rewr_conv @{thm atomize_all}
   690   | _ => Conv.all_conv) ct
   688   | _ => Conv.all_conv) ct
   691 
   689 
   692 fun normalize ctxt thm =
   690 fun normalize ctxt thm =