diff --git a/src/FOL/FOL.thy b/src/FOL/FOL.thy --- a/src/FOL/FOL.thy +++ b/src/FOL/FOL.thy @@ -1,455 +1,455 @@ (* Title: FOL/FOL.thy Author: Lawrence C Paulson and Markus Wenzel *) section \Classical first-order logic\ theory FOL imports IFOL keywords "print_claset" "print_induct_rules" :: diag begin ML_file \~~/src/Provers/classical.ML\ ML_file \~~/src/Provers/blast.ML\ ML_file \~~/src/Provers/clasimp.ML\ subsection \The classical axiom\ axiomatization where classical: \(\ P \ P) \ P\ subsection \Lemmas and proof tools\ lemma ccontr: \(\ P \ False) \ P\ by (erule FalseE [THEN classical]) subsubsection \Classical introduction rules for \\\ and \\\\ lemma disjCI: \(\ Q \ P) \ P \ Q\ apply (rule classical) apply (assumption | erule meta_mp | rule disjI1 notI)+ apply (erule notE disjI2)+ done text \Introduction rule involving only \\\\ lemma ex_classical: assumes r: \\ (\x. P(x)) \ P(a)\ shows \\x. P(x)\ apply (rule classical) apply (rule exI, erule r) done text \Version of above, simplifying \\\\ to \\\\.\ lemma exCI: assumes r: \\x. \ P(x) \ P(a)\ shows \\x. P(x)\ apply (rule ex_classical) apply (rule notI [THEN allI, THEN r]) apply (erule notE) apply (erule exI) done lemma excluded_middle: \\ P \ P\ apply (rule disjCI) apply assumption done lemma case_split [case_names True False]: assumes r1: \P \ Q\ and r2: \\ P \ Q\ shows \Q\ apply (rule excluded_middle [THEN disjE]) apply (erule r2) apply (erule r1) done ML \ fun case_tac ctxt a fixes = Rule_Insts.res_inst_tac ctxt [((("P", 0), Position.none), a)] fixes @{thm case_split}; \ method_setup case_tac = \ Args.goal_spec -- Scan.lift (Args.embedded_inner_syntax -- Parse.for_fixes) >> (fn (quant, (s, fixes)) => fn ctxt => SIMPLE_METHOD'' quant (case_tac ctxt s fixes)) \ "case_tac emulation (dynamic instantiation!)" subsection \Special elimination rules\ text \Classical implies (\\\) elimination.\ lemma impCE: assumes major: \P \ Q\ and r1: \\ P \ R\ and r2: \Q \ R\ shows \R\ apply (rule excluded_middle [THEN disjE]) apply (erule r1) apply (rule r2) apply (erule major [THEN mp]) done text \ This version of \\\ elimination works on \Q\ before \P\. It works best for those cases in which P holds ``almost everywhere''. Can't install as default: would break old proofs. \ lemma impCE': assumes major: \P \ Q\ and r1: \Q \ R\ and r2: \\ P \ R\ shows \R\ apply (rule excluded_middle [THEN disjE]) apply (erule r2) apply (rule r1) apply (erule major [THEN mp]) done text \Double negation law.\ lemma notnotD: \\ \ P \ P\ apply (rule classical) apply (erule notE) apply assumption done lemma contrapos2: \\Q; \ P \ \ Q\ \ P\ apply (rule classical) apply (drule (1) meta_mp) apply (erule (1) notE) done subsubsection \Tactics for implication and contradiction\ text \ Classical \\\ elimination. Proof substitutes \P = Q\ in \\ P \ \ Q\ and \P \ Q\. \ lemma iffCE: assumes major: \P \ Q\ and r1: \\P; Q\ \ R\ and r2: \\\ P; \ Q\ \ R\ shows \R\ apply (rule major [unfolded iff_def, THEN conjE]) apply (elim impCE) apply (erule (1) r2) apply (erule (1) notE)+ apply (erule (1) r1) done (*Better for fast_tac: needs no quantifier duplication!*) lemma alt_ex1E: assumes major: \\! x. P(x)\ and r: \\x. \P(x); \y y'. P(y) \ P(y') \ y = y'\ \ R\ shows \R\ using major proof (rule ex1E) fix x assume * : \\y. P(y) \ y = x\ assume \P(x)\ then show \R\ proof (rule r) { fix y y' assume \P(y)\ and \P(y')\ with * have \x = y\ and \x = y'\ by - (tactic "IntPr.fast_tac \<^context> 1")+ then have \y = y'\ by (rule subst) } note r' = this show \\y y'. P(y) \ P(y') \ y = y'\ by (intro strip, elim conjE) (rule r') qed qed lemma imp_elim: \P \ Q \ (\ R \ P) \ (Q \ R) \ R\ by (rule classical) iprover lemma swap: \\ P \ (\ R \ P) \ R\ by (rule classical) iprover section \Classical Reasoner\ ML \ structure Cla = Classical ( val imp_elim = @{thm imp_elim} val not_elim = @{thm notE} val swap = @{thm swap} val classical = @{thm classical} val sizef = size_of_thm val hyp_subst_tacs = [hyp_subst_tac] ); structure Basic_Classical: BASIC_CLASSICAL = Cla; open Basic_Classical; \ (*Propositional rules*) lemmas [intro!] = refl TrueI conjI disjCI impI notI iffI and [elim!] = conjE disjE impCE FalseE iffCE ML \val prop_cs = claset_of \<^context>\ (*Quantifier rules*) lemmas [intro!] = allI ex_ex1I and [intro] = exI and [elim!] = exE alt_ex1E and [elim] = allE ML \val FOL_cs = claset_of \<^context>\ ML \ structure Blast = Blast ( structure Classical = Cla val Trueprop_const = dest_Const \<^const>\Trueprop\ val equality_name = \<^const_name>\eq\ val not_name = \<^const_name>\Not\ val notE = @{thm notE} val ccontr = @{thm ccontr} val hyp_subst_tac = Hypsubst.blast_hyp_subst_tac ); val blast_tac = Blast.blast_tac; \ lemma ex1_functional: \\\! z. P(a,z); P(a,b); P(a,c)\ \ b = c\ by blast text \Elimination of \True\ from assumptions:\ lemma True_implies_equals: \(True \ PROP P) \ PROP P\ proof assume \True \ PROP P\ from this and TrueI show \PROP P\ . next assume \PROP P\ then show \PROP P\ . qed lemma uncurry: \P \ Q \ R \ P \ Q \ R\ by blast lemma iff_allI: \(\x. P(x) \ Q(x)) \ (\x. P(x)) \ (\x. Q(x))\ by blast lemma iff_exI: \(\x. P(x) \ Q(x)) \ (\x. P(x)) \ (\x. Q(x))\ by blast lemma all_comm: \(\x y. P(x,y)) \ (\y x. P(x,y))\ by blast lemma ex_comm: \(\x y. P(x,y)) \ (\y x. P(x,y))\ by blast subsection \Classical simplification rules\ text \ Avoids duplication of subgoals after \expand_if\, when the true and false cases boil down to the same thing. \ lemma cases_simp: \(P \ Q) \ (\ P \ Q) \ Q\ by blast subsubsection \Miniscoping: pushing quantifiers in\ text \ We do NOT distribute of \\\ over \\\, or dually that of \\\ over \\\. Baaz and Leitsch, On Skolemization and Proof Complexity (1994) show that this step can increase proof length! \ text \Existential miniscoping.\ lemma int_ex_simps: \\P Q. (\x. P(x) \ Q) \ (\x. P(x)) \ Q\ \\P Q. (\x. P \ Q(x)) \ P \ (\x. Q(x))\ \\P Q. (\x. P(x) \ Q) \ (\x. P(x)) \ Q\ \\P Q. (\x. P \ Q(x)) \ P \ (\x. Q(x))\ by iprover+ text \Classical rules.\ lemma cla_ex_simps: \\P Q. (\x. P(x) \ Q) \ (\x. P(x)) \ Q\ \\P Q. (\x. P \ Q(x)) \ P \ (\x. Q(x))\ by blast+ lemmas ex_simps = int_ex_simps cla_ex_simps text \Universal miniscoping.\ lemma int_all_simps: \\P Q. (\x. P(x) \ Q) \ (\x. P(x)) \ Q\ \\P Q. (\x. P \ Q(x)) \ P \ (\x. Q(x))\ \\P Q. (\x. P(x) \ Q) \ (\ x. P(x)) \ Q\ \\P Q. (\x. P \ Q(x)) \ P \ (\x. Q(x))\ by iprover+ text \Classical rules.\ lemma cla_all_simps: \\P Q. (\x. P(x) \ Q) \ (\x. P(x)) \ Q\ \\P Q. (\x. P \ Q(x)) \ P \ (\x. Q(x))\ by blast+ lemmas all_simps = int_all_simps cla_all_simps subsubsection \Named rewrite rules proved for IFOL\ lemma imp_disj1: \(P \ Q) \ R \ (P \ Q \ R)\ by blast lemma imp_disj2: \Q \ (P \ R) \ (P \ Q \ R)\ by blast lemma de_Morgan_conj: \(\ (P \ Q)) \ (\ P \ \ Q)\ by blast lemma not_imp: \\ (P \ Q) \ (P \ \ Q)\ by blast lemma not_iff: \\ (P \ Q) \ (P \ \ Q)\ by blast lemma not_all: \(\ (\x. P(x))) \ (\x. \ P(x))\ by blast lemma imp_all: \((\x. P(x)) \ Q) \ (\x. P(x) \ Q)\ by blast lemmas meta_simps = triv_forall_equality \ \prunes params\ True_implies_equals \ \prune asms \True\\ lemmas IFOL_simps = refl [THEN P_iff_T] conj_simps disj_simps not_simps imp_simps iff_simps quant_simps lemma notFalseI: \\ False\ by iprover lemma cla_simps_misc: \\ (P \ Q) \ \ P \ \ Q\ \P \ \ P\ \\ P \ P\ \\ \ P \ P\ \(\ P \ P) \ P\ \(\ P \ \ Q) \ (P \ Q)\ by blast+ lemmas cla_simps = de_Morgan_conj de_Morgan_disj imp_disj1 imp_disj2 not_imp not_all not_ex cases_simp cla_simps_misc ML_file \simpdata.ML\ -simproc_setup defined_Ex (\\x. P(x)\) = \fn _ => Quantifier1.rearrange_ex\ -simproc_setup defined_All (\\x. P(x)\) = \fn _ => Quantifier1.rearrange_all\ +simproc_setup defined_Ex (\\x. P(x)\) = \fn _ => Quantifier1.rearrange_Ex\ +simproc_setup defined_All (\\x. P(x)\) = \fn _ => Quantifier1.rearrange_All\ ML \ (*intuitionistic simprules only*) val IFOL_ss = put_simpset FOL_basic_ss \<^context> addsimps @{thms meta_simps IFOL_simps int_ex_simps int_all_simps} addsimprocs [\<^simproc>\defined_All\, \<^simproc>\defined_Ex\] |> Simplifier.add_cong @{thm imp_cong} |> simpset_of; (*classical simprules too*) val FOL_ss = put_simpset IFOL_ss \<^context> addsimps @{thms cla_simps cla_ex_simps cla_all_simps} |> simpset_of; \ setup \ map_theory_simpset (put_simpset FOL_ss) #> Simplifier.method_setup Splitter.split_modifiers \ ML_file \~~/src/Tools/eqsubst.ML\ subsection \Other simple lemmas\ lemma [simp]: \((P \ R) \ (Q \ R)) \ ((P \ Q) \ R)\ by blast lemma [simp]: \((P \ Q) \ (P \ R)) \ (P \ (Q \ R))\ by blast lemma not_disj_iff_imp: \\ P \ Q \ (P \ Q)\ by blast subsubsection \Monotonicity of implications\ lemma conj_mono: \\P1 \ Q1; P2 \ Q2\ \ (P1 \ P2) \ (Q1 \ Q2)\ by fast (*or (IntPr.fast_tac 1)*) lemma disj_mono: \\P1 \ Q1; P2 \ Q2\ \ (P1 \ P2) \ (Q1 \ Q2)\ by fast (*or (IntPr.fast_tac 1)*) lemma imp_mono: \\Q1 \ P1; P2 \ Q2\ \ (P1 \ P2) \ (Q1 \ Q2)\ by fast (*or (IntPr.fast_tac 1)*) lemma imp_refl: \P \ P\ by (rule impI) text \The quantifier monotonicity rules are also intuitionistically valid.\ lemma ex_mono: \(\x. P(x) \ Q(x)) \ (\x. P(x)) \ (\x. Q(x))\ by blast lemma all_mono: \(\x. P(x) \ Q(x)) \ (\x. P(x)) \ (\x. Q(x))\ by blast subsection \Proof by cases and induction\ text \Proper handling of non-atomic rule statements.\ context begin qualified definition \induct_forall(P) \ \x. P(x)\ qualified definition \induct_implies(A, B) \ A \ B\ qualified definition \induct_equal(x, y) \ x = y\ qualified definition \induct_conj(A, B) \ A \ B\ lemma induct_forall_eq: \(\x. P(x)) \ Trueprop(induct_forall(\x. P(x)))\ unfolding atomize_all induct_forall_def . lemma induct_implies_eq: \(A \ B) \ Trueprop(induct_implies(A, B))\ unfolding atomize_imp induct_implies_def . lemma induct_equal_eq: \(x \ y) \ Trueprop(induct_equal(x, y))\ unfolding atomize_eq induct_equal_def . lemma induct_conj_eq: \(A &&& B) \ Trueprop(induct_conj(A, B))\ unfolding atomize_conj induct_conj_def . lemmas induct_atomize = induct_forall_eq induct_implies_eq induct_equal_eq induct_conj_eq lemmas induct_rulify [symmetric] = induct_atomize lemmas induct_rulify_fallback = induct_forall_def induct_implies_def induct_equal_def induct_conj_def text \Method setup.\ ML_file \~~/src/Tools/induct.ML\ ML \ structure Induct = Induct ( val cases_default = @{thm case_split} val atomize = @{thms induct_atomize} val rulify = @{thms induct_rulify} val rulify_fallback = @{thms induct_rulify_fallback} val equal_def = @{thm induct_equal_def} fun dest_def _ = NONE fun trivial_tac _ _ = no_tac ); \ declare case_split [cases type: o] end ML_file \~~/src/Tools/case_product.ML\ hide_const (open) eq end diff --git a/src/HOL/HOL.thy b/src/HOL/HOL.thy --- a/src/HOL/HOL.thy +++ b/src/HOL/HOL.thy @@ -1,2141 +1,2141 @@ (* Title: HOL/HOL.thy Author: Tobias Nipkow, Markus Wenzel, and Larry Paulson *) section \The basis of Higher-Order Logic\ theory HOL imports Pure Tools.Code_Generator keywords "try" "solve_direct" "quickcheck" "print_coercions" "print_claset" "print_induct_rules" :: diag and "quickcheck_params" :: thy_decl abbrevs "?<" = "\\<^sub>\\<^sub>1" begin ML_file \~~/src/Tools/misc_legacy.ML\ ML_file \~~/src/Tools/try.ML\ ML_file \~~/src/Tools/quickcheck.ML\ ML_file \~~/src/Tools/solve_direct.ML\ ML_file \~~/src/Tools/IsaPlanner/zipper.ML\ ML_file \~~/src/Tools/IsaPlanner/isand.ML\ ML_file \~~/src/Tools/IsaPlanner/rw_inst.ML\ ML_file \~~/src/Provers/hypsubst.ML\ ML_file \~~/src/Provers/splitter.ML\ ML_file \~~/src/Provers/classical.ML\ ML_file \~~/src/Provers/blast.ML\ ML_file \~~/src/Provers/clasimp.ML\ ML_file \~~/src/Tools/eqsubst.ML\ ML_file \~~/src/Provers/quantifier1.ML\ ML_file \~~/src/Tools/atomize_elim.ML\ ML_file \~~/src/Tools/cong_tac.ML\ ML_file \~~/src/Tools/intuitionistic.ML\ setup \Intuitionistic.method_setup \<^binding>\iprover\\ ML_file \~~/src/Tools/project_rule.ML\ ML_file \~~/src/Tools/subtyping.ML\ ML_file \~~/src/Tools/case_product.ML\ ML \Plugin_Name.declare_setup \<^binding>\extraction\\ ML \ Plugin_Name.declare_setup \<^binding>\quickcheck_random\; Plugin_Name.declare_setup \<^binding>\quickcheck_exhaustive\; Plugin_Name.declare_setup \<^binding>\quickcheck_bounded_forall\; Plugin_Name.declare_setup \<^binding>\quickcheck_full_exhaustive\; Plugin_Name.declare_setup \<^binding>\quickcheck_narrowing\; \ ML \ Plugin_Name.define_setup \<^binding>\quickcheck\ [\<^plugin>\quickcheck_exhaustive\, \<^plugin>\quickcheck_random\, \<^plugin>\quickcheck_bounded_forall\, \<^plugin>\quickcheck_full_exhaustive\, \<^plugin>\quickcheck_narrowing\] \ subsection \Primitive logic\ text \ The definition of the logic is based on Mike Gordon's technical report @{cite "Gordon-TR68"} that describes the first implementation of HOL. However, there are a number of differences. In particular, we start with the definite description operator and introduce Hilbert's \\\ operator only much later. Moreover, axiom \(P \ Q) \ (Q \ P) \ (P = Q)\ is derived from the other axioms. The fact that this axiom is derivable was first noticed by Bruno Barras (for Mike Gordon's line of HOL systems) and later independently by Alexander Maletzky (for Isabelle/HOL). \ subsubsection \Core syntax\ setup \Axclass.class_axiomatization (\<^binding>\type\, [])\ default_sort type setup \Object_Logic.add_base_sort \<^sort>\type\\ setup \Proofterm.set_preproc (Proof_Rewrite_Rules.standard_preproc [])\ axiomatization where fun_arity: "OFCLASS('a \ 'b, type_class)" instance "fun" :: (type, type) type by (rule fun_arity) axiomatization where itself_arity: "OFCLASS('a itself, type_class)" instance itself :: (type) type by (rule itself_arity) typedecl bool judgment Trueprop :: "bool \ prop" ("(_)" 5) axiomatization implies :: "[bool, bool] \ bool" (infixr "\" 25) and eq :: "['a, 'a] \ bool" and The :: "('a \ bool) \ 'a" notation (input) eq (infixl "=" 50) notation (output) eq (infix "=" 50) text \The input syntax for \eq\ is more permissive than the output syntax because of the large amount of material that relies on infixl.\ subsubsection \Defined connectives and quantifiers\ definition True :: bool where "True \ ((\x::bool. x) = (\x. x))" definition All :: "('a \ bool) \ bool" (binder "\" 10) where "All P \ (P = (\x. True))" definition Ex :: "('a \ bool) \ bool" (binder "\" 10) where "Ex P \ \Q. (\x. P x \ Q) \ Q" definition False :: bool where "False \ (\P. P)" definition Not :: "bool \ bool" ("\ _" [40] 40) where not_def: "\ P \ P \ False" definition conj :: "[bool, bool] \ bool" (infixr "\" 35) where and_def: "P \ Q \ \R. (P \ Q \ R) \ R" definition disj :: "[bool, bool] \ bool" (infixr "\" 30) where or_def: "P \ Q \ \R. (P \ R) \ (Q \ R) \ R" definition Uniq :: "('a \ bool) \ bool" where "Uniq P \ (\x y. P x \ P y \ y = x)" definition Ex1 :: "('a \ bool) \ bool" where "Ex1 P \ \x. P x \ (\y. P y \ y = x)" subsubsection \Additional concrete syntax\ syntax (ASCII) "_Uniq" :: "pttrn \ bool \ bool" ("(4?< _./ _)" [0, 10] 10) syntax "_Uniq" :: "pttrn \ bool \ bool" ("(2\\<^sub>\\<^sub>1 _./ _)" [0, 10] 10) translations "\\<^sub>\\<^sub>1x. P" \ "CONST Uniq (\x. P)" print_translation \ [Syntax_Trans.preserve_binder_abs_tr' \<^const_syntax>\Uniq\ \<^syntax_const>\_Uniq\] \ \ \to avoid eta-contraction of body\ syntax (ASCII) "_Ex1" :: "pttrn \ bool \ bool" ("(3EX! _./ _)" [0, 10] 10) syntax (input) "_Ex1" :: "pttrn \ bool \ bool" ("(3?! _./ _)" [0, 10] 10) syntax "_Ex1" :: "pttrn \ bool \ bool" ("(3\!_./ _)" [0, 10] 10) translations "\!x. P" \ "CONST Ex1 (\x. P)" print_translation \ [Syntax_Trans.preserve_binder_abs_tr' \<^const_syntax>\Ex1\ \<^syntax_const>\_Ex1\] \ \ \to avoid eta-contraction of body\ syntax "_Not_Ex" :: "idts \ bool \ bool" ("(3\_./ _)" [0, 10] 10) "_Not_Ex1" :: "pttrn \ bool \ bool" ("(3\!_./ _)" [0, 10] 10) translations "\x. P" \ "\ (\x. P)" "\!x. P" \ "\ (\!x. P)" abbreviation not_equal :: "['a, 'a] \ bool" (infix "\" 50) where "x \ y \ \ (x = y)" notation (ASCII) Not ("~ _" [40] 40) and conj (infixr "&" 35) and disj (infixr "|" 30) and implies (infixr "-->" 25) and not_equal (infix "~=" 50) abbreviation (iff) iff :: "[bool, bool] \ bool" (infixr "\" 25) where "A \ B \ A = B" syntax "_The" :: "[pttrn, bool] \ 'a" ("(3THE _./ _)" [0, 10] 10) translations "THE x. P" \ "CONST The (\x. P)" print_translation \ [(\<^const_syntax>\The\, fn _ => fn [Abs abs] => let val (x, t) = Syntax_Trans.atomic_abs_tr' abs in Syntax.const \<^syntax_const>\_The\ $ x $ t end)] \ \ \To avoid eta-contraction of body\ nonterminal letbinds and letbind syntax "_bind" :: "[pttrn, 'a] \ letbind" ("(2_ =/ _)" 10) "" :: "letbind \ letbinds" ("_") "_binds" :: "[letbind, letbinds] \ letbinds" ("_;/ _") "_Let" :: "[letbinds, 'a] \ 'a" ("(let (_)/ in (_))" [0, 10] 10) nonterminal case_syn and cases_syn syntax "_case_syntax" :: "['a, cases_syn] \ 'b" ("(case _ of/ _)" 10) "_case1" :: "['a, 'b] \ case_syn" ("(2_ \/ _)" 10) "" :: "case_syn \ cases_syn" ("_") "_case2" :: "[case_syn, cases_syn] \ cases_syn" ("_/ | _") syntax (ASCII) "_case1" :: "['a, 'b] \ case_syn" ("(2_ =>/ _)" 10) notation (ASCII) All (binder "ALL " 10) and Ex (binder "EX " 10) notation (input) All (binder "! " 10) and Ex (binder "? " 10) subsubsection \Axioms and basic definitions\ axiomatization where refl: "t = (t::'a)" and subst: "s = t \ P s \ P t" and ext: "(\x::'a. (f x ::'b) = g x) \ (\x. f x) = (\x. g x)" \ \Extensionality is built into the meta-logic, and this rule expresses a related property. It is an eta-expanded version of the traditional rule, and similar to the ABS rule of HOL\ and the_eq_trivial: "(THE x. x = a) = (a::'a)" axiomatization where impI: "(P \ Q) \ P \ Q" and mp: "\P \ Q; P\ \ Q" and True_or_False: "(P = True) \ (P = False)" definition If :: "bool \ 'a \ 'a \ 'a" ("(if (_)/ then (_)/ else (_))" [0, 0, 10] 10) where "If P x y \ (THE z::'a. (P = True \ z = x) \ (P = False \ z = y))" definition Let :: "'a \ ('a \ 'b) \ 'b" where "Let s f \ f s" translations "_Let (_binds b bs) e" \ "_Let b (_Let bs e)" "let x = a in e" \ "CONST Let a (\x. e)" axiomatization undefined :: 'a class default = fixes default :: 'a subsection \Fundamental rules\ subsubsection \Equality\ lemma sym: "s = t \ t = s" by (erule subst) (rule refl) lemma ssubst: "t = s \ P s \ P t" by (drule sym) (erule subst) lemma trans: "\r = s; s = t\ \ r = t" by (erule subst) lemma trans_sym [Pure.elim?]: "r = s \ t = s \ r = t" by (rule trans [OF _ sym]) lemma meta_eq_to_obj_eq: assumes "A \ B" shows "A = B" unfolding assms by (rule refl) text \Useful with \erule\ for proving equalities from known equalities.\ (* a = b | | c = d *) lemma box_equals: "\a = b; a = c; b = d\ \ c = d" by (iprover intro: sym trans) text \For calculational reasoning:\ lemma forw_subst: "a = b \ P b \ P a" by (rule ssubst) lemma back_subst: "P a \ a = b \ P b" by (rule subst) subsubsection \Congruence rules for application\ text \Similar to \AP_THM\ in Gordon's HOL.\ lemma fun_cong: "(f :: 'a \ 'b) = g \ f x = g x" by (iprover intro: refl elim: subst) text \Similar to \AP_TERM\ in Gordon's HOL and FOL's \subst_context\.\ lemma arg_cong: "x = y \ f x = f y" by (iprover intro: refl elim: subst) lemma arg_cong2: "\a = b; c = d\ \ f a c = f b d" by (iprover intro: refl elim: subst) lemma cong: "\f = g; (x::'a) = y\ \ f x = g y" by (iprover intro: refl elim: subst) ML \fun cong_tac ctxt = Cong_Tac.cong_tac ctxt @{thm cong}\ subsubsection \Equality of booleans -- iff\ lemma iffD2: "\P = Q; Q\ \ P" by (erule ssubst) lemma rev_iffD2: "\Q; P = Q\ \ P" by (erule iffD2) lemma iffD1: "Q = P \ Q \ P" by (drule sym) (rule iffD2) lemma rev_iffD1: "Q \ Q = P \ P" by (drule sym) (rule rev_iffD2) lemma iffE: assumes major: "P = Q" and minor: "\P \ Q; Q \ P\ \ R" shows R by (iprover intro: minor impI major [THEN iffD2] major [THEN iffD1]) subsubsection \True (1)\ lemma TrueI: True unfolding True_def by (rule refl) lemma eqTrueE: "P = True \ P" by (erule iffD2) (rule TrueI) subsubsection \Universal quantifier (1)\ lemma spec: "\x::'a. P x \ P x" unfolding All_def by (iprover intro: eqTrueE fun_cong) lemma allE: assumes major: "\x. P x" and minor: "P x \ R" shows R by (iprover intro: minor major [THEN spec]) lemma all_dupE: assumes major: "\x. P x" and minor: "\P x; \x. P x\ \ R" shows R by (iprover intro: minor major major [THEN spec]) subsubsection \False\ text \ Depends upon \spec\; it is impossible to do propositional logic before quantifiers! \ lemma FalseE: "False \ P" unfolding False_def by (erule spec) lemma False_neq_True: "False = True \ P" by (erule eqTrueE [THEN FalseE]) subsubsection \Negation\ lemma notI: assumes "P \ False" shows "\ P" unfolding not_def by (iprover intro: impI assms) lemma False_not_True: "False \ True" by (iprover intro: notI elim: False_neq_True) lemma True_not_False: "True \ False" by (iprover intro: notI dest: sym elim: False_neq_True) lemma notE: "\\ P; P\ \ R" unfolding not_def by (iprover intro: mp [THEN FalseE]) subsubsection \Implication\ lemma impE: assumes "P \ Q" P "Q \ R" shows R by (iprover intro: assms mp) text \Reduces \Q\ to \P \ Q\, allowing substitution in \P\.\ lemma rev_mp: "\P; P \ Q\ \ Q" by (rule mp) lemma contrapos_nn: assumes major: "\ Q" and minor: "P \ Q" shows "\ P" by (iprover intro: notI minor major [THEN notE]) text \Not used at all, but we already have the other 3 combinations.\ lemma contrapos_pn: assumes major: "Q" and minor: "P \ \ Q" shows "\ P" by (iprover intro: notI minor major notE) lemma not_sym: "t \ s \ s \ t" by (erule contrapos_nn) (erule sym) lemma eq_neq_eq_imp_neq: "\x = a; a \ b; b = y\ \ x \ y" by (erule subst, erule ssubst, assumption) subsubsection \Disjunction (1)\ lemma disjE: assumes major: "P \ Q" and minorP: "P \ R" and minorQ: "Q \ R" shows R by (iprover intro: minorP minorQ impI major [unfolded or_def, THEN spec, THEN mp, THEN mp]) subsubsection \Derivation of \iffI\\ text \In an intuitionistic version of HOL \iffI\ needs to be an axiom.\ lemma iffI: assumes "P \ Q" and "Q \ P" shows "P = Q" proof (rule disjE[OF True_or_False[of P]]) assume 1: "P = True" note Q = assms(1)[OF eqTrueE[OF this]] from 1 show ?thesis proof (rule ssubst) from True_or_False[of Q] show "True = Q" proof (rule disjE) assume "Q = True" thus ?thesis by(rule sym) next assume "Q = False" with Q have False by (rule rev_iffD1) thus ?thesis by (rule FalseE) qed qed next assume 2: "P = False" thus ?thesis proof (rule ssubst) from True_or_False[of Q] show "False = Q" proof (rule disjE) assume "Q = True" from 2 assms(2)[OF eqTrueE[OF this]] have False by (rule iffD1) thus ?thesis by (rule FalseE) next assume "Q = False" thus ?thesis by(rule sym) qed qed qed subsubsection \True (2)\ lemma eqTrueI: "P \ P = True" by (iprover intro: iffI TrueI) subsubsection \Universal quantifier (2)\ lemma allI: assumes "\x::'a. P x" shows "\x. P x" unfolding All_def by (iprover intro: ext eqTrueI assms) subsubsection \Existential quantifier\ lemma exI: "P x \ \x::'a. P x" unfolding Ex_def by (iprover intro: allI allE impI mp) lemma exE: assumes major: "\x::'a. P x" and minor: "\x. P x \ Q" shows "Q" by (rule major [unfolded Ex_def, THEN spec, THEN mp]) (iprover intro: impI [THEN allI] minor) subsubsection \Conjunction\ lemma conjI: "\P; Q\ \ P \ Q" unfolding and_def by (iprover intro: impI [THEN allI] mp) lemma conjunct1: "\P \ Q\ \ P" unfolding and_def by (iprover intro: impI dest: spec mp) lemma conjunct2: "\P \ Q\ \ Q" unfolding and_def by (iprover intro: impI dest: spec mp) lemma conjE: assumes major: "P \ Q" and minor: "\P; Q\ \ R" shows R proof (rule minor) show P by (rule major [THEN conjunct1]) show Q by (rule major [THEN conjunct2]) qed lemma context_conjI: assumes P "P \ Q" shows "P \ Q" by (iprover intro: conjI assms) subsubsection \Disjunction (2)\ lemma disjI1: "P \ P \ Q" unfolding or_def by (iprover intro: allI impI mp) lemma disjI2: "Q \ P \ Q" unfolding or_def by (iprover intro: allI impI mp) subsubsection \Classical logic\ lemma classical: assumes "\ P \ P" shows P proof (rule True_or_False [THEN disjE]) show P if "P = True" using that by (iprover intro: eqTrueE) show P if "P = False" proof (intro notI assms) assume P with that show False by (iprover elim: subst) qed qed lemmas ccontr = FalseE [THEN classical] text \\notE\ with premises exchanged; it discharges \\ R\ so that it can be used to make elimination rules.\ lemma rev_notE: assumes premp: P and premnot: "\ R \ \ P" shows R by (iprover intro: ccontr notE [OF premnot premp]) text \Double negation law.\ lemma notnotD: "\\ P \ P" by (iprover intro: ccontr notE ) lemma contrapos_pp: assumes p1: Q and p2: "\ P \ \ Q" shows P by (iprover intro: classical p1 p2 notE) subsubsection \Unique existence\ lemma Uniq_I [intro?]: assumes "\x y. \P x; P y\ \ y = x" shows "Uniq P" unfolding Uniq_def by (iprover intro: assms allI impI) lemma Uniq_D [dest?]: "\Uniq P; P a; P b\ \ a=b" unfolding Uniq_def by (iprover dest: spec mp) lemma ex1I: assumes "P a" "\x. P x \ x = a" shows "\!x. P x" unfolding Ex1_def by (iprover intro: assms exI conjI allI impI) text \Sometimes easier to use: the premises have no shared variables. Safe!\ lemma ex_ex1I: assumes ex_prem: "\x. P x" and eq: "\x y. \P x; P y\ \ x = y" shows "\!x. P x" by (iprover intro: ex_prem [THEN exE] ex1I eq) lemma ex1E: assumes major: "\!x. P x" and minor: "\x. \P x; \y. P y \ y = x\ \ R" shows R proof (rule major [unfolded Ex1_def, THEN exE]) show "\x. P x \ (\y. P y \ y = x) \ R" by (iprover intro: minor elim: conjE) qed lemma ex1_implies_ex: "\!x. P x \ \x. P x" by (iprover intro: exI elim: ex1E) subsubsection \Classical intro rules for disjunction and existential quantifiers\ lemma disjCI: assumes "\ Q \ P" shows "P \ Q" by (rule classical) (iprover intro: assms disjI1 disjI2 notI elim: notE) lemma excluded_middle: "\ P \ P" by (iprover intro: disjCI) text \ case distinction as a natural deduction rule. Note that \\ P\ is the second case, not the first. \ lemma case_split [case_names True False]: assumes "P \ Q" "\ P \ Q" shows Q using excluded_middle [of P] by (iprover intro: assms elim: disjE) text \Classical implies (\\\) elimination.\ lemma impCE: assumes major: "P \ Q" and minor: "\ P \ R" "Q \ R" shows R using excluded_middle [of P] by (iprover intro: minor major [THEN mp] elim: disjE)+ text \ This version of \\\ elimination works on \Q\ before \P\. It works best for those cases in which \P\ holds "almost everywhere". Can't install as default: would break old proofs. \ lemma impCE': assumes major: "P \ Q" and minor: "Q \ R" "\ P \ R" shows R using assms by (elim impCE) text \Classical \\\ elimination.\ lemma iffCE: assumes major: "P = Q" and minor: "\P; Q\ \ R" "\\ P; \ Q\ \ R" shows R by (rule major [THEN iffE]) (iprover intro: minor elim: impCE notE) lemma exCI: assumes "\x. \ P x \ P a" shows "\x. P x" by (rule ccontr) (iprover intro: assms exI allI notI notE [of "\x. P x"]) subsubsection \Intuitionistic Reasoning\ lemma impE': assumes 1: "P \ Q" and 2: "Q \ R" and 3: "P \ Q \ P" shows R proof - from 3 and 1 have P . with 1 have Q by (rule impE) with 2 show R . qed lemma allE': assumes 1: "\x. P x" and 2: "P x \ \x. P x \ Q" shows Q proof - from 1 have "P x" by (rule spec) from this and 1 show Q by (rule 2) qed lemma notE': assumes 1: "\ P" and 2: "\ P \ P" shows R proof - from 2 and 1 have P . with 1 show R by (rule notE) qed lemma TrueE: "True \ P \ P" . lemma notFalseE: "\ False \ P \ P" . lemmas [Pure.elim!] = disjE iffE FalseE conjE exE TrueE notFalseE and [Pure.intro!] = iffI conjI impI TrueI notI allI refl and [Pure.elim 2] = allE notE' impE' and [Pure.intro] = exI disjI2 disjI1 lemmas [trans] = trans and [sym] = sym not_sym and [Pure.elim?] = iffD1 iffD2 impE subsubsection \Atomizing meta-level connectives\ axiomatization where eq_reflection: "x = y \ x \ y" \ \admissible axiom\ lemma atomize_all [atomize]: "(\x. P x) \ Trueprop (\x. P x)" proof assume "\x. P x" then show "\x. P x" .. next assume "\x. P x" then show "\x. P x" by (rule allE) qed lemma atomize_imp [atomize]: "(A \ B) \ Trueprop (A \ B)" proof assume r: "A \ B" show "A \ B" by (rule impI) (rule r) next assume "A \ B" and A then show B by (rule mp) qed lemma atomize_not: "(A \ False) \ Trueprop (\ A)" proof assume r: "A \ False" show "\ A" by (rule notI) (rule r) next assume "\ A" and A then show False by (rule notE) qed lemma atomize_eq [atomize, code]: "(x \ y) \ Trueprop (x = y)" proof assume "x \ y" show "x = y" by (unfold \x \ y\) (rule refl) next assume "x = y" then show "x \ y" by (rule eq_reflection) qed lemma atomize_conj [atomize]: "(A &&& B) \ Trueprop (A \ B)" proof assume conj: "A &&& B" show "A \ B" proof (rule conjI) from conj show A by (rule conjunctionD1) from conj show B by (rule conjunctionD2) qed next assume conj: "A \ B" show "A &&& B" proof - from conj show A .. from conj show B .. qed qed lemmas [symmetric, rulify] = atomize_all atomize_imp and [symmetric, defn] = atomize_all atomize_imp atomize_eq subsubsection \Atomizing elimination rules\ lemma atomize_exL[atomize_elim]: "(\x. P x \ Q) \ ((\x. P x) \ Q)" by rule iprover+ lemma atomize_conjL[atomize_elim]: "(A \ B \ C) \ (A \ B \ C)" by rule iprover+ lemma atomize_disjL[atomize_elim]: "((A \ C) \ (B \ C) \ C) \ ((A \ B \ C) \ C)" by rule iprover+ lemma atomize_elimL[atomize_elim]: "(\B. (A \ B) \ B) \ Trueprop A" .. subsection \Package setup\ ML_file \Tools/hologic.ML\ ML_file \Tools/rewrite_hol_proof.ML\ setup \Proofterm.set_preproc (Proof_Rewrite_Rules.standard_preproc Rewrite_HOL_Proof.rews)\ subsubsection \Sledgehammer setup\ text \ Theorems blacklisted to Sledgehammer. These theorems typically produce clauses that are prolific (match too many equality or membership literals) and relate to seldom-used facts. Some duplicate other rules. \ named_theorems no_atp "theorems that should be filtered out by Sledgehammer" subsubsection \Classical Reasoner setup\ lemma imp_elim: "P \ Q \ (\ R \ P) \ (Q \ R) \ R" by (rule classical) iprover lemma swap: "\ P \ (\ R \ P) \ R" by (rule classical) iprover lemma thin_refl: "\x = x; PROP W\ \ PROP W" . ML \ structure Hypsubst = Hypsubst ( val dest_eq = HOLogic.dest_eq val dest_Trueprop = HOLogic.dest_Trueprop val dest_imp = HOLogic.dest_imp val eq_reflection = @{thm eq_reflection} val rev_eq_reflection = @{thm meta_eq_to_obj_eq} val imp_intr = @{thm impI} val rev_mp = @{thm rev_mp} val subst = @{thm subst} val sym = @{thm sym} val thin_refl = @{thm thin_refl}; ); open Hypsubst; structure Classical = Classical ( val imp_elim = @{thm imp_elim} val not_elim = @{thm notE} val swap = @{thm swap} val classical = @{thm classical} val sizef = Drule.size_of_thm val hyp_subst_tacs = [Hypsubst.hyp_subst_tac] ); structure Basic_Classical: BASIC_CLASSICAL = Classical; open Basic_Classical; \ setup \ (*prevent substitution on bool*) let fun non_bool_eq (\<^const_name>\HOL.eq\, Type (_, [T, _])) = T <> \<^typ>\bool\ | non_bool_eq _ = false; fun hyp_subst_tac' ctxt = SUBGOAL (fn (goal, i) => if Term.exists_Const non_bool_eq goal then Hypsubst.hyp_subst_tac ctxt i else no_tac); in Context_Rules.addSWrapper (fn ctxt => fn tac => hyp_subst_tac' ctxt ORELSE' tac) end \ declare iffI [intro!] and notI [intro!] and impI [intro!] and disjCI [intro!] and conjI [intro!] and TrueI [intro!] and refl [intro!] declare iffCE [elim!] and FalseE [elim!] and impCE [elim!] and disjE [elim!] and conjE [elim!] declare ex_ex1I [intro!] and allI [intro!] and exI [intro] declare exE [elim!] allE [elim] ML \val HOL_cs = claset_of \<^context>\ lemma contrapos_np: "\ Q \ (\ P \ Q) \ P" by (erule swap) declare ex_ex1I [rule del, intro! 2] and ex1I [intro] declare ext [intro] lemmas [intro?] = ext and [elim?] = ex1_implies_ex text \Better than \ex1E\ for classical reasoner: needs no quantifier duplication!\ lemma alt_ex1E [elim!]: assumes major: "\!x. P x" and minor: "\x. \P x; \y y'. P y \ P y' \ y = y'\ \ R" shows R proof (rule ex1E [OF major minor]) show "\y y'. P y \ P y' \ y = y'" if "P x" and \
: "\y. P y \ y = x" for x using \P x\ \
\
by fast qed assumption text \And again using Uniq\ lemma alt_ex1E': assumes "\!x. P x" "\x. \P x; \\<^sub>\\<^sub>1x. P x\ \ R" shows R using assms unfolding Uniq_def by fast lemma ex1_iff_ex_Uniq: "(\!x. P x) \ (\x. P x) \ (\\<^sub>\\<^sub>1x. P x)" unfolding Uniq_def by fast ML \ structure Blast = Blast ( structure Classical = Classical val Trueprop_const = dest_Const \<^const>\Trueprop\ val equality_name = \<^const_name>\HOL.eq\ val not_name = \<^const_name>\Not\ val notE = @{thm notE} val ccontr = @{thm ccontr} val hyp_subst_tac = Hypsubst.blast_hyp_subst_tac ); val blast_tac = Blast.blast_tac; \ subsubsection \THE: definite description operator\ lemma the_equality [intro]: assumes "P a" and "\x. P x \ x = a" shows "(THE x. P x) = a" by (blast intro: assms trans [OF arg_cong [where f=The] the_eq_trivial]) lemma theI: assumes "P a" and "\x. P x \ x = a" shows "P (THE x. P x)" by (iprover intro: assms the_equality [THEN ssubst]) lemma theI': "\!x. P x \ P (THE x. P x)" by (blast intro: theI) text \Easier to apply than \theI\: only one occurrence of \P\.\ lemma theI2: assumes "P a" "\x. P x \ x = a" "\x. P x \ Q x" shows "Q (THE x. P x)" by (iprover intro: assms theI) lemma the1I2: assumes "\!x. P x" "\x. P x \ Q x" shows "Q (THE x. P x)" by (iprover intro: assms(2) theI2[where P=P and Q=Q] ex1E[OF assms(1)] elim: allE impE) lemma the1_equality [elim?]: "\\!x. P x; P a\ \ (THE x. P x) = a" by blast lemma the1_equality': "\\\<^sub>\\<^sub>1x. P x; P a\ \ (THE x. P x) = a" unfolding Uniq_def by blast lemma the_sym_eq_trivial: "(THE y. x = y) = x" by blast subsubsection \Simplifier\ lemma eta_contract_eq: "(\s. f s) = f" .. lemma simp_thms: shows not_not: "(\ \ P) = P" and Not_eq_iff: "((\ P) = (\ Q)) = (P = Q)" and "(P \ Q) = (P = (\ Q))" "(P \ \P) = True" "(\ P \ P) = True" "(x = x) = True" and not_True_eq_False [code]: "(\ True) = False" and not_False_eq_True [code]: "(\ False) = True" and "(\ P) \ P" "P \ (\ P)" "(True = P) = P" and eq_True: "(P = True) = P" and "(False = P) = (\ P)" and eq_False: "(P = False) = (\ P)" and "(True \ P) = P" "(False \ P) = True" "(P \ True) = True" "(P \ P) = True" "(P \ False) = (\ P)" "(P \ \ P) = (\ P)" "(P \ True) = P" "(True \ P) = P" "(P \ False) = False" "(False \ P) = False" "(P \ P) = P" "(P \ (P \ Q)) = (P \ Q)" "(P \ \ P) = False" "(\ P \ P) = False" "(P \ True) = True" "(True \ P) = True" "(P \ False) = P" "(False \ P) = P" "(P \ P) = P" "(P \ (P \ Q)) = (P \ Q)" and "(\x. P) = P" "(\x. P) = P" "\x. x = t" "\x. t = x" and "\P. (\x. x = t \ P x) = P t" "\P. (\x. t = x \ P x) = P t" "\P. (\x. x = t \ P x) = P t" "\P. (\x. t = x \ P x) = P t" "(\x. x \ t) = False" "(\x. t \ x) = False" by (blast, blast, blast, blast, blast, iprover+) lemma disj_absorb: "A \ A \ A" by blast lemma disj_left_absorb: "A \ (A \ B) \ A \ B" by blast lemma conj_absorb: "A \ A \ A" by blast lemma conj_left_absorb: "A \ (A \ B) \ A \ B" by blast lemma eq_ac: shows eq_commute: "a = b \ b = a" and iff_left_commute: "(P \ (Q \ R)) \ (Q \ (P \ R))" and iff_assoc: "((P \ Q) \ R) \ (P \ (Q \ R))" by (iprover, blast+) lemma neq_commute: "a \ b \ b \ a" by iprover lemma conj_comms: shows conj_commute: "P \ Q \ Q \ P" and conj_left_commute: "P \ (Q \ R) \ Q \ (P \ R)" by iprover+ lemma conj_assoc: "(P \ Q) \ R \ P \ (Q \ R)" by iprover lemmas conj_ac = conj_commute conj_left_commute conj_assoc lemma disj_comms: shows disj_commute: "P \ Q \ Q \ P" and disj_left_commute: "P \ (Q \ R) \ Q \ (P \ R)" by iprover+ lemma disj_assoc: "(P \ Q) \ R \ P \ (Q \ R)" by iprover lemmas disj_ac = disj_commute disj_left_commute disj_assoc lemma conj_disj_distribL: "P \ (Q \ R) \ P \ Q \ P \ R" by iprover lemma conj_disj_distribR: "(P \ Q) \ R \ P \ R \ Q \ R" by iprover lemma disj_conj_distribL: "P \ (Q \ R) \ (P \ Q) \ (P \ R)" by iprover lemma disj_conj_distribR: "(P \ Q) \ R \ (P \ R) \ (Q \ R)" by iprover lemma imp_conjR: "(P \ (Q \ R)) = ((P \ Q) \ (P \ R))" by iprover lemma imp_conjL: "((P \ Q) \ R) = (P \ (Q \ R))" by iprover lemma imp_disjL: "((P \ Q) \ R) = ((P \ R) \ (Q \ R))" by iprover text \These two are specialized, but \imp_disj_not1\ is useful in \Auth/Yahalom\.\ lemma imp_disj_not1: "(P \ Q \ R) \ (\ Q \ P \ R)" by blast lemma imp_disj_not2: "(P \ Q \ R) \ (\ R \ P \ Q)" by blast lemma imp_disj1: "((P \ Q) \ R) \ (P \ Q \ R)" by blast lemma imp_disj2: "(Q \ (P \ R)) \ (P \ Q \ R)" by blast lemma imp_cong: "(P = P') \ (P' \ (Q = Q')) \ ((P \ Q) \ (P' \ Q'))" by iprover lemma de_Morgan_disj: "\ (P \ Q) \ \ P \ \ Q" by iprover lemma de_Morgan_conj: "\ (P \ Q) \ \ P \ \ Q" by blast lemma not_imp: "\ (P \ Q) \ P \ \ Q" by blast lemma not_iff: "P \ Q \ (P \ \ Q)" by blast lemma disj_not1: "\ P \ Q \ (P \ Q)" by blast lemma disj_not2: "P \ \ Q \ (Q \ P)" by blast \ \changes orientation :-(\ lemma imp_conv_disj: "(P \ Q) \ (\ P) \ Q" by blast lemma disj_imp: "P \ Q \ \ P \ Q" by blast lemma iff_conv_conj_imp: "(P \ Q) \ (P \ Q) \ (Q \ P)" by iprover lemma cases_simp: "(P \ Q) \ (\ P \ Q) \ Q" \ \Avoids duplication of subgoals after \if_split\, when the true and false\ \ \cases boil down to the same thing.\ by blast lemma not_all: "\ (\x. P x) \ (\x. \ P x)" by blast lemma imp_all: "((\x. P x) \ Q) \ (\x. P x \ Q)" by blast lemma not_ex: "\ (\x. P x) \ (\x. \ P x)" by iprover lemma imp_ex: "((\x. P x) \ Q) \ (\x. P x \ Q)" by iprover lemma all_not_ex: "(\x. P x) \ \ (\x. \ P x)" by blast declare All_def [no_atp] lemma ex_disj_distrib: "(\x. P x \ Q x) \ (\x. P x) \ (\x. Q x)" by iprover lemma all_conj_distrib: "(\x. P x \ Q x) \ (\x. P x) \ (\x. Q x)" by iprover text \ \<^medskip> The \\\ congruence rule: not included by default! May slow rewrite proofs down by as much as 50\%\ lemma conj_cong: "P = P' \ (P' \ Q = Q') \ (P \ Q) = (P' \ Q')" by iprover lemma rev_conj_cong: "Q = Q' \ (Q' \ P = P') \ (P \ Q) = (P' \ Q')" by iprover text \The \|\ congruence rule: not included by default!\ lemma disj_cong: "P = P' \ (\ P' \ Q = Q') \ (P \ Q) = (P' \ Q')" by blast text \\<^medskip> if-then-else rules\ lemma if_True [code]: "(if True then x else y) = x" unfolding If_def by blast lemma if_False [code]: "(if False then x else y) = y" unfolding If_def by blast lemma if_P: "P \ (if P then x else y) = x" unfolding If_def by blast lemma if_not_P: "\ P \ (if P then x else y) = y" unfolding If_def by blast lemma if_split: "P (if Q then x else y) = ((Q \ P x) \ (\ Q \ P y))" proof (rule case_split [of Q]) show ?thesis if Q using that by (simplesubst if_P) blast+ show ?thesis if "\ Q" using that by (simplesubst if_not_P) blast+ qed lemma if_split_asm: "P (if Q then x else y) = (\ ((Q \ \ P x) \ (\ Q \ \ P y)))" by (simplesubst if_split) blast lemmas if_splits [no_atp] = if_split if_split_asm lemma if_cancel: "(if c then x else x) = x" by (simplesubst if_split) blast lemma if_eq_cancel: "(if x = y then y else x) = x" by (simplesubst if_split) blast lemma if_bool_eq_conj: "(if P then Q else R) = ((P \ Q) \ (\ P \ R))" \ \This form is useful for expanding \if\s on the RIGHT of the \\\ symbol.\ by (rule if_split) lemma if_bool_eq_disj: "(if P then Q else R) = ((P \ Q) \ (\ P \ R))" \ \And this form is useful for expanding \if\s on the LEFT.\ by (simplesubst if_split) blast lemma Eq_TrueI: "P \ P \ True" unfolding atomize_eq by iprover lemma Eq_FalseI: "\ P \ P \ False" unfolding atomize_eq by iprover text \\<^medskip> let rules for simproc\ lemma Let_folded: "f x \ g x \ Let x f \ Let x g" by (unfold Let_def) lemma Let_unfold: "f x \ g \ Let x f \ g" by (unfold Let_def) text \ The following copy of the implication operator is useful for fine-tuning congruence rules. It instructs the simplifier to simplify its premise. \ definition simp_implies :: "prop \ prop \ prop" (infixr "=simp=>" 1) where "simp_implies \ (\)" lemma simp_impliesI: assumes PQ: "(PROP P \ PROP Q)" shows "PROP P =simp=> PROP Q" unfolding simp_implies_def by (iprover intro: PQ) lemma simp_impliesE: assumes PQ: "PROP P =simp=> PROP Q" and P: "PROP P" and QR: "PROP Q \ PROP R" shows "PROP R" by (iprover intro: QR P PQ [unfolded simp_implies_def]) lemma simp_implies_cong: assumes PP' :"PROP P \ PROP P'" and P'QQ': "PROP P' \ (PROP Q \ PROP Q')" shows "(PROP P =simp=> PROP Q) \ (PROP P' =simp=> PROP Q')" unfolding simp_implies_def proof (rule equal_intr_rule) assume PQ: "PROP P \ PROP Q" and P': "PROP P'" from PP' [symmetric] and P' have "PROP P" by (rule equal_elim_rule1) then have "PROP Q" by (rule PQ) with P'QQ' [OF P'] show "PROP Q'" by (rule equal_elim_rule1) next assume P'Q': "PROP P' \ PROP Q'" and P: "PROP P" from PP' and P have P': "PROP P'" by (rule equal_elim_rule1) then have "PROP Q'" by (rule P'Q') with P'QQ' [OF P', symmetric] show "PROP Q" by (rule equal_elim_rule1) qed lemma uncurry: assumes "P \ Q \ R" shows "P \ Q \ R" using assms by blast lemma iff_allI: assumes "\x. P x = Q x" shows "(\x. P x) = (\x. Q x)" using assms by blast lemma iff_exI: assumes "\x. P x = Q x" shows "(\x. P x) = (\x. Q x)" using assms by blast lemma all_comm: "(\x y. P x y) = (\y x. P x y)" by blast lemma ex_comm: "(\x y. P x y) = (\y x. P x y)" by blast ML_file \Tools/simpdata.ML\ ML \open Simpdata\ setup \ map_theory_simpset (put_simpset HOL_basic_ss) #> Simplifier.method_setup Splitter.split_modifiers \ -simproc_setup defined_Ex ("\x. P x") = \K Quantifier1.rearrange_ex\ -simproc_setup defined_All ("\x. P x") = \K Quantifier1.rearrange_all\ +simproc_setup defined_Ex ("\x. P x") = \K Quantifier1.rearrange_Ex\ +simproc_setup defined_All ("\x. P x") = \K Quantifier1.rearrange_All\ text \Simproc for proving \(y = x) \ False\ from premise \\ (x = y)\:\ simproc_setup neq ("x = y") = \fn _ => let val neq_to_EQ_False = @{thm not_sym} RS @{thm Eq_FalseI}; fun is_neq eq lhs rhs thm = (case Thm.prop_of thm of _ $ (Not $ (eq' $ l' $ r')) => Not = HOLogic.Not andalso eq' = eq andalso r' aconv lhs andalso l' aconv rhs | _ => false); fun proc ss ct = (case Thm.term_of ct of eq $ lhs $ rhs => (case find_first (is_neq eq lhs rhs) (Simplifier.prems_of ss) of SOME thm => SOME (thm RS neq_to_EQ_False) | NONE => NONE) | _ => NONE); in proc end \ simproc_setup let_simp ("Let x f") = \ let fun count_loose (Bound i) k = if i >= k then 1 else 0 | count_loose (s $ t) k = count_loose s k + count_loose t k | count_loose (Abs (_, _, t)) k = count_loose t (k + 1) | count_loose _ _ = 0; fun is_trivial_let (Const (\<^const_name>\Let\, _) $ x $ t) = (case t of Abs (_, _, t') => count_loose t' 0 <= 1 | _ => true); in fn _ => fn ctxt => fn ct => if is_trivial_let (Thm.term_of ct) then SOME @{thm Let_def} (*no or one ocurrence of bound variable*) else let (*Norbert Schirmer's case*) val t = Thm.term_of ct; val (t', ctxt') = yield_singleton (Variable.import_terms false) t ctxt; in Option.map (hd o Variable.export ctxt' ctxt o single) (case t' of Const (\<^const_name>\Let\,_) $ x $ f => (* x and f are already in normal form *) if is_Free x orelse is_Bound x orelse is_Const x then SOME @{thm Let_def} else let val n = case f of (Abs (x, _, _)) => x | _ => "x"; val cx = Thm.cterm_of ctxt x; val xT = Thm.typ_of_cterm cx; val cf = Thm.cterm_of ctxt f; val fx_g = Simplifier.rewrite ctxt (Thm.apply cf cx); val (_ $ _ $ g) = Thm.prop_of fx_g; val g' = abstract_over (x, g); val abs_g'= Abs (n, xT, g'); in if g aconv g' then let val rl = infer_instantiate ctxt [(("f", 0), cf), (("x", 0), cx)] @{thm Let_unfold}; in SOME (rl OF [fx_g]) end else if (Envir.beta_eta_contract f) aconv (Envir.beta_eta_contract abs_g') then NONE (*avoid identity conversion*) else let val g'x = abs_g' $ x; val g_g'x = Thm.symmetric (Thm.beta_conversion false (Thm.cterm_of ctxt g'x)); val rl = @{thm Let_folded} |> infer_instantiate ctxt [(("f", 0), Thm.cterm_of ctxt f), (("x", 0), cx), (("g", 0), Thm.cterm_of ctxt abs_g')]; in SOME (rl OF [Thm.transitive fx_g g_g'x]) end end | _ => NONE) end end \ lemma True_implies_equals: "(True \ PROP P) \ PROP P" proof assume "True \ PROP P" from this [OF TrueI] show "PROP P" . next assume "PROP P" then show "PROP P" . qed lemma implies_True_equals: "(PROP P \ True) \ Trueprop True" by standard (intro TrueI) lemma False_implies_equals: "(False \ P) \ Trueprop True" by standard simp_all (* It seems that making this a simp rule is slower than using the simproc below *) lemma implies_False_swap: "(False \ PROP P \ PROP Q) \ (PROP P \ False \ PROP Q)" by (rule swap_prems_eq) ML \ fun eliminate_false_implies ct = let val (prems, concl) = Logic.strip_horn (Thm.term_of ct) fun go n = if n > 1 then Conv.rewr_conv @{thm Pure.swap_prems_eq} then_conv Conv.arg_conv (go (n - 1)) then_conv Conv.rewr_conv @{thm HOL.implies_True_equals} else Conv.rewr_conv @{thm HOL.False_implies_equals} in case concl of Const (@{const_name HOL.Trueprop}, _) $ _ => SOME (go (length prems) ct) | _ => NONE end \ simproc_setup eliminate_false_implies ("False \ PROP P") = \K (K eliminate_false_implies)\ lemma ex_simps: "\P Q. (\x. P x \ Q) = ((\x. P x) \ Q)" "\P Q. (\x. P \ Q x) = (P \ (\x. Q x))" "\P Q. (\x. P x \ Q) = ((\x. P x) \ Q)" "\P Q. (\x. P \ Q x) = (P \ (\x. Q x))" "\P Q. (\x. P x \ Q) = ((\x. P x) \ Q)" "\P Q. (\x. P \ Q x) = (P \ (\x. Q x))" \ \Miniscoping: pushing in existential quantifiers.\ by (iprover | blast)+ lemma all_simps: "\P Q. (\x. P x \ Q) = ((\x. P x) \ Q)" "\P Q. (\x. P \ Q x) = (P \ (\x. Q x))" "\P Q. (\x. P x \ Q) = ((\x. P x) \ Q)" "\P Q. (\x. P \ Q x) = (P \ (\x. Q x))" "\P Q. (\x. P x \ Q) = ((\x. P x) \ Q)" "\P Q. (\x. P \ Q x) = (P \ (\x. Q x))" \ \Miniscoping: pushing in universal quantifiers.\ by (iprover | blast)+ lemmas [simp] = triv_forall_equality \ \prunes params\ True_implies_equals implies_True_equals \ \prune \True\ in asms\ False_implies_equals \ \prune \False\ in asms\ if_True if_False if_cancel if_eq_cancel imp_disjL \ \In general it seems wrong to add distributive laws by default: they might cause exponential blow-up. But \imp_disjL\ has been in for a while and cannot be removed without affecting existing proofs. Moreover, rewriting by \(P \ Q \ R) = ((P \ R) \ (Q \ R))\ might be justified on the grounds that it allows simplification of \R\ in the two cases.\ conj_assoc disj_assoc de_Morgan_conj de_Morgan_disj imp_disj1 imp_disj2 not_imp disj_not1 not_all not_ex cases_simp the_eq_trivial the_sym_eq_trivial ex_simps all_simps simp_thms lemmas [cong] = imp_cong simp_implies_cong lemmas [split] = if_split ML \val HOL_ss = simpset_of \<^context>\ text \Simplifies \x\ assuming \c\ and \y\ assuming \\ c\.\ lemma if_cong: assumes "b = c" and "c \ x = u" and "\ c \ y = v" shows "(if b then x else y) = (if c then u else v)" using assms by simp text \Prevents simplification of \x\ and \y\: faster and allows the execution of functional programs.\ lemma if_weak_cong [cong]: assumes "b = c" shows "(if b then x else y) = (if c then x else y)" using assms by (rule arg_cong) text \Prevents simplification of t: much faster\ lemma let_weak_cong: assumes "a = b" shows "(let x = a in t x) = (let x = b in t x)" using assms by (rule arg_cong) text \To tidy up the result of a simproc. Only the RHS will be simplified.\ lemma eq_cong2: assumes "u = u'" shows "(t \ u) \ (t \ u')" using assms by simp lemma if_distrib: "f (if c then x else y) = (if c then f x else f y)" by simp lemma if_distribR: "(if b then f else g) x = (if b then f x else g x)" by simp lemma all_if_distrib: "(\x. if x = a then P x else Q x) \ P a \ (\x. x\a \ Q x)" by auto lemma ex_if_distrib: "(\x. if x = a then P x else Q x) \ P a \ (\x. x\a \ Q x)" by auto lemma if_if_eq_conj: "(if P then if Q then x else y else y) = (if P \ Q then x else y)" by simp text \As a simplification rule, it replaces all function equalities by first-order equalities.\ lemma fun_eq_iff: "f = g \ (\x. f x = g x)" by auto subsubsection \Generic cases and induction\ text \Rule projections:\ ML \ structure Project_Rule = Project_Rule ( val conjunct1 = @{thm conjunct1} val conjunct2 = @{thm conjunct2} val mp = @{thm mp} ); \ context begin qualified definition "induct_forall P \ \x. P x" qualified definition "induct_implies A B \ A \ B" qualified definition "induct_equal x y \ x = y" qualified definition "induct_conj A B \ A \ B" qualified definition "induct_true \ True" qualified definition "induct_false \ False" lemma induct_forall_eq: "(\x. P x) \ Trueprop (induct_forall (\x. P x))" by (unfold atomize_all induct_forall_def) lemma induct_implies_eq: "(A \ B) \ Trueprop (induct_implies A B)" by (unfold atomize_imp induct_implies_def) lemma induct_equal_eq: "(x \ y) \ Trueprop (induct_equal x y)" by (unfold atomize_eq induct_equal_def) lemma induct_conj_eq: "(A &&& B) \ Trueprop (induct_conj A B)" by (unfold atomize_conj induct_conj_def) lemmas induct_atomize' = induct_forall_eq induct_implies_eq induct_conj_eq lemmas induct_atomize = induct_atomize' induct_equal_eq lemmas induct_rulify' [symmetric] = induct_atomize' lemmas induct_rulify [symmetric] = induct_atomize lemmas induct_rulify_fallback = induct_forall_def induct_implies_def induct_equal_def induct_conj_def induct_true_def induct_false_def lemma induct_forall_conj: "induct_forall (\x. induct_conj (A x) (B x)) = induct_conj (induct_forall A) (induct_forall B)" by (unfold induct_forall_def induct_conj_def) iprover lemma induct_implies_conj: "induct_implies C (induct_conj A B) = induct_conj (induct_implies C A) (induct_implies C B)" by (unfold induct_implies_def induct_conj_def) iprover lemma induct_conj_curry: "(induct_conj A B \ PROP C) \ (A \ B \ PROP C)" proof assume r: "induct_conj A B \ PROP C" assume ab: A B show "PROP C" by (rule r) (simp add: induct_conj_def ab) next assume r: "A \ B \ PROP C" assume ab: "induct_conj A B" show "PROP C" by (rule r) (simp_all add: ab [unfolded induct_conj_def]) qed lemmas induct_conj = induct_forall_conj induct_implies_conj induct_conj_curry lemma induct_trueI: "induct_true" by (simp add: induct_true_def) text \Method setup.\ ML_file \~~/src/Tools/induct.ML\ ML \ structure Induct = Induct ( val cases_default = @{thm case_split} val atomize = @{thms induct_atomize} val rulify = @{thms induct_rulify'} val rulify_fallback = @{thms induct_rulify_fallback} val equal_def = @{thm induct_equal_def} fun dest_def (Const (\<^const_name>\induct_equal\, _) $ t $ u) = SOME (t, u) | dest_def _ = NONE fun trivial_tac ctxt = match_tac ctxt @{thms induct_trueI} ) \ ML_file \~~/src/Tools/induction.ML\ declaration \ fn _ => Induct.map_simpset (fn ss => ss addsimprocs [Simplifier.make_simproc \<^context> "swap_induct_false" {lhss = [\<^term>\induct_false \ PROP P \ PROP Q\], proc = fn _ => fn _ => fn ct => (case Thm.term_of ct of _ $ (P as _ $ \<^const>\induct_false\) $ (_ $ Q $ _) => if P <> Q then SOME Drule.swap_prems_eq else NONE | _ => NONE)}, Simplifier.make_simproc \<^context> "induct_equal_conj_curry" {lhss = [\<^term>\induct_conj P Q \ PROP R\], proc = fn _ => fn _ => fn ct => (case Thm.term_of ct of _ $ (_ $ P) $ _ => let fun is_conj (\<^const>\induct_conj\ $ P $ Q) = is_conj P andalso is_conj Q | is_conj (Const (\<^const_name>\induct_equal\, _) $ _ $ _) = true | is_conj \<^const>\induct_true\ = true | is_conj \<^const>\induct_false\ = true | is_conj _ = false in if is_conj P then SOME @{thm induct_conj_curry} else NONE end | _ => NONE)}] |> Simplifier.set_mksimps (fn ctxt => Simpdata.mksimps Simpdata.mksimps_pairs ctxt #> map (rewrite_rule ctxt (map Thm.symmetric @{thms induct_rulify_fallback})))) \ text \Pre-simplification of induction and cases rules\ lemma [induct_simp]: "(\x. induct_equal x t \ PROP P x) \ PROP P t" unfolding induct_equal_def proof assume r: "\x. x = t \ PROP P x" show "PROP P t" by (rule r [OF refl]) next fix x assume "PROP P t" "x = t" then show "PROP P x" by simp qed lemma [induct_simp]: "(\x. induct_equal t x \ PROP P x) \ PROP P t" unfolding induct_equal_def proof assume r: "\x. t = x \ PROP P x" show "PROP P t" by (rule r [OF refl]) next fix x assume "PROP P t" "t = x" then show "PROP P x" by simp qed lemma [induct_simp]: "(induct_false \ P) \ Trueprop induct_true" unfolding induct_false_def induct_true_def by (iprover intro: equal_intr_rule) lemma [induct_simp]: "(induct_true \ PROP P) \ PROP P" unfolding induct_true_def proof assume "True \ PROP P" then show "PROP P" using TrueI . next assume "PROP P" then show "PROP P" . qed lemma [induct_simp]: "(PROP P \ induct_true) \ Trueprop induct_true" unfolding induct_true_def by (iprover intro: equal_intr_rule) lemma [induct_simp]: "(\x::'a::{}. induct_true) \ Trueprop induct_true" unfolding induct_true_def by (iprover intro: equal_intr_rule) lemma [induct_simp]: "induct_implies induct_true P \ P" by (simp add: induct_implies_def induct_true_def) lemma [induct_simp]: "x = x \ True" by (rule simp_thms) end ML_file \~~/src/Tools/induct_tacs.ML\ subsubsection \Coherent logic\ ML_file \~~/src/Tools/coherent.ML\ ML \ structure Coherent = Coherent ( val atomize_elimL = @{thm atomize_elimL}; val atomize_exL = @{thm atomize_exL}; val atomize_conjL = @{thm atomize_conjL}; val atomize_disjL = @{thm atomize_disjL}; val operator_names = [\<^const_name>\HOL.disj\, \<^const_name>\HOL.conj\, \<^const_name>\Ex\]; ); \ subsubsection \Reorienting equalities\ ML \ signature REORIENT_PROC = sig val add : (term -> bool) -> theory -> theory val proc : morphism -> Proof.context -> cterm -> thm option end; structure Reorient_Proc : REORIENT_PROC = struct structure Data = Theory_Data ( type T = ((term -> bool) * stamp) list; val empty = []; val extend = I; fun merge data : T = Library.merge (eq_snd (op =)) data; ); fun add m = Data.map (cons (m, stamp ())); fun matches thy t = exists (fn (m, _) => m t) (Data.get thy); val meta_reorient = @{thm eq_commute [THEN eq_reflection]}; fun proc phi ctxt ct = let val thy = Proof_Context.theory_of ctxt; in case Thm.term_of ct of (_ $ t $ u) => if matches thy u then NONE else SOME meta_reorient | _ => NONE end; end; \ subsection \Other simple lemmas and lemma duplicates\ lemma all_cong1: "(\x. P x = P' x) \ (\x. P x) = (\x. P' x)" by auto lemma ex_cong1: "(\x. P x = P' x) \ (\x. P x) = (\x. P' x)" by auto lemma all_cong: "(\x. Q x \ P x = P' x) \ (\x. Q x \ P x) = (\x. Q x \ P' x)" by auto lemma ex_cong: "(\x. Q x \ P x = P' x) \ (\x. Q x \ P x) = (\x. Q x \ P' x)" by auto lemma ex1_eq [iff]: "\!x. x = t" "\!x. t = x" by blast+ lemma choice_eq: "(\x. \!y. P x y) = (\!f. \x. P x (f x))" (is "?lhs = ?rhs") proof (intro iffI allI) assume L: ?lhs then have \
: "\x. P x (THE y. P x y)" by (best intro: theI') show ?rhs by (rule ex1I) (use L \
in \fast+\) next fix x assume R: ?rhs then obtain f where f: "\x. P x (f x)" and f1: "\y. (\x. P x (y x)) \ y = f" by (blast elim: ex1E) show "\!y. P x y" proof (rule ex1I) show "P x (f x)" using f by blast show "y = f x" if "P x y" for y proof - have "P z (if z = x then y else f z)" for z using f that by (auto split: if_split) with f1 [of "\z. if z = x then y else f z"] f show ?thesis by (auto simp add: split: if_split_asm dest: fun_cong) qed qed qed lemmas eq_sym_conv = eq_commute lemma nnf_simps: "(\ (P \ Q)) = (\ P \ \ Q)" "(\ (P \ Q)) = (\ P \ \ Q)" "(P \ Q) = (\ P \ Q)" "(P = Q) = ((P \ Q) \ (\ P \ \ Q))" "(\ (P = Q)) = ((P \ \ Q) \ (\ P \ Q))" "(\ \ P) = P" by blast+ subsection \Basic ML bindings\ ML \ val FalseE = @{thm FalseE} val Let_def = @{thm Let_def} val TrueI = @{thm TrueI} val allE = @{thm allE} val allI = @{thm allI} val all_dupE = @{thm all_dupE} val arg_cong = @{thm arg_cong} val box_equals = @{thm box_equals} val ccontr = @{thm ccontr} val classical = @{thm classical} val conjE = @{thm conjE} val conjI = @{thm conjI} val conjunct1 = @{thm conjunct1} val conjunct2 = @{thm conjunct2} val disjCI = @{thm disjCI} val disjE = @{thm disjE} val disjI1 = @{thm disjI1} val disjI2 = @{thm disjI2} val eq_reflection = @{thm eq_reflection} val ex1E = @{thm ex1E} val ex1I = @{thm ex1I} val ex1_implies_ex = @{thm ex1_implies_ex} val exE = @{thm exE} val exI = @{thm exI} val excluded_middle = @{thm excluded_middle} val ext = @{thm ext} val fun_cong = @{thm fun_cong} val iffD1 = @{thm iffD1} val iffD2 = @{thm iffD2} val iffI = @{thm iffI} val impE = @{thm impE} val impI = @{thm impI} val meta_eq_to_obj_eq = @{thm meta_eq_to_obj_eq} val mp = @{thm mp} val notE = @{thm notE} val notI = @{thm notI} val not_all = @{thm not_all} val not_ex = @{thm not_ex} val not_iff = @{thm not_iff} val not_not = @{thm not_not} val not_sym = @{thm not_sym} val refl = @{thm refl} val rev_mp = @{thm rev_mp} val spec = @{thm spec} val ssubst = @{thm ssubst} val subst = @{thm subst} val sym = @{thm sym} val trans = @{thm trans} \ locale cnf begin lemma clause2raw_notE: "\P; \P\ \ False" by auto lemma clause2raw_not_disj: "\\ P; \ Q\ \ \ (P \ Q)" by auto lemma clause2raw_not_not: "P \ \\ P" by auto lemma iff_refl: "(P::bool) = P" by auto lemma iff_trans: "[| (P::bool) = Q; Q = R |] ==> P = R" by auto lemma conj_cong: "[| P = P'; Q = Q' |] ==> (P \ Q) = (P' \ Q')" by auto lemma disj_cong: "[| P = P'; Q = Q' |] ==> (P \ Q) = (P' \ Q')" by auto lemma make_nnf_imp: "[| (\P) = P'; Q = Q' |] ==> (P \ Q) = (P' \ Q')" by auto lemma make_nnf_iff: "[| P = P'; (\P) = NP; Q = Q'; (\Q) = NQ |] ==> (P = Q) = ((P' \ NQ) \ (NP \ Q'))" by auto lemma make_nnf_not_false: "(\False) = True" by auto lemma make_nnf_not_true: "(\True) = False" by auto lemma make_nnf_not_conj: "[| (\P) = P'; (\Q) = Q' |] ==> (\(P \ Q)) = (P' \ Q')" by auto lemma make_nnf_not_disj: "[| (\P) = P'; (\Q) = Q' |] ==> (\(P \ Q)) = (P' \ Q')" by auto lemma make_nnf_not_imp: "[| P = P'; (\Q) = Q' |] ==> (\(P \ Q)) = (P' \ Q')" by auto lemma make_nnf_not_iff: "[| P = P'; (\P) = NP; Q = Q'; (\Q) = NQ |] ==> (\(P = Q)) = ((P' \ Q') \ (NP \ NQ))" by auto lemma make_nnf_not_not: "P = P' ==> (\\P) = P'" by auto lemma simp_TF_conj_True_l: "[| P = True; Q = Q' |] ==> (P \ Q) = Q'" by auto lemma simp_TF_conj_True_r: "[| P = P'; Q = True |] ==> (P \ Q) = P'" by auto lemma simp_TF_conj_False_l: "P = False ==> (P \ Q) = False" by auto lemma simp_TF_conj_False_r: "Q = False ==> (P \ Q) = False" by auto lemma simp_TF_disj_True_l: "P = True ==> (P \ Q) = True" by auto lemma simp_TF_disj_True_r: "Q = True ==> (P \ Q) = True" by auto lemma simp_TF_disj_False_l: "[| P = False; Q = Q' |] ==> (P \ Q) = Q'" by auto lemma simp_TF_disj_False_r: "[| P = P'; Q = False |] ==> (P \ Q) = P'" by auto lemma make_cnf_disj_conj_l: "[| (P \ R) = PR; (Q \ R) = QR |] ==> ((P \ Q) \ R) = (PR \ QR)" by auto lemma make_cnf_disj_conj_r: "[| (P \ Q) = PQ; (P \ R) = PR |] ==> (P \ (Q \ R)) = (PQ \ PR)" by auto lemma make_cnfx_disj_ex_l: "((\(x::bool). P x) \ Q) = (\x. P x \ Q)" by auto lemma make_cnfx_disj_ex_r: "(P \ (\(x::bool). Q x)) = (\x. P \ Q x)" by auto lemma make_cnfx_newlit: "(P \ Q) = (\x. (P \ x) \ (Q \ \x))" by auto lemma make_cnfx_ex_cong: "(\(x::bool). P x = Q x) \ (\x. P x) = (\x. Q x)" by auto lemma weakening_thm: "[| P; Q |] ==> Q" by auto lemma cnftac_eq_imp: "[| P = Q; P |] ==> Q" by auto end ML_file \Tools/cnf.ML\ section \\NO_MATCH\ simproc\ text \ The simplification procedure can be used to avoid simplification of terms of a certain form. \ definition NO_MATCH :: "'a \ 'b \ bool" where "NO_MATCH pat val \ True" lemma NO_MATCH_cong[cong]: "NO_MATCH pat val = NO_MATCH pat val" by (rule refl) declare [[coercion_args NO_MATCH - -]] simproc_setup NO_MATCH ("NO_MATCH pat val") = \fn _ => fn ctxt => fn ct => let val thy = Proof_Context.theory_of ctxt val dest_binop = Term.dest_comb #> apfst (Term.dest_comb #> snd) val m = Pattern.matches thy (dest_binop (Thm.term_of ct)) in if m then NONE else SOME @{thm NO_MATCH_def} end \ text \ This setup ensures that a rewrite rule of the form \<^term>\NO_MATCH pat val \ t\ is only applied, if the pattern \pat\ does not match the value \val\. \ text\ Tagging a premise of a simp rule with ASSUMPTION forces the simplifier not to simplify the argument and to solve it by an assumption. \ definition ASSUMPTION :: "bool \ bool" where "ASSUMPTION A \ A" lemma ASSUMPTION_cong[cong]: "ASSUMPTION A = ASSUMPTION A" by (rule refl) lemma ASSUMPTION_I: "A \ ASSUMPTION A" by (simp add: ASSUMPTION_def) lemma ASSUMPTION_D: "ASSUMPTION A \ A" by (simp add: ASSUMPTION_def) setup \ let val asm_sol = mk_solver "ASSUMPTION" (fn ctxt => resolve_tac ctxt [@{thm ASSUMPTION_I}] THEN' resolve_tac ctxt (Simplifier.prems_of ctxt)) in map_theory_simpset (fn ctxt => Simplifier.addSolver (ctxt,asm_sol)) end \ subsection \Code generator setup\ subsubsection \Generic code generator preprocessor setup\ lemma conj_left_cong: "P \ Q \ P \ R \ Q \ R" by (fact arg_cong) lemma disj_left_cong: "P \ Q \ P \ R \ Q \ R" by (fact arg_cong) setup \ Code_Preproc.map_pre (put_simpset HOL_basic_ss) #> Code_Preproc.map_post (put_simpset HOL_basic_ss) #> Code_Simp.map_ss (put_simpset HOL_basic_ss #> Simplifier.add_cong @{thm conj_left_cong} #> Simplifier.add_cong @{thm disj_left_cong}) \ subsubsection \Equality\ class equal = fixes equal :: "'a \ 'a \ bool" assumes equal_eq: "equal x y \ x = y" begin lemma equal: "equal = (=)" by (rule ext equal_eq)+ lemma equal_refl: "equal x x \ True" unfolding equal by rule+ lemma eq_equal: "(=) \ equal" by (rule eq_reflection) (rule ext, rule ext, rule sym, rule equal_eq) end declare eq_equal [symmetric, code_post] declare eq_equal [code] setup \ Code_Preproc.map_pre (fn ctxt => ctxt addsimprocs [Simplifier.make_simproc \<^context> "equal" {lhss = [\<^term>\HOL.eq\], proc = fn _ => fn _ => fn ct => (case Thm.term_of ct of Const (_, Type (\<^type_name>\fun\, [Type _, _])) => SOME @{thm eq_equal} | _ => NONE)}]) \ subsubsection \Generic code generator foundation\ text \Datatype \<^typ>\bool\\ code_datatype True False lemma [code]: shows "False \ P \ False" and "True \ P \ P" and "P \ False \ False" and "P \ True \ P" by simp_all lemma [code]: shows "False \ P \ P" and "True \ P \ True" and "P \ False \ P" and "P \ True \ True" by simp_all lemma [code]: shows "(False \ P) \ True" and "(True \ P) \ P" and "(P \ False) \ \ P" and "(P \ True) \ True" by simp_all text \More about \<^typ>\prop\\ lemma [code nbe]: shows "(True \ PROP Q) \ PROP Q" and "(PROP Q \ True) \ Trueprop True" and "(P \ R) \ Trueprop (P \ R)" by (auto intro!: equal_intr_rule) lemma Trueprop_code [code]: "Trueprop True \ Code_Generator.holds" by (auto intro!: equal_intr_rule holds) declare Trueprop_code [symmetric, code_post] text \Equality\ declare simp_thms(6) [code nbe] instantiation itself :: (type) equal begin definition equal_itself :: "'a itself \ 'a itself \ bool" where "equal_itself x y \ x = y" instance by standard (fact equal_itself_def) end lemma equal_itself_code [code]: "equal TYPE('a) TYPE('a) \ True" by (simp add: equal) setup \Sign.add_const_constraint (\<^const_name>\equal\, SOME \<^typ>\'a::type \ 'a \ bool\)\ lemma equal_alias_cert: "OFCLASS('a, equal_class) \ (((=) :: 'a \ 'a \ bool) \ equal)" (is "?ofclass \ ?equal") proof assume "PROP ?ofclass" show "PROP ?equal" by (tactic \ALLGOALS (resolve_tac \<^context> [Thm.unconstrainT @{thm eq_equal}])\) (fact \PROP ?ofclass\) next assume "PROP ?equal" show "PROP ?ofclass" proof qed (simp add: \PROP ?equal\) qed setup \Sign.add_const_constraint (\<^const_name>\equal\, SOME \<^typ>\'a::equal \ 'a \ bool\)\ setup \Nbe.add_const_alias @{thm equal_alias_cert}\ text \Cases\ lemma Let_case_cert: assumes "CASE \ (\x. Let x f)" shows "CASE x \ f x" using assms by simp_all setup \ Code.declare_case_global @{thm Let_case_cert} #> Code.declare_undefined_global \<^const_name>\undefined\ \ declare [[code abort: undefined]] subsubsection \Generic code generator target languages\ text \type \<^typ>\bool\\ code_printing type_constructor bool \ (SML) "bool" and (OCaml) "bool" and (Haskell) "Bool" and (Scala) "Boolean" | constant True \ (SML) "true" and (OCaml) "true" and (Haskell) "True" and (Scala) "true" | constant False \ (SML) "false" and (OCaml) "false" and (Haskell) "False" and (Scala) "false" code_reserved SML bool true false code_reserved OCaml bool code_reserved Scala Boolean code_printing constant Not \ (SML) "not" and (OCaml) "not" and (Haskell) "not" and (Scala) "'! _" | constant HOL.conj \ (SML) infixl 1 "andalso" and (OCaml) infixl 3 "&&" and (Haskell) infixr 3 "&&" and (Scala) infixl 3 "&&" | constant HOL.disj \ (SML) infixl 0 "orelse" and (OCaml) infixl 2 "||" and (Haskell) infixl 2 "||" and (Scala) infixl 1 "||" | constant HOL.implies \ (SML) "!(if (_)/ then (_)/ else true)" and (OCaml) "!(if (_)/ then (_)/ else true)" and (Haskell) "!(if (_)/ then (_)/ else True)" and (Scala) "!(if ((_))/ (_)/ else true)" | constant If \ (SML) "!(if (_)/ then (_)/ else (_))" and (OCaml) "!(if (_)/ then (_)/ else (_))" and (Haskell) "!(if (_)/ then (_)/ else (_))" and (Scala) "!(if ((_))/ (_)/ else (_))" code_reserved SML not code_reserved OCaml not code_identifier code_module Pure \ (SML) HOL and (OCaml) HOL and (Haskell) HOL and (Scala) HOL text \Using built-in Haskell equality.\ code_printing type_class equal \ (Haskell) "Eq" | constant HOL.equal \ (Haskell) infix 4 "==" | constant HOL.eq \ (Haskell) infix 4 "==" text \\undefined\\ code_printing constant undefined \ (SML) "!(raise/ Fail/ \"undefined\")" and (OCaml) "failwith/ \"undefined\"" and (Haskell) "error/ \"undefined\"" and (Scala) "!sys.error(\"undefined\")" subsubsection \Evaluation and normalization by evaluation\ method_setup eval = \ let fun eval_tac ctxt = let val conv = Code_Runtime.dynamic_holds_conv ctxt in CONVERSION (Conv.params_conv ~1 (K (Conv.concl_conv ~1 conv)) ctxt) THEN' resolve_tac ctxt [TrueI] end in Scan.succeed (SIMPLE_METHOD' o eval_tac) end \ "solve goal by evaluation" method_setup normalization = \ Scan.succeed (fn ctxt => SIMPLE_METHOD' (CHANGED_PROP o (CONVERSION (Nbe.dynamic_conv ctxt) THEN_ALL_NEW (TRY o resolve_tac ctxt [TrueI])))) \ "solve goal by normalization" subsection \Counterexample Search Units\ subsubsection \Quickcheck\ quickcheck_params [size = 5, iterations = 50] subsubsection \Nitpick setup\ named_theorems nitpick_unfold "alternative definitions of constants as needed by Nitpick" and nitpick_simp "equational specification of constants as needed by Nitpick" and nitpick_psimp "partial equational specification of constants as needed by Nitpick" and nitpick_choice_spec "choice specification of constants as needed by Nitpick" declare if_bool_eq_conj [nitpick_unfold, no_atp] and if_bool_eq_disj [no_atp] subsection \Preprocessing for the predicate compiler\ named_theorems code_pred_def "alternative definitions of constants for the Predicate Compiler" and code_pred_inline "inlining definitions for the Predicate Compiler" and code_pred_simp "simplification rules for the optimisations in the Predicate Compiler" subsection \Legacy tactics and ML bindings\ ML \ (* combination of (spec RS spec RS ...(j times) ... spec RS mp) *) local fun wrong_prem (Const (\<^const_name>\All\, _) $ Abs (_, _, t)) = wrong_prem t | wrong_prem (Bound _) = true | wrong_prem _ = false; val filter_right = filter (not o wrong_prem o HOLogic.dest_Trueprop o hd o Thm.prems_of); fun smp i = funpow i (fn m => filter_right ([spec] RL m)) [mp]; in fun smp_tac ctxt j = EVERY' [dresolve_tac ctxt (smp j), assume_tac ctxt]; end; local val nnf_ss = simpset_of (put_simpset HOL_basic_ss \<^context> addsimps @{thms simp_thms nnf_simps}); in fun nnf_conv ctxt = Simplifier.rewrite (put_simpset nnf_ss ctxt); end \ hide_const (open) eq equal end diff --git a/src/HOL/Library/Quantified_Premise_Simproc.thy b/src/HOL/Library/Quantified_Premise_Simproc.thy --- a/src/HOL/Library/Quantified_Premise_Simproc.thy +++ b/src/HOL/Library/Quantified_Premise_Simproc.thy @@ -1,9 +1,9 @@ (* Author: Florian Haftmann, TU München *) theory Quantified_Premise_Simproc imports Main begin -simproc_setup defined_forall ("\x. PROP P x") = \K Quantifier1.rearrange_All\ +simproc_setup defined_all ("\x. PROP P x") = \K Quantifier1.rearrange_all\ end diff --git a/src/HOL/Set.thy b/src/HOL/Set.thy --- a/src/HOL/Set.thy +++ b/src/HOL/Set.thy @@ -1,2032 +1,2028 @@ (* Title: HOL/Set.thy Author: Tobias Nipkow Author: Lawrence C Paulson Author: Markus Wenzel *) section \Set theory for higher-order logic\ theory Set imports Lattices begin subsection \Sets as predicates\ typedecl 'a set axiomatization Collect :: "('a \ bool) \ 'a set" \ \comprehension\ and member :: "'a \ 'a set \ bool" \ \membership\ where mem_Collect_eq [iff, code_unfold]: "member a (Collect P) = P a" and Collect_mem_eq [simp]: "Collect (\x. member x A) = A" notation member ("'(\')") and member ("(_/ \ _)" [51, 51] 50) abbreviation not_member where "not_member x A \ \ (x \ A)" \ \non-membership\ notation not_member ("'(\')") and not_member ("(_/ \ _)" [51, 51] 50) notation (ASCII) member ("'(:')") and member ("(_/ : _)" [51, 51] 50) and not_member ("'(~:')") and not_member ("(_/ ~: _)" [51, 51] 50) text \Set comprehensions\ syntax "_Coll" :: "pttrn \ bool \ 'a set" ("(1{_./ _})") translations "{x. P}" \ "CONST Collect (\x. P)" syntax (ASCII) "_Collect" :: "pttrn \ 'a set \ bool \ 'a set" ("(1{(_/: _)./ _})") syntax "_Collect" :: "pttrn \ 'a set \ bool \ 'a set" ("(1{(_/ \ _)./ _})") translations "{p:A. P}" \ "CONST Collect (\p. p \ A \ P)" lemma CollectI: "P a \ a \ {x. P x}" by simp lemma CollectD: "a \ {x. P x} \ P a" by simp lemma Collect_cong: "(\x. P x = Q x) \ {x. P x} = {x. Q x}" by simp text \ Simproc for pulling \x = t\ in \{x. \ \ x = t \ \}\ to the front (and similarly for \t = x\): \ simproc_setup defined_Collect ("{x. P x \ Q x}") = \ fn _ => Quantifier1.rearrange_Collect (fn ctxt => resolve_tac ctxt @{thms Collect_cong} 1 THEN resolve_tac ctxt @{thms iffI} 1 THEN ALLGOALS (EVERY' [REPEAT_DETERM o eresolve_tac ctxt @{thms conjE}, DEPTH_SOLVE_1 o (assume_tac ctxt ORELSE' resolve_tac ctxt @{thms conjI})])) \ lemmas CollectE = CollectD [elim_format] lemma set_eqI: assumes "\x. x \ A \ x \ B" shows "A = B" proof - from assms have "{x. x \ A} = {x. x \ B}" by simp then show ?thesis by simp qed lemma set_eq_iff: "A = B \ (\x. x \ A \ x \ B)" by (auto intro:set_eqI) lemma Collect_eqI: assumes "\x. P x = Q x" shows "Collect P = Collect Q" using assms by (auto intro: set_eqI) text \Lifting of predicate class instances\ instantiation set :: (type) boolean_algebra begin definition less_eq_set where "A \ B \ (\x. member x A) \ (\x. member x B)" definition less_set where "A < B \ (\x. member x A) < (\x. member x B)" definition inf_set where "A \ B = Collect ((\x. member x A) \ (\x. member x B))" definition sup_set where "A \ B = Collect ((\x. member x A) \ (\x. member x B))" definition bot_set where "\ = Collect \" definition top_set where "\ = Collect \" definition uminus_set where "- A = Collect (- (\x. member x A))" definition minus_set where "A - B = Collect ((\x. member x A) - (\x. member x B))" instance by standard (simp_all add: less_eq_set_def less_set_def inf_set_def sup_set_def bot_set_def top_set_def uminus_set_def minus_set_def less_le_not_le sup_inf_distrib1 diff_eq set_eqI fun_eq_iff del: inf_apply sup_apply bot_apply top_apply minus_apply uminus_apply) end text \Set enumerations\ abbreviation empty :: "'a set" ("{}") where "{} \ bot" definition insert :: "'a \ 'a set \ 'a set" where insert_compr: "insert a B = {x. x = a \ x \ B}" syntax "_Finset" :: "args \ 'a set" ("{(_)}") translations "{x, xs}" \ "CONST insert x {xs}" "{x}" \ "CONST insert x {}" subsection \Subsets and bounded quantifiers\ abbreviation subset :: "'a set \ 'a set \ bool" where "subset \ less" abbreviation subset_eq :: "'a set \ 'a set \ bool" where "subset_eq \ less_eq" notation subset ("'(\')") and subset ("(_/ \ _)" [51, 51] 50) and subset_eq ("'(\')") and subset_eq ("(_/ \ _)" [51, 51] 50) abbreviation (input) supset :: "'a set \ 'a set \ bool" where "supset \ greater" abbreviation (input) supset_eq :: "'a set \ 'a set \ bool" where "supset_eq \ greater_eq" notation supset ("'(\')") and supset ("(_/ \ _)" [51, 51] 50) and supset_eq ("'(\')") and supset_eq ("(_/ \ _)" [51, 51] 50) notation (ASCII output) subset ("'(<')") and subset ("(_/ < _)" [51, 51] 50) and subset_eq ("'(<=')") and subset_eq ("(_/ <= _)" [51, 51] 50) definition Ball :: "'a set \ ('a \ bool) \ bool" where "Ball A P \ (\x. x \ A \ P x)" \ \bounded universal quantifiers\ definition Bex :: "'a set \ ('a \ bool) \ bool" where "Bex A P \ (\x. x \ A \ P x)" \ \bounded existential quantifiers\ syntax (ASCII) "_Ball" :: "pttrn \ 'a set \ bool \ bool" ("(3ALL (_/:_)./ _)" [0, 0, 10] 10) "_Bex" :: "pttrn \ 'a set \ bool \ bool" ("(3EX (_/:_)./ _)" [0, 0, 10] 10) "_Bex1" :: "pttrn \ 'a set \ bool \ bool" ("(3EX! (_/:_)./ _)" [0, 0, 10] 10) "_Bleast" :: "id \ 'a set \ bool \ 'a" ("(3LEAST (_/:_)./ _)" [0, 0, 10] 10) syntax (input) "_Ball" :: "pttrn \ 'a set \ bool \ bool" ("(3! (_/:_)./ _)" [0, 0, 10] 10) "_Bex" :: "pttrn \ 'a set \ bool \ bool" ("(3? (_/:_)./ _)" [0, 0, 10] 10) "_Bex1" :: "pttrn \ 'a set \ bool \ bool" ("(3?! (_/:_)./ _)" [0, 0, 10] 10) syntax "_Ball" :: "pttrn \ 'a set \ bool \ bool" ("(3\(_/\_)./ _)" [0, 0, 10] 10) "_Bex" :: "pttrn \ 'a set \ bool \ bool" ("(3\(_/\_)./ _)" [0, 0, 10] 10) "_Bex1" :: "pttrn \ 'a set \ bool \ bool" ("(3\!(_/\_)./ _)" [0, 0, 10] 10) "_Bleast" :: "id \ 'a set \ bool \ 'a" ("(3LEAST(_/\_)./ _)" [0, 0, 10] 10) translations "\x\A. P" \ "CONST Ball A (\x. P)" "\x\A. P" \ "CONST Bex A (\x. P)" "\!x\A. P" \ "\!x. x \ A \ P" "LEAST x:A. P" \ "LEAST x. x \ A \ P" syntax (ASCII output) "_setlessAll" :: "[idt, 'a, bool] \ bool" ("(3ALL _<_./ _)" [0, 0, 10] 10) "_setlessEx" :: "[idt, 'a, bool] \ bool" ("(3EX _<_./ _)" [0, 0, 10] 10) "_setleAll" :: "[idt, 'a, bool] \ bool" ("(3ALL _<=_./ _)" [0, 0, 10] 10) "_setleEx" :: "[idt, 'a, bool] \ bool" ("(3EX _<=_./ _)" [0, 0, 10] 10) "_setleEx1" :: "[idt, 'a, bool] \ bool" ("(3EX! _<=_./ _)" [0, 0, 10] 10) syntax "_setlessAll" :: "[idt, 'a, bool] \ bool" ("(3\_\_./ _)" [0, 0, 10] 10) "_setlessEx" :: "[idt, 'a, bool] \ bool" ("(3\_\_./ _)" [0, 0, 10] 10) "_setleAll" :: "[idt, 'a, bool] \ bool" ("(3\_\_./ _)" [0, 0, 10] 10) "_setleEx" :: "[idt, 'a, bool] \ bool" ("(3\_\_./ _)" [0, 0, 10] 10) "_setleEx1" :: "[idt, 'a, bool] \ bool" ("(3\!_\_./ _)" [0, 0, 10] 10) translations "\A\B. P" \ "\A. A \ B \ P" "\A\B. P" \ "\A. A \ B \ P" "\A\B. P" \ "\A. A \ B \ P" "\A\B. P" \ "\A. A \ B \ P" "\!A\B. P" \ "\!A. A \ B \ P" print_translation \ let val All_binder = Mixfix.binder_name \<^const_syntax>\All\; val Ex_binder = Mixfix.binder_name \<^const_syntax>\Ex\; val impl = \<^const_syntax>\HOL.implies\; val conj = \<^const_syntax>\HOL.conj\; val sbset = \<^const_syntax>\subset\; val sbset_eq = \<^const_syntax>\subset_eq\; val trans = [((All_binder, impl, sbset), \<^syntax_const>\_setlessAll\), ((All_binder, impl, sbset_eq), \<^syntax_const>\_setleAll\), ((Ex_binder, conj, sbset), \<^syntax_const>\_setlessEx\), ((Ex_binder, conj, sbset_eq), \<^syntax_const>\_setleEx\)]; fun mk v (v', T) c n P = if v = v' andalso not (Term.exists_subterm (fn Free (x, _) => x = v | _ => false) n) then Syntax.const c $ Syntax_Trans.mark_bound_body (v', T) $ n $ P else raise Match; fun tr' q = (q, fn _ => (fn [Const (\<^syntax_const>\_bound\, _) $ Free (v, Type (\<^type_name>\set\, _)), Const (c, _) $ (Const (d, _) $ (Const (\<^syntax_const>\_bound\, _) $ Free (v', T)) $ n) $ P] => (case AList.lookup (=) trans (q, c, d) of NONE => raise Match | SOME l => mk v (v', T) l n P) | _ => raise Match)); in [tr' All_binder, tr' Ex_binder] end \ text \ \<^medskip> Translate between \{e | x1\xn. P}\ and \{u. \x1\xn. u = e \ P}\; \{y. \x1\xn. y = e \ P}\ is only translated if \[0..n] \ bvs e\. \ syntax "_Setcompr" :: "'a \ idts \ bool \ 'a set" ("(1{_ |/_./ _})") parse_translation \ let val ex_tr = snd (Syntax_Trans.mk_binder_tr ("EX ", \<^const_syntax>\Ex\)); fun nvars (Const (\<^syntax_const>\_idts\, _) $ _ $ idts) = nvars idts + 1 | nvars _ = 1; fun setcompr_tr ctxt [e, idts, b] = let val eq = Syntax.const \<^const_syntax>\HOL.eq\ $ Bound (nvars idts) $ e; val P = Syntax.const \<^const_syntax>\HOL.conj\ $ eq $ b; val exP = ex_tr ctxt [idts, P]; in Syntax.const \<^const_syntax>\Collect\ $ absdummy dummyT exP end; in [(\<^syntax_const>\_Setcompr\, setcompr_tr)] end \ print_translation \ [Syntax_Trans.preserve_binder_abs2_tr' \<^const_syntax>\Ball\ \<^syntax_const>\_Ball\, Syntax_Trans.preserve_binder_abs2_tr' \<^const_syntax>\Bex\ \<^syntax_const>\_Bex\] \ \ \to avoid eta-contraction of body\ print_translation \ let val ex_tr' = snd (Syntax_Trans.mk_binder_tr' (\<^const_syntax>\Ex\, "DUMMY")); fun setcompr_tr' ctxt [Abs (abs as (_, _, P))] = let fun check (Const (\<^const_syntax>\Ex\, _) $ Abs (_, _, P), n) = check (P, n + 1) | check (Const (\<^const_syntax>\HOL.conj\, _) $ (Const (\<^const_syntax>\HOL.eq\, _) $ Bound m $ e) $ P, n) = n > 0 andalso m = n andalso not (loose_bvar1 (P, n)) andalso subset (=) (0 upto (n - 1), add_loose_bnos (e, 0, [])) | check _ = false; fun tr' (_ $ abs) = let val _ $ idts $ (_ $ (_ $ _ $ e) $ Q) = ex_tr' ctxt [abs] in Syntax.const \<^syntax_const>\_Setcompr\ $ e $ idts $ Q end; in if check (P, 0) then tr' P else let val (x as _ $ Free(xN, _), t) = Syntax_Trans.atomic_abs_tr' abs; val M = Syntax.const \<^syntax_const>\_Coll\ $ x $ t; in case t of Const (\<^const_syntax>\HOL.conj\, _) $ (Const (\<^const_syntax>\Set.member\, _) $ (Const (\<^syntax_const>\_bound\, _) $ Free (yN, _)) $ A) $ P => if xN = yN then Syntax.const \<^syntax_const>\_Collect\ $ x $ A $ P else M | _ => M end end; in [(\<^const_syntax>\Collect\, setcompr_tr')] end \ simproc_setup defined_Bex ("\x\A. P x \ Q x") = \ - fn _ => Quantifier1.rearrange_bex - (fn ctxt => - unfold_tac ctxt @{thms Bex_def} THEN - Quantifier1.prove_one_point_ex_tac ctxt) + fn _ => Quantifier1.rearrange_Bex + (fn ctxt => unfold_tac ctxt @{thms Bex_def}) \ simproc_setup defined_All ("\x\A. P x \ Q x") = \ - fn _ => Quantifier1.rearrange_ball - (fn ctxt => - unfold_tac ctxt @{thms Ball_def} THEN - Quantifier1.prove_one_point_all_tac ctxt) + fn _ => Quantifier1.rearrange_Ball + (fn ctxt => unfold_tac ctxt @{thms Ball_def}) \ lemma ballI [intro!]: "(\x. x \ A \ P x) \ \x\A. P x" by (simp add: Ball_def) lemmas strip = impI allI ballI lemma bspec [dest?]: "\x\A. P x \ x \ A \ P x" by (simp add: Ball_def) text \Gives better instantiation for bound:\ setup \ map_theory_claset (fn ctxt => ctxt addbefore ("bspec", fn ctxt' => dresolve_tac ctxt' @{thms bspec} THEN' assume_tac ctxt')) \ ML \ structure Simpdata = struct open Simpdata; val mksimps_pairs = [(\<^const_name>\Ball\, @{thms bspec})] @ mksimps_pairs; end; open Simpdata; \ declaration \fn _ => Simplifier.map_ss (Simplifier.set_mksimps (mksimps mksimps_pairs))\ lemma ballE [elim]: "\x\A. P x \ (P x \ Q) \ (x \ A \ Q) \ Q" unfolding Ball_def by blast lemma bexI [intro]: "P x \ x \ A \ \x\A. P x" \ \Normally the best argument order: \P x\ constrains the choice of \x \ A\.\ unfolding Bex_def by blast lemma rev_bexI [intro?]: "x \ A \ P x \ \x\A. P x" \ \The best argument order when there is only one \x \ A\.\ unfolding Bex_def by blast lemma bexCI: "(\x\A. \ P x \ P a) \ a \ A \ \x\A. P x" unfolding Bex_def by blast lemma bexE [elim!]: "\x\A. P x \ (\x. x \ A \ P x \ Q) \ Q" unfolding Bex_def by blast lemma ball_triv [simp]: "(\x\A. P) \ ((\x. x \ A) \ P)" \ \Trival rewrite rule.\ by (simp add: Ball_def) lemma bex_triv [simp]: "(\x\A. P) \ ((\x. x \ A) \ P)" \ \Dual form for existentials.\ by (simp add: Bex_def) lemma bex_triv_one_point1 [simp]: "(\x\A. x = a) \ a \ A" by blast lemma bex_triv_one_point2 [simp]: "(\x\A. a = x) \ a \ A" by blast lemma bex_one_point1 [simp]: "(\x\A. x = a \ P x) \ a \ A \ P a" by blast lemma bex_one_point2 [simp]: "(\x\A. a = x \ P x) \ a \ A \ P a" by blast lemma ball_one_point1 [simp]: "(\x\A. x = a \ P x) \ (a \ A \ P a)" by blast lemma ball_one_point2 [simp]: "(\x\A. a = x \ P x) \ (a \ A \ P a)" by blast lemma ball_conj_distrib: "(\x\A. P x \ Q x) \ (\x\A. P x) \ (\x\A. Q x)" by blast lemma bex_disj_distrib: "(\x\A. P x \ Q x) \ (\x\A. P x) \ (\x\A. Q x)" by blast text \Congruence rules\ lemma ball_cong: "\ A = B; \x. x \ B \ P x \ Q x \ \ (\x\A. P x) \ (\x\B. Q x)" by (simp add: Ball_def) lemma ball_cong_simp [cong]: "\ A = B; \x. x \ B =simp=> P x \ Q x \ \ (\x\A. P x) \ (\x\B. Q x)" by (simp add: simp_implies_def Ball_def) lemma bex_cong: "\ A = B; \x. x \ B \ P x \ Q x \ \ (\x\A. P x) \ (\x\B. Q x)" by (simp add: Bex_def cong: conj_cong) lemma bex_cong_simp [cong]: "\ A = B; \x. x \ B =simp=> P x \ Q x \ \ (\x\A. P x) \ (\x\B. Q x)" by (simp add: simp_implies_def Bex_def cong: conj_cong) lemma bex1_def: "(\!x\X. P x) \ (\x\X. P x) \ (\x\X. \y\X. P x \ P y \ x = y)" by auto subsection \Basic operations\ subsubsection \Subsets\ lemma subsetI [intro!]: "(\x. x \ A \ x \ B) \ A \ B" by (simp add: less_eq_set_def le_fun_def) text \ \<^medskip> Map the type \'a set \ anything\ to just \'a\; for overloading constants whose first argument has type \'a set\. \ lemma subsetD [elim, intro?]: "A \ B \ c \ A \ c \ B" by (simp add: less_eq_set_def le_fun_def) \ \Rule in Modus Ponens style.\ lemma rev_subsetD [intro?,no_atp]: "c \ A \ A \ B \ c \ B" \ \The same, with reversed premises for use with @{method erule} -- cf. @{thm rev_mp}.\ by (rule subsetD) lemma subsetCE [elim,no_atp]: "A \ B \ (c \ A \ P) \ (c \ B \ P) \ P" \ \Classical elimination rule.\ by (auto simp add: less_eq_set_def le_fun_def) lemma subset_eq: "A \ B \ (\x\A. x \ B)" by blast lemma contra_subsetD [no_atp]: "A \ B \ c \ B \ c \ A" by blast lemma subset_refl: "A \ A" by (fact order_refl) (* already [iff] *) lemma subset_trans: "A \ B \ B \ C \ A \ C" by (fact order_trans) lemma subset_not_subset_eq [code]: "A \ B \ A \ B \ \ B \ A" by (fact less_le_not_le) lemma eq_mem_trans: "a = b \ b \ A \ a \ A" by simp lemmas basic_trans_rules [trans] = order_trans_rules rev_subsetD subsetD eq_mem_trans subsubsection \Equality\ lemma subset_antisym [intro!]: "A \ B \ B \ A \ A = B" \ \Anti-symmetry of the subset relation.\ by (iprover intro: set_eqI subsetD) text \\<^medskip> Equality rules from ZF set theory -- are they appropriate here?\ lemma equalityD1: "A = B \ A \ B" by simp lemma equalityD2: "A = B \ B \ A" by simp text \ \<^medskip> Be careful when adding this to the claset as \subset_empty\ is in the simpset: \<^prop>\A = {}\ goes to \<^prop>\{} \ A\ and \<^prop>\A \ {}\ and then back to \<^prop>\A = {}\! \ lemma equalityE: "A = B \ (A \ B \ B \ A \ P) \ P" by simp lemma equalityCE [elim]: "A = B \ (c \ A \ c \ B \ P) \ (c \ A \ c \ B \ P) \ P" by blast lemma eqset_imp_iff: "A = B \ x \ A \ x \ B" by simp lemma eqelem_imp_iff: "x = y \ x \ A \ y \ A" by simp subsubsection \The empty set\ lemma empty_def: "{} = {x. False}" by (simp add: bot_set_def bot_fun_def) lemma empty_iff [simp]: "c \ {} \ False" by (simp add: empty_def) lemma emptyE [elim!]: "a \ {} \ P" by simp lemma empty_subsetI [iff]: "{} \ A" \ \One effect is to delete the ASSUMPTION \<^prop>\{} \ A\\ by blast lemma equals0I: "(\y. y \ A \ False) \ A = {}" by blast lemma equals0D: "A = {} \ a \ A" \ \Use for reasoning about disjointness: \A \ B = {}\\ by blast lemma ball_empty [simp]: "Ball {} P \ True" by (simp add: Ball_def) lemma bex_empty [simp]: "Bex {} P \ False" by (simp add: Bex_def) subsubsection \The universal set -- UNIV\ abbreviation UNIV :: "'a set" where "UNIV \ top" lemma UNIV_def: "UNIV = {x. True}" by (simp add: top_set_def top_fun_def) lemma UNIV_I [simp]: "x \ UNIV" by (simp add: UNIV_def) declare UNIV_I [intro] \ \unsafe makes it less likely to cause problems\ lemma UNIV_witness [intro?]: "\x. x \ UNIV" by simp lemma subset_UNIV: "A \ UNIV" by (fact top_greatest) (* already simp *) text \ \<^medskip> Eta-contracting these two rules (to remove \P\) causes them to be ignored because of their interaction with congruence rules. \ lemma ball_UNIV [simp]: "Ball UNIV P \ All P" by (simp add: Ball_def) lemma bex_UNIV [simp]: "Bex UNIV P \ Ex P" by (simp add: Bex_def) lemma UNIV_eq_I: "(\x. x \ A) \ UNIV = A" by auto lemma UNIV_not_empty [iff]: "UNIV \ {}" by (blast elim: equalityE) lemma empty_not_UNIV[simp]: "{} \ UNIV" by blast subsubsection \The Powerset operator -- Pow\ definition Pow :: "'a set \ 'a set set" where Pow_def: "Pow A = {B. B \ A}" lemma Pow_iff [iff]: "A \ Pow B \ A \ B" by (simp add: Pow_def) lemma PowI: "A \ B \ A \ Pow B" by (simp add: Pow_def) lemma PowD: "A \ Pow B \ A \ B" by (simp add: Pow_def) lemma Pow_bottom: "{} \ Pow B" by simp lemma Pow_top: "A \ Pow A" by simp lemma Pow_not_empty: "Pow A \ {}" using Pow_top by blast subsubsection \Set complement\ lemma Compl_iff [simp]: "c \ - A \ c \ A" by (simp add: fun_Compl_def uminus_set_def) lemma ComplI [intro!]: "(c \ A \ False) \ c \ - A" by (simp add: fun_Compl_def uminus_set_def) blast text \ \<^medskip> This form, with negated conclusion, works well with the Classical prover. Negated assumptions behave like formulae on the right side of the notional turnstile \dots \ lemma ComplD [dest!]: "c \ - A \ c \ A" by simp lemmas ComplE = ComplD [elim_format] lemma Compl_eq: "- A = {x. \ x \ A}" by blast subsubsection \Binary intersection\ abbreviation inter :: "'a set \ 'a set \ 'a set" (infixl "\" 70) where "(\) \ inf" notation (ASCII) inter (infixl "Int" 70) lemma Int_def: "A \ B = {x. x \ A \ x \ B}" by (simp add: inf_set_def inf_fun_def) lemma Int_iff [simp]: "c \ A \ B \ c \ A \ c \ B" unfolding Int_def by blast lemma IntI [intro!]: "c \ A \ c \ B \ c \ A \ B" by simp lemma IntD1: "c \ A \ B \ c \ A" by simp lemma IntD2: "c \ A \ B \ c \ B" by simp lemma IntE [elim!]: "c \ A \ B \ (c \ A \ c \ B \ P) \ P" by simp lemma mono_Int: "mono f \ f (A \ B) \ f A \ f B" by (fact mono_inf) subsubsection \Binary union\ abbreviation union :: "'a set \ 'a set \ 'a set" (infixl "\" 65) where "union \ sup" notation (ASCII) union (infixl "Un" 65) lemma Un_def: "A \ B = {x. x \ A \ x \ B}" by (simp add: sup_set_def sup_fun_def) lemma Un_iff [simp]: "c \ A \ B \ c \ A \ c \ B" unfolding Un_def by blast lemma UnI1 [elim?]: "c \ A \ c \ A \ B" by simp lemma UnI2 [elim?]: "c \ B \ c \ A \ B" by simp text \\<^medskip> Classical introduction rule: no commitment to \A\ vs. \B\.\ lemma UnCI [intro!]: "(c \ B \ c \ A) \ c \ A \ B" by auto lemma UnE [elim!]: "c \ A \ B \ (c \ A \ P) \ (c \ B \ P) \ P" unfolding Un_def by blast lemma insert_def: "insert a B = {x. x = a} \ B" by (simp add: insert_compr Un_def) lemma mono_Un: "mono f \ f A \ f B \ f (A \ B)" by (fact mono_sup) subsubsection \Set difference\ lemma Diff_iff [simp]: "c \ A - B \ c \ A \ c \ B" by (simp add: minus_set_def fun_diff_def) lemma DiffI [intro!]: "c \ A \ c \ B \ c \ A - B" by simp lemma DiffD1: "c \ A - B \ c \ A" by simp lemma DiffD2: "c \ A - B \ c \ B \ P" by simp lemma DiffE [elim!]: "c \ A - B \ (c \ A \ c \ B \ P) \ P" by simp lemma set_diff_eq: "A - B = {x. x \ A \ x \ B}" by blast lemma Compl_eq_Diff_UNIV: "- A = (UNIV - A)" by blast subsubsection \Augmenting a set -- \<^const>\insert\\ lemma insert_iff [simp]: "a \ insert b A \ a = b \ a \ A" unfolding insert_def by blast lemma insertI1: "a \ insert a B" by simp lemma insertI2: "a \ B \ a \ insert b B" by simp lemma insertE [elim!]: "a \ insert b A \ (a = b \ P) \ (a \ A \ P) \ P" unfolding insert_def by blast lemma insertCI [intro!]: "(a \ B \ a = b) \ a \ insert b B" \ \Classical introduction rule.\ by auto lemma subset_insert_iff: "A \ insert x B \ (if x \ A then A - {x} \ B else A \ B)" by auto lemma set_insert: assumes "x \ A" obtains B where "A = insert x B" and "x \ B" proof show "A = insert x (A - {x})" using assms by blast show "x \ A - {x}" by blast qed lemma insert_ident: "x \ A \ x \ B \ insert x A = insert x B \ A = B" by auto lemma insert_eq_iff: assumes "a \ A" "b \ B" shows "insert a A = insert b B \ (if a = b then A = B else \C. A = insert b C \ b \ C \ B = insert a C \ a \ C)" (is "?L \ ?R") proof show ?R if ?L proof (cases "a = b") case True with assms \?L\ show ?R by (simp add: insert_ident) next case False let ?C = "A - {b}" have "A = insert b ?C \ b \ ?C \ B = insert a ?C \ a \ ?C" using assms \?L\ \a \ b\ by auto then show ?R using \a \ b\ by auto qed show ?L if ?R using that by (auto split: if_splits) qed lemma insert_UNIV: "insert x UNIV = UNIV" by auto subsubsection \Singletons, using insert\ lemma singletonI [intro!]: "a \ {a}" \ \Redundant? But unlike \insertCI\, it proves the subgoal immediately!\ by (rule insertI1) lemma singletonD [dest!]: "b \ {a} \ b = a" by blast lemmas singletonE = singletonD [elim_format] lemma singleton_iff: "b \ {a} \ b = a" by blast lemma singleton_inject [dest!]: "{a} = {b} \ a = b" by blast lemma singleton_insert_inj_eq [iff]: "{b} = insert a A \ a = b \ A \ {b}" by blast lemma singleton_insert_inj_eq' [iff]: "insert a A = {b} \ a = b \ A \ {b}" by blast lemma subset_singletonD: "A \ {x} \ A = {} \ A = {x}" by fast lemma subset_singleton_iff: "X \ {a} \ X = {} \ X = {a}" by blast lemma subset_singleton_iff_Uniq: "(\a. A \ {a}) \ (\\<^sub>\\<^sub>1x. x \ A)" unfolding Uniq_def by blast lemma singleton_conv [simp]: "{x. x = a} = {a}" by blast lemma singleton_conv2 [simp]: "{x. a = x} = {a}" by blast lemma Diff_single_insert: "A - {x} \ B \ A \ insert x B" by blast lemma subset_Diff_insert: "A \ B - insert x C \ A \ B - C \ x \ A" by blast lemma doubleton_eq_iff: "{a, b} = {c, d} \ a = c \ b = d \ a = d \ b = c" by (blast elim: equalityE) lemma Un_singleton_iff: "A \ B = {x} \ A = {} \ B = {x} \ A = {x} \ B = {} \ A = {x} \ B = {x}" by auto lemma singleton_Un_iff: "{x} = A \ B \ A = {} \ B = {x} \ A = {x} \ B = {} \ A = {x} \ B = {x}" by auto subsubsection \Image of a set under a function\ text \Frequently \b\ does not have the syntactic form of \f x\.\ definition image :: "('a \ 'b) \ 'a set \ 'b set" (infixr "`" 90) where "f ` A = {y. \x\A. y = f x}" lemma image_eqI [simp, intro]: "b = f x \ x \ A \ b \ f ` A" unfolding image_def by blast lemma imageI: "x \ A \ f x \ f ` A" by (rule image_eqI) (rule refl) lemma rev_image_eqI: "x \ A \ b = f x \ b \ f ` A" \ \This version's more effective when we already have the required \x\.\ by (rule image_eqI) lemma imageE [elim!]: assumes "b \ (\x. f x) ` A" \ \The eta-expansion gives variable-name preservation.\ obtains x where "b = f x" and "x \ A" using assms unfolding image_def by blast lemma Compr_image_eq: "{x \ f ` A. P x} = f ` {x \ A. P (f x)}" by auto lemma image_Un: "f ` (A \ B) = f ` A \ f ` B" by blast lemma image_iff: "z \ f ` A \ (\x\A. z = f x)" by blast lemma image_subsetI: "(\x. x \ A \ f x \ B) \ f ` A \ B" \ \Replaces the three steps \subsetI\, \imageE\, \hypsubst\, but breaks too many existing proofs.\ by blast lemma image_subset_iff: "f ` A \ B \ (\x\A. f x \ B)" \ \This rewrite rule would confuse users if made default.\ by blast lemma subset_imageE: assumes "B \ f ` A" obtains C where "C \ A" and "B = f ` C" proof - from assms have "B = f ` {a \ A. f a \ B}" by fast moreover have "{a \ A. f a \ B} \ A" by blast ultimately show thesis by (blast intro: that) qed lemma subset_image_iff: "B \ f ` A \ (\AA\A. B = f ` AA)" by (blast elim: subset_imageE) lemma image_ident [simp]: "(\x. x) ` Y = Y" by blast lemma image_empty [simp]: "f ` {} = {}" by blast lemma image_insert [simp]: "f ` insert a B = insert (f a) (f ` B)" by blast lemma image_constant: "x \ A \ (\x. c) ` A = {c}" by auto lemma image_constant_conv: "(\x. c) ` A = (if A = {} then {} else {c})" by auto lemma image_image: "f ` (g ` A) = (\x. f (g x)) ` A" by blast lemma insert_image [simp]: "x \ A \ insert (f x) (f ` A) = f ` A" by blast lemma image_is_empty [iff]: "f ` A = {} \ A = {}" by blast lemma empty_is_image [iff]: "{} = f ` A \ A = {}" by blast lemma image_Collect: "f ` {x. P x} = {f x | x. P x}" \ \NOT suitable as a default simp rule: the RHS isn't simpler than the LHS, with its implicit quantifier and conjunction. Also image enjoys better equational properties than does the RHS.\ by blast lemma if_image_distrib [simp]: "(\x. if P x then f x else g x) ` S = f ` (S \ {x. P x}) \ g ` (S \ {x. \ P x})" by auto lemma image_cong: "f ` M = g ` N" if "M = N" "\x. x \ N \ f x = g x" using that by (simp add: image_def) lemma image_cong_simp [cong]: "f ` M = g ` N" if "M = N" "\x. x \ N =simp=> f x = g x" using that image_cong [of M N f g] by (simp add: simp_implies_def) lemma image_Int_subset: "f ` (A \ B) \ f ` A \ f ` B" by blast lemma image_diff_subset: "f ` A - f ` B \ f ` (A - B)" by blast lemma Setcompr_eq_image: "{f x |x. x \ A} = f ` A" by blast lemma setcompr_eq_image: "{f x |x. P x} = f ` {x. P x}" by auto lemma ball_imageD: "\x\f ` A. P x \ \x\A. P (f x)" by simp lemma bex_imageD: "\x\f ` A. P x \ \x\A. P (f x)" by auto lemma image_add_0 [simp]: "(+) (0::'a::comm_monoid_add) ` S = S" by auto text \\<^medskip> Range of a function -- just an abbreviation for image!\ abbreviation range :: "('a \ 'b) \ 'b set" \ \of function\ where "range f \ f ` UNIV" lemma range_eqI: "b = f x \ b \ range f" by simp lemma rangeI: "f x \ range f" by simp lemma rangeE [elim?]: "b \ range (\x. f x) \ (\x. b = f x \ P) \ P" by (rule imageE) lemma full_SetCompr_eq: "{u. \x. u = f x} = range f" by auto lemma range_composition: "range (\x. f (g x)) = f ` range g" by auto lemma range_constant [simp]: "range (\_. x) = {x}" by (simp add: image_constant) lemma range_eq_singletonD: "range f = {a} \ f x = a" by auto subsubsection \Some rules with \if\\ text \Elimination of \{x. \ \ x = t \ \}\.\ lemma Collect_conv_if: "{x. x = a \ P x} = (if P a then {a} else {})" by auto lemma Collect_conv_if2: "{x. a = x \ P x} = (if P a then {a} else {})" by auto text \ Rewrite rules for boolean case-splitting: faster than \if_split [split]\. \ lemma if_split_eq1: "(if Q then x else y) = b \ (Q \ x = b) \ (\ Q \ y = b)" by (rule if_split) lemma if_split_eq2: "a = (if Q then x else y) \ (Q \ a = x) \ (\ Q \ a = y)" by (rule if_split) text \ Split ifs on either side of the membership relation. Not for \[simp]\ -- can cause goals to blow up! \ lemma if_split_mem1: "(if Q then x else y) \ b \ (Q \ x \ b) \ (\ Q \ y \ b)" by (rule if_split) lemma if_split_mem2: "(a \ (if Q then x else y)) \ (Q \ a \ x) \ (\ Q \ a \ y)" by (rule if_split [where P = "\S. a \ S"]) lemmas split_ifs = if_bool_eq_conj if_split_eq1 if_split_eq2 if_split_mem1 if_split_mem2 (*Would like to add these, but the existing code only searches for the outer-level constant, which in this case is just Set.member; we instead need to use term-nets to associate patterns with rules. Also, if a rule fails to apply, then the formula should be kept. [("uminus", Compl_iff RS iffD1), ("minus", [Diff_iff RS iffD1]), ("Int", [IntD1,IntD2]), ("Collect", [CollectD]), ("Inter", [InterD]), ("INTER", [INT_D])] *) subsection \Further operations and lemmas\ subsubsection \The ``proper subset'' relation\ lemma psubsetI [intro!]: "A \ B \ A \ B \ A \ B" unfolding less_le by blast lemma psubsetE [elim!]: "A \ B \ (A \ B \ \ B \ A \ R) \ R" unfolding less_le by blast lemma psubset_insert_iff: "A \ insert x B \ (if x \ B then A \ B else if x \ A then A - {x} \ B else A \ B)" by (auto simp add: less_le subset_insert_iff) lemma psubset_eq: "A \ B \ A \ B \ A \ B" by (simp only: less_le) lemma psubset_imp_subset: "A \ B \ A \ B" by (simp add: psubset_eq) lemma psubset_trans: "A \ B \ B \ C \ A \ C" unfolding less_le by (auto dest: subset_antisym) lemma psubsetD: "A \ B \ c \ A \ c \ B" unfolding less_le by (auto dest: subsetD) lemma psubset_subset_trans: "A \ B \ B \ C \ A \ C" by (auto simp add: psubset_eq) lemma subset_psubset_trans: "A \ B \ B \ C \ A \ C" by (auto simp add: psubset_eq) lemma psubset_imp_ex_mem: "A \ B \ \b. b \ B - A" unfolding less_le by blast lemma atomize_ball: "(\x. x \ A \ P x) \ Trueprop (\x\A. P x)" by (simp only: Ball_def atomize_all atomize_imp) lemmas [symmetric, rulify] = atomize_ball and [symmetric, defn] = atomize_ball lemma image_Pow_mono: "f ` A \ B \ image f ` Pow A \ Pow B" by blast lemma image_Pow_surj: "f ` A = B \ image f ` Pow A = Pow B" by (blast elim: subset_imageE) subsubsection \Derived rules involving subsets.\ text \\insert\.\ lemma subset_insertI: "B \ insert a B" by (rule subsetI) (erule insertI2) lemma subset_insertI2: "A \ B \ A \ insert b B" by blast lemma subset_insert: "x \ A \ A \ insert x B \ A \ B" by blast text \\<^medskip> Finite Union -- the least upper bound of two sets.\ lemma Un_upper1: "A \ A \ B" by (fact sup_ge1) lemma Un_upper2: "B \ A \ B" by (fact sup_ge2) lemma Un_least: "A \ C \ B \ C \ A \ B \ C" by (fact sup_least) text \\<^medskip> Finite Intersection -- the greatest lower bound of two sets.\ lemma Int_lower1: "A \ B \ A" by (fact inf_le1) lemma Int_lower2: "A \ B \ B" by (fact inf_le2) lemma Int_greatest: "C \ A \ C \ B \ C \ A \ B" by (fact inf_greatest) text \\<^medskip> Set difference.\ lemma Diff_subset[simp]: "A - B \ A" by blast lemma Diff_subset_conv: "A - B \ C \ A \ B \ C" by blast subsubsection \Equalities involving union, intersection, inclusion, etc.\ text \\{}\.\ lemma Collect_const [simp]: "{s. P} = (if P then UNIV else {})" \ \supersedes \Collect_False_empty\\ by auto lemma subset_empty [simp]: "A \ {} \ A = {}" by (fact bot_unique) lemma not_psubset_empty [iff]: "\ (A < {})" by (fact not_less_bot) (* FIXME: already simp *) lemma Collect_subset [simp]: "{x\A. P x} \ A" by auto lemma Collect_empty_eq [simp]: "Collect P = {} \ (\x. \ P x)" by blast lemma empty_Collect_eq [simp]: "{} = Collect P \ (\x. \ P x)" by blast lemma Collect_neg_eq: "{x. \ P x} = - {x. P x}" by blast lemma Collect_disj_eq: "{x. P x \ Q x} = {x. P x} \ {x. Q x}" by blast lemma Collect_imp_eq: "{x. P x \ Q x} = - {x. P x} \ {x. Q x}" by blast lemma Collect_conj_eq: "{x. P x \ Q x} = {x. P x} \ {x. Q x}" by blast lemma Collect_mono_iff: "Collect P \ Collect Q \ (\x. P x \ Q x)" by blast text \\<^medskip> \insert\.\ lemma insert_is_Un: "insert a A = {a} \ A" \ \NOT SUITABLE FOR REWRITING since \{a} \ insert a {}\\ by blast lemma insert_not_empty [simp]: "insert a A \ {}" and empty_not_insert [simp]: "{} \ insert a A" by blast+ lemma insert_absorb: "a \ A \ insert a A = A" \ \\[simp]\ causes recursive calls when there are nested inserts\ \ \with \<^emph>\quadratic\ running time\ by blast lemma insert_absorb2 [simp]: "insert x (insert x A) = insert x A" by blast lemma insert_commute: "insert x (insert y A) = insert y (insert x A)" by blast lemma insert_subset [simp]: "insert x A \ B \ x \ B \ A \ B" by blast lemma mk_disjoint_insert: "a \ A \ \B. A = insert a B \ a \ B" \ \use new \B\ rather than \A - {a}\ to avoid infinite unfolding\ by (rule exI [where x = "A - {a}"]) blast lemma insert_Collect: "insert a (Collect P) = {u. u \ a \ P u}" by auto lemma insert_inter_insert [simp]: "insert a A \ insert a B = insert a (A \ B)" by blast lemma insert_disjoint [simp]: "insert a A \ B = {} \ a \ B \ A \ B = {}" "{} = insert a A \ B \ a \ B \ {} = A \ B" by auto lemma disjoint_insert [simp]: "B \ insert a A = {} \ a \ B \ B \ A = {}" "{} = A \ insert b B \ b \ A \ {} = A \ B" by auto text \\<^medskip> \Int\\ lemma Int_absorb: "A \ A = A" by (fact inf_idem) (* already simp *) lemma Int_left_absorb: "A \ (A \ B) = A \ B" by (fact inf_left_idem) lemma Int_commute: "A \ B = B \ A" by (fact inf_commute) lemma Int_left_commute: "A \ (B \ C) = B \ (A \ C)" by (fact inf_left_commute) lemma Int_assoc: "(A \ B) \ C = A \ (B \ C)" by (fact inf_assoc) lemmas Int_ac = Int_assoc Int_left_absorb Int_commute Int_left_commute \ \Intersection is an AC-operator\ lemma Int_absorb1: "B \ A \ A \ B = B" by (fact inf_absorb2) lemma Int_absorb2: "A \ B \ A \ B = A" by (fact inf_absorb1) lemma Int_empty_left: "{} \ B = {}" by (fact inf_bot_left) (* already simp *) lemma Int_empty_right: "A \ {} = {}" by (fact inf_bot_right) (* already simp *) lemma disjoint_eq_subset_Compl: "A \ B = {} \ A \ - B" by blast lemma disjoint_iff: "A \ B = {} \ (\x. x\A \ x \ B)" by blast lemma disjoint_iff_not_equal: "A \ B = {} \ (\x\A. \y\B. x \ y)" by blast lemma Int_UNIV_left: "UNIV \ B = B" by (fact inf_top_left) (* already simp *) lemma Int_UNIV_right: "A \ UNIV = A" by (fact inf_top_right) (* already simp *) lemma Int_Un_distrib: "A \ (B \ C) = (A \ B) \ (A \ C)" by (fact inf_sup_distrib1) lemma Int_Un_distrib2: "(B \ C) \ A = (B \ A) \ (C \ A)" by (fact inf_sup_distrib2) lemma Int_UNIV [simp]: "A \ B = UNIV \ A = UNIV \ B = UNIV" by (fact inf_eq_top_iff) (* already simp *) lemma Int_subset_iff [simp]: "C \ A \ B \ C \ A \ C \ B" by (fact le_inf_iff) lemma Int_Collect: "x \ A \ {x. P x} \ x \ A \ P x" by blast text \\<^medskip> \Un\.\ lemma Un_absorb: "A \ A = A" by (fact sup_idem) (* already simp *) lemma Un_left_absorb: "A \ (A \ B) = A \ B" by (fact sup_left_idem) lemma Un_commute: "A \ B = B \ A" by (fact sup_commute) lemma Un_left_commute: "A \ (B \ C) = B \ (A \ C)" by (fact sup_left_commute) lemma Un_assoc: "(A \ B) \ C = A \ (B \ C)" by (fact sup_assoc) lemmas Un_ac = Un_assoc Un_left_absorb Un_commute Un_left_commute \ \Union is an AC-operator\ lemma Un_absorb1: "A \ B \ A \ B = B" by (fact sup_absorb2) lemma Un_absorb2: "B \ A \ A \ B = A" by (fact sup_absorb1) lemma Un_empty_left: "{} \ B = B" by (fact sup_bot_left) (* already simp *) lemma Un_empty_right: "A \ {} = A" by (fact sup_bot_right) (* already simp *) lemma Un_UNIV_left: "UNIV \ B = UNIV" by (fact sup_top_left) (* already simp *) lemma Un_UNIV_right: "A \ UNIV = UNIV" by (fact sup_top_right) (* already simp *) lemma Un_insert_left [simp]: "(insert a B) \ C = insert a (B \ C)" by blast lemma Un_insert_right [simp]: "A \ (insert a B) = insert a (A \ B)" by blast lemma Int_insert_left: "(insert a B) \ C = (if a \ C then insert a (B \ C) else B \ C)" by auto lemma Int_insert_left_if0 [simp]: "a \ C \ (insert a B) \ C = B \ C" by auto lemma Int_insert_left_if1 [simp]: "a \ C \ (insert a B) \ C = insert a (B \ C)" by auto lemma Int_insert_right: "A \ (insert a B) = (if a \ A then insert a (A \ B) else A \ B)" by auto lemma Int_insert_right_if0 [simp]: "a \ A \ A \ (insert a B) = A \ B" by auto lemma Int_insert_right_if1 [simp]: "a \ A \ A \ (insert a B) = insert a (A \ B)" by auto lemma Un_Int_distrib: "A \ (B \ C) = (A \ B) \ (A \ C)" by (fact sup_inf_distrib1) lemma Un_Int_distrib2: "(B \ C) \ A = (B \ A) \ (C \ A)" by (fact sup_inf_distrib2) lemma Un_Int_crazy: "(A \ B) \ (B \ C) \ (C \ A) = (A \ B) \ (B \ C) \ (C \ A)" by blast lemma subset_Un_eq: "A \ B \ A \ B = B" by (fact le_iff_sup) lemma Un_empty [iff]: "A \ B = {} \ A = {} \ B = {}" by (fact sup_eq_bot_iff) (* FIXME: already simp *) lemma Un_subset_iff [simp]: "A \ B \ C \ A \ C \ B \ C" by (fact le_sup_iff) lemma Un_Diff_Int: "(A - B) \ (A \ B) = A" by blast lemma Diff_Int2: "A \ C - B \ C = A \ C - B" by blast lemma subset_UnE: assumes "C \ A \ B" obtains A' B' where "A' \ A" "B' \ B" "C = A' \ B'" proof show "C \ A \ A" "C \ B \ B" "C = (C \ A) \ (C \ B)" using assms by blast+ qed text \\<^medskip> Set complement\ lemma Compl_disjoint [simp]: "A \ - A = {}" by (fact inf_compl_bot) lemma Compl_disjoint2 [simp]: "- A \ A = {}" by (fact compl_inf_bot) lemma Compl_partition: "A \ - A = UNIV" by (fact sup_compl_top) lemma Compl_partition2: "- A \ A = UNIV" by (fact compl_sup_top) lemma double_complement: "- (-A) = A" for A :: "'a set" by (fact double_compl) (* already simp *) lemma Compl_Un: "- (A \ B) = (- A) \ (- B)" by (fact compl_sup) (* already simp *) lemma Compl_Int: "- (A \ B) = (- A) \ (- B)" by (fact compl_inf) (* already simp *) lemma subset_Compl_self_eq: "A \ - A \ A = {}" by blast lemma Un_Int_assoc_eq: "(A \ B) \ C = A \ (B \ C) \ C \ A" \ \Halmos, Naive Set Theory, page 16.\ by blast lemma Compl_UNIV_eq: "- UNIV = {}" by (fact compl_top_eq) (* already simp *) lemma Compl_empty_eq: "- {} = UNIV" by (fact compl_bot_eq) (* already simp *) lemma Compl_subset_Compl_iff [iff]: "- A \ - B \ B \ A" by (fact compl_le_compl_iff) (* FIXME: already simp *) lemma Compl_eq_Compl_iff [iff]: "- A = - B \ A = B" for A B :: "'a set" by (fact compl_eq_compl_iff) (* FIXME: already simp *) lemma Compl_insert: "- insert x A = (- A) - {x}" by blast text \\<^medskip> Bounded quantifiers. The following are not added to the default simpset because (a) they duplicate the body and (b) there are no similar rules for \Int\. \ lemma ball_Un: "(\x \ A \ B. P x) \ (\x\A. P x) \ (\x\B. P x)" by blast lemma bex_Un: "(\x \ A \ B. P x) \ (\x\A. P x) \ (\x\B. P x)" by blast text \\<^medskip> Set difference.\ lemma Diff_eq: "A - B = A \ (- B)" by blast lemma Diff_eq_empty_iff [simp]: "A - B = {} \ A \ B" by blast lemma Diff_cancel [simp]: "A - A = {}" by blast lemma Diff_idemp [simp]: "(A - B) - B = A - B" for A B :: "'a set" by blast lemma Diff_triv: "A \ B = {} \ A - B = A" by (blast elim: equalityE) lemma empty_Diff [simp]: "{} - A = {}" by blast lemma Diff_empty [simp]: "A - {} = A" by blast lemma Diff_UNIV [simp]: "A - UNIV = {}" by blast lemma Diff_insert0 [simp]: "x \ A \ A - insert x B = A - B" by blast lemma Diff_insert: "A - insert a B = A - B - {a}" \ \NOT SUITABLE FOR REWRITING since \{a} \ insert a 0\\ by blast lemma Diff_insert2: "A - insert a B = A - {a} - B" \ \NOT SUITABLE FOR REWRITING since \{a} \ insert a 0\\ by blast lemma insert_Diff_if: "insert x A - B = (if x \ B then A - B else insert x (A - B))" by auto lemma insert_Diff1 [simp]: "x \ B \ insert x A - B = A - B" by blast lemma insert_Diff_single[simp]: "insert a (A - {a}) = insert a A" by blast lemma insert_Diff: "a \ A \ insert a (A - {a}) = A" by blast lemma Diff_insert_absorb: "x \ A \ (insert x A) - {x} = A" by auto lemma Diff_disjoint [simp]: "A \ (B - A) = {}" by blast lemma Diff_partition: "A \ B \ A \ (B - A) = B" by blast lemma double_diff: "A \ B \ B \ C \ B - (C - A) = A" by blast lemma Un_Diff_cancel [simp]: "A \ (B - A) = A \ B" by blast lemma Un_Diff_cancel2 [simp]: "(B - A) \ A = B \ A" by blast lemma Diff_Un: "A - (B \ C) = (A - B) \ (A - C)" by blast lemma Diff_Int: "A - (B \ C) = (A - B) \ (A - C)" by blast lemma Diff_Diff_Int: "A - (A - B) = A \ B" by blast lemma Un_Diff: "(A \ B) - C = (A - C) \ (B - C)" by blast lemma Int_Diff: "(A \ B) - C = A \ (B - C)" by blast lemma Diff_Int_distrib: "C \ (A - B) = (C \ A) - (C \ B)" by blast lemma Diff_Int_distrib2: "(A - B) \ C = (A \ C) - (B \ C)" by blast lemma Diff_Compl [simp]: "A - (- B) = A \ B" by auto lemma Compl_Diff_eq [simp]: "- (A - B) = - A \ B" by blast lemma subset_Compl_singleton [simp]: "A \ - {b} \ b \ A" by blast text \\<^medskip> Quantification over type \<^typ>\bool\.\ lemma bool_induct: "P True \ P False \ P x" by (cases x) auto lemma all_bool_eq: "(\b. P b) \ P True \ P False" by (auto intro: bool_induct) lemma bool_contrapos: "P x \ \ P False \ P True" by (cases x) auto lemma ex_bool_eq: "(\b. P b) \ P True \ P False" by (auto intro: bool_contrapos) lemma UNIV_bool: "UNIV = {False, True}" by (auto intro: bool_induct) text \\<^medskip> \Pow\\ lemma Pow_empty [simp]: "Pow {} = {{}}" by (auto simp add: Pow_def) lemma Pow_singleton_iff [simp]: "Pow X = {Y} \ X = {} \ Y = {}" by blast (* somewhat slow *) lemma Pow_insert: "Pow (insert a A) = Pow A \ (insert a ` Pow A)" by (blast intro: image_eqI [where ?x = "u - {a}" for u]) lemma Pow_Compl: "Pow (- A) = {- B | B. A \ Pow B}" by (blast intro: exI [where ?x = "- u" for u]) lemma Pow_UNIV [simp]: "Pow UNIV = UNIV" by blast lemma Un_Pow_subset: "Pow A \ Pow B \ Pow (A \ B)" by blast lemma Pow_Int_eq [simp]: "Pow (A \ B) = Pow A \ Pow B" by blast text \\<^medskip> Miscellany.\ lemma set_eq_subset: "A = B \ A \ B \ B \ A" by blast lemma subset_iff: "A \ B \ (\t. t \ A \ t \ B)" by blast lemma subset_iff_psubset_eq: "A \ B \ A \ B \ A = B" unfolding less_le by blast lemma all_not_in_conv [simp]: "(\x. x \ A) \ A = {}" by blast lemma ex_in_conv: "(\x. x \ A) \ A \ {}" by blast lemma ball_simps [simp, no_atp]: "\A P Q. (\x\A. P x \ Q) \ ((\x\A. P x) \ Q)" "\A P Q. (\x\A. P \ Q x) \ (P \ (\x\A. Q x))" "\A P Q. (\x\A. P \ Q x) \ (P \ (\x\A. Q x))" "\A P Q. (\x\A. P x \ Q) \ ((\x\A. P x) \ Q)" "\P. (\x\{}. P x) \ True" "\P. (\x\UNIV. P x) \ (\x. P x)" "\a B P. (\x\insert a B. P x) \ (P a \ (\x\B. P x))" "\P Q. (\x\Collect Q. P x) \ (\x. Q x \ P x)" "\A P f. (\x\f`A. P x) \ (\x\A. P (f x))" "\A P. (\ (\x\A. P x)) \ (\x\A. \ P x)" by auto lemma bex_simps [simp, no_atp]: "\A P Q. (\x\A. P x \ Q) \ ((\x\A. P x) \ Q)" "\A P Q. (\x\A. P \ Q x) \ (P \ (\x\A. Q x))" "\P. (\x\{}. P x) \ False" "\P. (\x\UNIV. P x) \ (\x. P x)" "\a B P. (\x\insert a B. P x) \ (P a \ (\x\B. P x))" "\P Q. (\x\Collect Q. P x) \ (\x. Q x \ P x)" "\A P f. (\x\f`A. P x) \ (\x\A. P (f x))" "\A P. (\(\x\A. P x)) \ (\x\A. \ P x)" by auto lemma ex_image_cong_iff [simp, no_atp]: "(\x. x\f`A) \ A \ {}" "(\x. x\f`A \ P x) \ (\x\A. P (f x))" by auto subsubsection \Monotonicity of various operations\ lemma image_mono: "A \ B \ f ` A \ f ` B" by blast lemma Pow_mono: "A \ B \ Pow A \ Pow B" by blast lemma insert_mono: "C \ D \ insert a C \ insert a D" by blast lemma Un_mono: "A \ C \ B \ D \ A \ B \ C \ D" by (fact sup_mono) lemma Int_mono: "A \ C \ B \ D \ A \ B \ C \ D" by (fact inf_mono) lemma Diff_mono: "A \ C \ D \ B \ A - B \ C - D" by blast lemma Compl_anti_mono: "A \ B \ - B \ - A" by (fact compl_mono) text \\<^medskip> Monotonicity of implications.\ lemma in_mono: "A \ B \ x \ A \ x \ B" by (rule impI) (erule subsetD) lemma conj_mono: "P1 \ Q1 \ P2 \ Q2 \ (P1 \ P2) \ (Q1 \ Q2)" by iprover lemma disj_mono: "P1 \ Q1 \ P2 \ Q2 \ (P1 \ P2) \ (Q1 \ Q2)" by iprover lemma imp_mono: "Q1 \ P1 \ P2 \ Q2 \ (P1 \ P2) \ (Q1 \ Q2)" by iprover lemma imp_refl: "P \ P" .. lemma not_mono: "Q \ P \ \ P \ \ Q" by iprover lemma ex_mono: "(\x. P x \ Q x) \ (\x. P x) \ (\x. Q x)" by iprover lemma all_mono: "(\x. P x \ Q x) \ (\x. P x) \ (\x. Q x)" by iprover lemma Collect_mono: "(\x. P x \ Q x) \ Collect P \ Collect Q" by blast lemma Int_Collect_mono: "A \ B \ (\x. x \ A \ P x \ Q x) \ A \ Collect P \ B \ Collect Q" by blast lemmas basic_monos = subset_refl imp_refl disj_mono conj_mono ex_mono Collect_mono in_mono lemma eq_to_mono: "a = b \ c = d \ b \ d \ a \ c" by iprover subsubsection \Inverse image of a function\ definition vimage :: "('a \ 'b) \ 'b set \ 'a set" (infixr "-`" 90) where "f -` B \ {x. f x \ B}" lemma vimage_eq [simp]: "a \ f -` B \ f a \ B" unfolding vimage_def by blast lemma vimage_singleton_eq: "a \ f -` {b} \ f a = b" by simp lemma vimageI [intro]: "f a = b \ b \ B \ a \ f -` B" unfolding vimage_def by blast lemma vimageI2: "f a \ A \ a \ f -` A" unfolding vimage_def by fast lemma vimageE [elim!]: "a \ f -` B \ (\x. f a = x \ x \ B \ P) \ P" unfolding vimage_def by blast lemma vimageD: "a \ f -` A \ f a \ A" unfolding vimage_def by fast lemma vimage_empty [simp]: "f -` {} = {}" by blast lemma vimage_Compl: "f -` (- A) = - (f -` A)" by blast lemma vimage_Un [simp]: "f -` (A \ B) = (f -` A) \ (f -` B)" by blast lemma vimage_Int [simp]: "f -` (A \ B) = (f -` A) \ (f -` B)" by fast lemma vimage_Collect_eq [simp]: "f -` Collect P = {y. P (f y)}" by blast lemma vimage_Collect: "(\x. P (f x) = Q x) \ f -` (Collect P) = Collect Q" by blast lemma vimage_insert: "f -` (insert a B) = (f -` {a}) \ (f -` B)" \ \NOT suitable for rewriting because of the recurrence of \{a}\.\ by blast lemma vimage_Diff: "f -` (A - B) = (f -` A) - (f -` B)" by blast lemma vimage_UNIV [simp]: "f -` UNIV = UNIV" by blast lemma vimage_mono: "A \ B \ f -` A \ f -` B" \ \monotonicity\ by blast lemma vimage_image_eq: "f -` (f ` A) = {y. \x\A. f x = f y}" by (blast intro: sym) lemma image_vimage_subset: "f ` (f -` A) \ A" by blast lemma image_vimage_eq [simp]: "f ` (f -` A) = A \ range f" by blast lemma image_subset_iff_subset_vimage: "f ` A \ B \ A \ f -` B" by blast lemma vimage_const [simp]: "((\x. c) -` A) = (if c \ A then UNIV else {})" by auto lemma vimage_if [simp]: "((\x. if x \ B then c else d) -` A) = (if c \ A then (if d \ A then UNIV else B) else if d \ A then - B else {})" by (auto simp add: vimage_def) lemma vimage_inter_cong: "(\ w. w \ S \ f w = g w) \ f -` y \ S = g -` y \ S" by auto lemma vimage_ident [simp]: "(\x. x) -` Y = Y" by blast subsubsection \Singleton sets\ definition is_singleton :: "'a set \ bool" where "is_singleton A \ (\x. A = {x})" lemma is_singletonI [simp, intro!]: "is_singleton {x}" unfolding is_singleton_def by simp lemma is_singletonI': "A \ {} \ (\x y. x \ A \ y \ A \ x = y) \ is_singleton A" unfolding is_singleton_def by blast lemma is_singletonE: "is_singleton A \ (\x. A = {x} \ P) \ P" unfolding is_singleton_def by blast subsubsection \Getting the contents of a singleton set\ definition the_elem :: "'a set \ 'a" where "the_elem X = (THE x. X = {x})" lemma the_elem_eq [simp]: "the_elem {x} = x" by (simp add: the_elem_def) lemma is_singleton_the_elem: "is_singleton A \ A = {the_elem A}" by (auto simp: is_singleton_def) lemma the_elem_image_unique: assumes "A \ {}" and *: "\y. y \ A \ f y = f x" shows "the_elem (f ` A) = f x" unfolding the_elem_def proof (rule the1_equality) from \A \ {}\ obtain y where "y \ A" by auto with * have "f x = f y" by simp with \y \ A\ have "f x \ f ` A" by blast with * show "f ` A = {f x}" by auto then show "\!x. f ` A = {x}" by auto qed subsubsection \Least value operator\ lemma Least_mono: "mono f \ \x\S. \y\S. x \ y \ (LEAST y. y \ f ` S) = f (LEAST x. x \ S)" for f :: "'a::order \ 'b::order" \ \Courtesy of Stephan Merz\ apply clarify apply (erule_tac P = "\x. x \ S" in LeastI2_order) apply fast apply (rule LeastI2_order) apply (auto elim: monoD intro!: order_antisym) done subsubsection \Monad operation\ definition bind :: "'a set \ ('a \ 'b set) \ 'b set" where "bind A f = {x. \B \ f`A. x \ B}" hide_const (open) bind lemma bind_bind: "Set.bind (Set.bind A B) C = Set.bind A (\x. Set.bind (B x) C)" for A :: "'a set" by (auto simp: bind_def) lemma empty_bind [simp]: "Set.bind {} f = {}" by (simp add: bind_def) lemma nonempty_bind_const: "A \ {} \ Set.bind A (\_. B) = B" by (auto simp: bind_def) lemma bind_const: "Set.bind A (\_. B) = (if A = {} then {} else B)" by (auto simp: bind_def) lemma bind_singleton_conv_image: "Set.bind A (\x. {f x}) = f ` A" by (auto simp: bind_def) subsubsection \Operations for execution\ definition is_empty :: "'a set \ bool" where [code_abbrev]: "is_empty A \ A = {}" hide_const (open) is_empty definition remove :: "'a \ 'a set \ 'a set" where [code_abbrev]: "remove x A = A - {x}" hide_const (open) remove lemma member_remove [simp]: "x \ Set.remove y A \ x \ A \ x \ y" by (simp add: remove_def) definition filter :: "('a \ bool) \ 'a set \ 'a set" where [code_abbrev]: "filter P A = {a \ A. P a}" hide_const (open) filter lemma member_filter [simp]: "x \ Set.filter P A \ x \ A \ P x" by (simp add: filter_def) instantiation set :: (equal) equal begin definition "HOL.equal A B \ A \ B \ B \ A" instance by standard (auto simp add: equal_set_def) end text \Misc\ definition pairwise :: "('a \ 'a \ bool) \ 'a set \ bool" where "pairwise R S \ (\x \ S. \y \ S. x \ y \ R x y)" lemma pairwise_alt: "pairwise R S \ (\x\S. \y\S-{x}. R x y)" by (auto simp add: pairwise_def) lemma pairwise_trivial [simp]: "pairwise (\i j. j \ i) I" by (auto simp: pairwise_def) lemma pairwiseI [intro?]: "pairwise R S" if "\x y. x \ S \ y \ S \ x \ y \ R x y" using that by (simp add: pairwise_def) lemma pairwiseD: "R x y" and "R y x" if "pairwise R S" "x \ S" and "y \ S" and "x \ y" using that by (simp_all add: pairwise_def) lemma pairwise_empty [simp]: "pairwise P {}" by (simp add: pairwise_def) lemma pairwise_singleton [simp]: "pairwise P {A}" by (simp add: pairwise_def) lemma pairwise_insert: "pairwise r (insert x s) \ (\y. y \ s \ y \ x \ r x y \ r y x) \ pairwise r s" by (force simp: pairwise_def) lemma pairwise_subset: "pairwise P S \ T \ S \ pairwise P T" by (force simp: pairwise_def) lemma pairwise_mono: "\pairwise P A; \x y. P x y \ Q x y; B \ A\ \ pairwise Q B" by (fastforce simp: pairwise_def) lemma pairwise_imageI: "pairwise P (f ` A)" if "\x y. x \ A \ y \ A \ x \ y \ f x \ f y \ P (f x) (f y)" using that by (auto intro: pairwiseI) lemma pairwise_image: "pairwise r (f ` s) \ pairwise (\x y. (f x \ f y) \ r (f x) (f y)) s" by (force simp: pairwise_def) definition disjnt :: "'a set \ 'a set \ bool" where "disjnt A B \ A \ B = {}" lemma disjnt_self_iff_empty [simp]: "disjnt S S \ S = {}" by (auto simp: disjnt_def) lemma disjnt_iff: "disjnt A B \ (\x. \ (x \ A \ x \ B))" by (force simp: disjnt_def) lemma disjnt_sym: "disjnt A B \ disjnt B A" using disjnt_iff by blast lemma disjnt_empty1 [simp]: "disjnt {} A" and disjnt_empty2 [simp]: "disjnt A {}" by (auto simp: disjnt_def) lemma disjnt_insert1 [simp]: "disjnt (insert a X) Y \ a \ Y \ disjnt X Y" by (simp add: disjnt_def) lemma disjnt_insert2 [simp]: "disjnt Y (insert a X) \ a \ Y \ disjnt Y X" by (simp add: disjnt_def) lemma disjnt_subset1 : "\disjnt X Y; Z \ X\ \ disjnt Z Y" by (auto simp: disjnt_def) lemma disjnt_subset2 : "\disjnt X Y; Z \ Y\ \ disjnt X Z" by (auto simp: disjnt_def) lemma disjnt_Un1 [simp]: "disjnt (A \ B) C \ disjnt A C \ disjnt B C" by (auto simp: disjnt_def) lemma disjnt_Un2 [simp]: "disjnt C (A \ B) \ disjnt C A \ disjnt C B" by (auto simp: disjnt_def) lemma disjoint_image_subset: "\pairwise disjnt \; \X. X \ \ \ f X \ X\ \ pairwise disjnt (f `\)" unfolding disjnt_def pairwise_def by fast lemma pairwise_disjnt_iff: "pairwise disjnt \ \ (\x. \\<^sub>\\<^sub>1 X. X \ \ \ x \ X)" by (auto simp: Uniq_def disjnt_iff pairwise_def) lemma Int_emptyI: "(\x. x \ A \ x \ B \ False) \ A \ B = {}" by blast lemma in_image_insert_iff: assumes "\C. C \ B \ x \ C" shows "A \ insert x ` B \ x \ A \ A - {x} \ B" (is "?P \ ?Q") proof assume ?P then show ?Q using assms by auto next assume ?Q then have "x \ A" and "A - {x} \ B" by simp_all from \A - {x} \ B\ have "insert x (A - {x}) \ insert x ` B" by (rule imageI) also from \x \ A\ have "insert x (A - {x}) = A" by auto finally show ?P . qed hide_const (open) member not_member lemmas equalityI = subset_antisym lemmas set_mp = subsetD lemmas set_rev_mp = rev_subsetD ML \ val Ball_def = @{thm Ball_def} val Bex_def = @{thm Bex_def} val CollectD = @{thm CollectD} val CollectE = @{thm CollectE} val CollectI = @{thm CollectI} val Collect_conj_eq = @{thm Collect_conj_eq} val Collect_mem_eq = @{thm Collect_mem_eq} val IntD1 = @{thm IntD1} val IntD2 = @{thm IntD2} val IntE = @{thm IntE} val IntI = @{thm IntI} val Int_Collect = @{thm Int_Collect} val UNIV_I = @{thm UNIV_I} val UNIV_witness = @{thm UNIV_witness} val UnE = @{thm UnE} val UnI1 = @{thm UnI1} val UnI2 = @{thm UnI2} val ballE = @{thm ballE} val ballI = @{thm ballI} val bexCI = @{thm bexCI} val bexE = @{thm bexE} val bexI = @{thm bexI} val bex_triv = @{thm bex_triv} val bspec = @{thm bspec} val contra_subsetD = @{thm contra_subsetD} val equalityCE = @{thm equalityCE} val equalityD1 = @{thm equalityD1} val equalityD2 = @{thm equalityD2} val equalityE = @{thm equalityE} val equalityI = @{thm equalityI} val imageE = @{thm imageE} val imageI = @{thm imageI} val image_Un = @{thm image_Un} val image_insert = @{thm image_insert} val insert_commute = @{thm insert_commute} val insert_iff = @{thm insert_iff} val mem_Collect_eq = @{thm mem_Collect_eq} val rangeE = @{thm rangeE} val rangeI = @{thm rangeI} val range_eqI = @{thm range_eqI} val subsetCE = @{thm subsetCE} val subsetD = @{thm subsetD} val subsetI = @{thm subsetI} val subset_refl = @{thm subset_refl} val subset_trans = @{thm subset_trans} val vimageD = @{thm vimageD} val vimageE = @{thm vimageE} val vimageI = @{thm vimageI} val vimageI2 = @{thm vimageI2} val vimage_Collect = @{thm vimage_Collect} val vimage_Int = @{thm vimage_Int} val vimage_Un = @{thm vimage_Un} \ end diff --git a/src/Provers/quantifier1.ML b/src/Provers/quantifier1.ML --- a/src/Provers/quantifier1.ML +++ b/src/Provers/quantifier1.ML @@ -1,285 +1,285 @@ (* Title: Provers/quantifier1.ML Author: Tobias Nipkow Copyright 1997 TU Munich Simplification procedures for turning ? x. ... & x = t & ... into ? x. x = t & ... & ... where the `? x. x = t &' in the latter formula must be eliminated by ordinary simplification. and ! x. (... & x = t & ...) --> P x into ! x. x = t --> (... & ...) --> P x where the `!x. x=t -->' in the latter formula is eliminated by ordinary simplification. And analogously for t=x, but the eqn is not turned around! NB Simproc is only triggered by "!x. P(x) & P'(x) --> Q(x)"; "!x. x=t --> P(x)" is covered by the congruence rule for -->; "!x. t=x --> P(x)" must be taken care of by an ordinary rewrite rule. As must be "? x. t=x & P(x)". And similarly for the bounded quantifiers. Gries etc call this the "1 point rules" The above also works for !x1..xn. and ?x1..xn by moving the defined quantifier inside first, but not for nested bounded quantifiers. For set comprehensions the basic permutations ... & x = t & ... -> x = t & (... & ...) ... & t = x & ... -> t = x & (... & ...) are also exported. To avoid looping, NONE is returned if the term cannot be rearranged, esp if x=t/t=x sits at the front already. *) signature QUANTIFIER1_DATA = sig (*abstract syntax*) val dest_eq: term -> (term * term) option val dest_conj: term -> (term * term) option val dest_imp: term -> (term * term) option val conj: term val imp: term (*rules*) val iff_reflection: thm (* P <-> Q ==> P == Q *) val iffI: thm val iff_trans: thm val conjI: thm val conjE: thm val impI: thm val mp: thm val exI: thm val exE: thm val uncurry: thm (* P --> Q --> R ==> P & Q --> R *) val iff_allI: thm (* !!x. P x <-> Q x ==> (!x. P x) = (!x. Q x) *) val iff_exI: thm (* !!x. P x <-> Q x ==> (? x. P x) = (? x. Q x) *) val all_comm: thm (* (!x y. P x y) = (!y x. P x y) *) val ex_comm: thm (* (? x y. P x y) = (? y x. P x y) *) end; signature QUANTIFIER1 = sig - val prove_one_point_all_tac: Proof.context -> tactic - val prove_one_point_ex_tac: Proof.context -> tactic val rearrange_all: Proof.context -> cterm -> thm option val rearrange_All: Proof.context -> cterm -> thm option - val rearrange_ex: Proof.context -> cterm -> thm option - val rearrange_ball: (Proof.context -> tactic) -> Proof.context -> cterm -> thm option - val rearrange_bex: (Proof.context -> tactic) -> Proof.context -> cterm -> thm option + val rearrange_Ball: (Proof.context -> tactic) -> Proof.context -> cterm -> thm option + val rearrange_Ex: Proof.context -> cterm -> thm option + val rearrange_Bex: (Proof.context -> tactic) -> Proof.context -> cterm -> thm option val rearrange_Collect: (Proof.context -> tactic) -> Proof.context -> cterm -> thm option end; functor Quantifier1(Data: QUANTIFIER1_DATA): QUANTIFIER1 = struct (* FIXME: only test! *) fun def xs eq = (case Data.dest_eq eq of SOME (s, t) => let val n = length xs in s = Bound n andalso not (loose_bvar1 (t, n)) orelse t = Bound n andalso not (loose_bvar1 (s, n)) end | NONE => false); fun extract_conj fst xs t = (case Data.dest_conj t of NONE => NONE | SOME (P, Q) => if def xs P then (if fst then NONE else SOME (xs, P, Q)) else if def xs Q then SOME (xs, Q, P) else (case extract_conj false xs P of SOME (xs, eq, P') => SOME (xs, eq, Data.conj $ P' $ Q) | NONE => (case extract_conj false xs Q of SOME (xs, eq, Q') => SOME (xs, eq, Data.conj $ P $ Q') | NONE => NONE))); fun extract_imp fst xs t = (case Data.dest_imp t of NONE => NONE | SOME (P, Q) => if def xs P then (if fst then NONE else SOME (xs, P, Q)) else (case extract_conj false xs P of SOME (xs, eq, P') => SOME (xs, eq, Data.imp $ P' $ Q) | NONE => (case extract_imp false xs Q of NONE => NONE | SOME (xs, eq, Q') => SOME (xs, eq, Data.imp $ P $ Q')))); fun extract_conj_from_judgment ctxt fst xs t = if Object_Logic.is_judgment ctxt t then let val judg $ t' = t in case extract_conj fst xs t' of NONE => NONE | SOME (xs, eq, P) => SOME (xs, judg $ eq, judg $ P) end else NONE; fun extract_implies ctxt fst xs t = (case try Logic.dest_implies t of NONE => NONE | SOME (P, Q) => if def xs P then (if fst then NONE else SOME (xs, P, Q)) else (case extract_conj_from_judgment ctxt false xs P of SOME (xs, eq, P') => SOME (xs, eq, Logic.implies $ P' $ Q) | NONE => (case extract_implies ctxt false xs Q of NONE => NONE | SOME (xs, eq, Q') => (SOME (xs, eq, Logic.implies $ P $ Q'))))); fun extract_quant ctxt extract q = let fun exqu xs ((qC as Const (qa, _)) $ Abs (x, T, Q)) = if qa = q then exqu ((qC, x, T) :: xs) Q else NONE | exqu xs P = extract ctxt (null xs) xs P in exqu [] end; fun iff_reflection_tac ctxt = resolve_tac ctxt [Data.iff_reflection] 1; fun qcomm_tac ctxt qcomm qI i = REPEAT_DETERM (resolve_tac ctxt [qcomm] i THEN resolve_tac ctxt [qI] i); (* Proves (? x0..xn. ... & x0 = t & ...) = (? x1..xn x0. x0 = t & ... & ...) Better: instantiate exI *) local val excomm = Data.ex_comm RS Data.iff_trans; in - fun prove_one_point_ex_tac ctxt = + fun prove_one_point_Ex_tac ctxt = qcomm_tac ctxt excomm Data.iff_exI 1 THEN resolve_tac ctxt [Data.iffI] 1 THEN ALLGOALS (EVERY' [eresolve_tac ctxt [Data.exE], REPEAT_DETERM o eresolve_tac ctxt [Data.conjE], resolve_tac ctxt [Data.exI], DEPTH_SOLVE_1 o ares_tac ctxt [Data.conjI]]) end; (* Proves (! x0..xn. (... & x0 = t & ...) --> P x0) = (! x1..xn x0. x0 = t --> (... & ...) --> P x0) *) local fun tac ctxt = SELECT_GOAL (EVERY1 [REPEAT o dresolve_tac ctxt [Data.uncurry], REPEAT o resolve_tac ctxt [Data.impI], eresolve_tac ctxt [Data.mp], REPEAT o eresolve_tac ctxt [Data.conjE], REPEAT o ares_tac ctxt [Data.conjI]]); val all_comm = Data.all_comm RS Data.iff_trans; val All_comm = @{thm swap_params [THEN transitive]}; in - fun prove_one_point_all_tac ctxt = + fun prove_one_point_All_tac ctxt = EVERY1 [qcomm_tac ctxt all_comm Data.iff_allI, resolve_tac ctxt [Data.iff_allI], resolve_tac ctxt [Data.iffI], tac ctxt, tac ctxt]; - fun prove_one_point_All_tac ctxt = + fun prove_one_point_all_tac ctxt = EVERY1 [qcomm_tac ctxt All_comm @{thm equal_allI}, resolve_tac ctxt [@{thm equal_allI}], resolve_tac ctxt [@{thm equal_intr_rule}], Object_Logic.atomize_prems_tac ctxt, tac ctxt, Object_Logic.atomize_prems_tac ctxt, tac ctxt]; end fun prove_conv ctxt tu tac = let val (goal, ctxt') = yield_singleton (Variable.import_terms true) (Logic.mk_equals tu) ctxt; val thm = Goal.prove ctxt' [] [] goal (fn {context = ctxt'', ...} => tac ctxt''); in singleton (Variable.export ctxt' ctxt) thm end; fun renumber l u (Bound i) = Bound (if i < l orelse i > u then i else if i = u then l else i + 1) | renumber l u (s $ t) = renumber l u s $ renumber l u t | renumber l u (Abs (x, T, t)) = Abs (x, T, renumber (l + 1) (u + 1) t) | renumber _ _ atom = atom; fun quantify qC x T xs P = let fun quant [] P = P | quant ((qC, x, T) :: xs) P = quant xs (qC $ Abs (x, T, P)); val n = length xs; val Q = if n = 0 then P else renumber 0 n P; in quant xs (qC $ Abs (x, T, Q)) end; fun rearrange_all ctxt ct = (case Thm.term_of ct of F as (all as Const (q, _)) $ Abs (x, T, P) => - (case extract_quant ctxt (K extract_imp) q P of + (case extract_quant ctxt extract_implies q P of NONE => NONE | SOME (xs, eq, Q) => - let val R = quantify all x T xs (Data.imp $ eq $ Q) - in SOME (prove_conv ctxt (F, R) (iff_reflection_tac THEN' prove_one_point_all_tac)) end) + let val R = quantify all x T xs (Logic.implies $ eq $ Q) + in SOME (prove_conv ctxt (F, R) prove_one_point_all_tac) end) | _ => NONE); fun rearrange_All ctxt ct = (case Thm.term_of ct of F as (all as Const (q, _)) $ Abs (x, T, P) => - (case extract_quant ctxt extract_implies q P of + (case extract_quant ctxt (K extract_imp) q P of NONE => NONE | SOME (xs, eq, Q) => - let val R = quantify all x T xs (Logic.implies $ eq $ Q) - in SOME (prove_conv ctxt (F, R) prove_one_point_All_tac) end) + let val R = quantify all x T xs (Data.imp $ eq $ Q) + in SOME (prove_conv ctxt (F, R) (iff_reflection_tac THEN' prove_one_point_All_tac)) end) | _ => NONE); -fun rearrange_ball tac ctxt ct = +fun rearrange_Ball tac ctxt ct = (case Thm.term_of ct of F as Ball $ A $ Abs (x, T, P) => (case extract_imp true [] P of NONE => NONE | SOME (xs, eq, Q) => if not (null xs) then NONE else let val R = Data.imp $ eq $ Q - in SOME (prove_conv ctxt (F, Ball $ A $ Abs (x, T, R)) (iff_reflection_tac THEN' tac)) end) + in SOME (prove_conv ctxt (F, Ball $ A $ Abs (x, T, R)) + (iff_reflection_tac THEN' tac THEN' prove_one_point_All_tac)) end) | _ => NONE); -fun rearrange_ex ctxt ct = +fun rearrange_Ex ctxt ct = (case Thm.term_of ct of F as (ex as Const (q, _)) $ Abs (x, T, P) => (case extract_quant ctxt (K extract_conj) q P of NONE => NONE | SOME (xs, eq, Q) => let val R = quantify ex x T xs (Data.conj $ eq $ Q) - in SOME (prove_conv ctxt (F, R) (iff_reflection_tac THEN' prove_one_point_ex_tac)) end) + in SOME (prove_conv ctxt (F, R) (iff_reflection_tac THEN' prove_one_point_Ex_tac)) end) | _ => NONE); -fun rearrange_bex tac ctxt ct = +fun rearrange_Bex tac ctxt ct = (case Thm.term_of ct of F as Bex $ A $ Abs (x, T, P) => (case extract_conj true [] P of NONE => NONE | SOME (xs, eq, Q) => if not (null xs) then NONE - else SOME (prove_conv ctxt (F, Bex $ A $ Abs (x, T, Data.conj $ eq $ Q)) (iff_reflection_tac THEN' tac))) + else SOME (prove_conv ctxt (F, Bex $ A $ Abs (x, T, Data.conj $ eq $ Q)) + (iff_reflection_tac THEN' tac THEN' prove_one_point_Ex_tac))) | _ => NONE); fun rearrange_Collect tac ctxt ct = (case Thm.term_of ct of F as Collect $ Abs (x, T, P) => (case extract_conj true [] P of NONE => NONE | SOME (_, eq, Q) => let val R = Collect $ Abs (x, T, Data.conj $ eq $ Q) in SOME (prove_conv ctxt (F, R) (iff_reflection_tac THEN' tac)) end) | _ => NONE); end; diff --git a/src/ZF/OrdQuant.thy b/src/ZF/OrdQuant.thy --- a/src/ZF/OrdQuant.thy +++ b/src/ZF/OrdQuant.thy @@ -1,366 +1,362 @@ (* Title: ZF/OrdQuant.thy Authors: Krzysztof Grabczewski and L C Paulson *) section \Special quantifiers\ theory OrdQuant imports Ordinal begin subsection \Quantifiers and union operator for ordinals\ definition (* Ordinal Quantifiers *) oall :: "[i, i => o] => o" where "oall(A, P) == \x. x P(x)" definition oex :: "[i, i => o] => o" where "oex(A, P) == \x. x i] => i" where "OUnion(i,B) == {z: \x\i. B(x). Ord(i)}" syntax "_oall" :: "[idt, i, o] => o" (\(3\_<_./ _)\ 10) "_oex" :: "[idt, i, o] => o" (\(3\_<_./ _)\ 10) "_OUNION" :: "[idt, i, i] => i" (\(3\_<_./ _)\ 10) translations "\x "CONST oall(a, \x. P)" "\x "CONST oex(a, \x. P)" "\x "CONST OUnion(a, \x. B)" subsubsection \simplification of the new quantifiers\ (*MOST IMPORTANT that this is added to the simpset BEFORE Ord_atomize is proved. Ord_atomize would convert this rule to x < 0 ==> P(x) == True, which causes dire effects!*) lemma [simp]: "(\x<0. P(x))" by (simp add: oall_def) lemma [simp]: "~(\x<0. P(x))" by (simp add: oex_def) lemma [simp]: "(\x (Ord(i) \ P(i) & (\xx (Ord(i) & (P(i) | (\xUnion over ordinals\ lemma Ord_OUN [intro,simp]: "[| !!x. x Ord(B(x)) |] ==> Ord(\xx i < (\xb(a); Ord(\x i \ (\x (\xi\nat.i)=nat"}! *) lemma OUN_least: "(!!x. x B(x) \ C) ==> (\x C" by (simp add: OUnion_def UN_least ltI) lemma OUN_least_le: "[| Ord(i); !!x. x b(x) \ i |] ==> (\x i" by (simp add: OUnion_def UN_least_le ltI Ord_0_le) lemma le_implies_OUN_le_OUN: "[| !!x. x c(x) \ d(x) |] ==> (\x (\x A ==> Ord(B(x))) ==> (\z < (\x\A. B(x)). C(z)) = (\x\A. \z < B(x). C(z))" by (simp add: OUnion_def) lemma OUN_Union_eq: "(!!x. x \ X ==> Ord(x)) ==> (\z < \(X). C(z)) = (\x\X. \z < x. C(z))" by (simp add: OUnion_def) (*So that rule_format will get rid of this quantifier...*) lemma atomize_oall [symmetric, rulify]: "(!!x. x P(x)) == Trueprop (\xuniversal quantifier for ordinals\ lemma oallI [intro!]: "[| !!x. x P(x) |] ==> \xx P(x)" by (simp add: oall_def) lemma oallE: "[| \x Q; ~x Q |] ==> Q" by (simp add: oall_def, blast) lemma rev_oallE [elim]: "[| \x Q; P(x) ==> Q |] ==> Q" by (simp add: oall_def, blast) (*Trival rewrite rule. @{term"(\xP"} holds only if a is not 0!*) lemma oall_simp [simp]: "(\x True" by blast (*Congruence rule for rewriting*) lemma oall_cong [cong]: "[| a=a'; !!x. x P(x) <-> P'(x) |] ==> oall(a, %x. P(x)) <-> oall(a', %x. P'(x))" by (simp add: oall_def) subsubsection \existential quantifier for ordinals\ lemma oexI [intro]: "[| P(x); x \xx P(a); a \xx Q |] ==> Q" apply (simp add: oex_def, blast) done lemma oex_cong [cong]: "[| a=a'; !!x. x P(x) <-> P'(x) |] ==> oex(a, %x. P(x)) <-> oex(a', %x. P'(x))" apply (simp add: oex_def cong add: conj_cong) done subsubsection \Rules for Ordinal-Indexed Unions\ lemma OUN_I [intro]: "[| a B(a) |] ==> b: (\z (\z B(a); a R |] ==> R" apply (unfold OUnion_def lt_def, blast) done lemma OUN_iff: "b \ (\x (\x B(x))" by (unfold OUnion_def oex_def lt_def, blast) lemma OUN_cong [cong]: "[| i=j; !!x. x C(x)=D(x) |] ==> (\xxy P(x) |] ==> P(i)" apply (simp add: lt_def oall_def) apply (erule conjE) apply (erule Ord_induct, assumption, blast) done subsection \Quantification over a class\ definition "rall" :: "[i=>o, i=>o] => o" where "rall(M, P) == \x. M(x) \ P(x)" definition "rex" :: "[i=>o, i=>o] => o" where "rex(M, P) == \x. M(x) & P(x)" syntax "_rall" :: "[pttrn, i=>o, o] => o" (\(3\_[_]./ _)\ 10) "_rex" :: "[pttrn, i=>o, o] => o" (\(3\_[_]./ _)\ 10) translations "\x[M]. P" \ "CONST rall(M, \x. P)" "\x[M]. P" \ "CONST rex(M, \x. P)" subsubsection\Relativized universal quantifier\ lemma rallI [intro!]: "[| !!x. M(x) ==> P(x) |] ==> \x[M]. P(x)" by (simp add: rall_def) lemma rspec: "[| \x[M]. P(x); M(x) |] ==> P(x)" by (simp add: rall_def) (*Instantiates x first: better for automatic theorem proving?*) lemma rev_rallE [elim]: "[| \x[M]. P(x); ~ M(x) ==> Q; P(x) ==> Q |] ==> Q" by (simp add: rall_def, blast) lemma rallE: "[| \x[M]. P(x); P(x) ==> Q; ~ M(x) ==> Q |] ==> Q" by blast (*Trival rewrite rule; (\x[M].P)<->P holds only if A is nonempty!*) lemma rall_triv [simp]: "(\x[M]. P) \ ((\x. M(x)) \ P)" by (simp add: rall_def) (*Congruence rule for rewriting*) lemma rall_cong [cong]: "(!!x. M(x) ==> P(x) <-> P'(x)) ==> (\x[M]. P(x)) <-> (\x[M]. P'(x))" by (simp add: rall_def) subsubsection\Relativized existential quantifier\ lemma rexI [intro]: "[| P(x); M(x) |] ==> \x[M]. P(x)" by (simp add: rex_def, blast) (*The best argument order when there is only one M(x)*) lemma rev_rexI: "[| M(x); P(x) |] ==> \x[M]. P(x)" by blast (*Not of the general form for such rules... *) lemma rexCI: "[| \x[M]. ~P(x) ==> P(a); M(a) |] ==> \x[M]. P(x)" by blast lemma rexE [elim!]: "[| \x[M]. P(x); !!x. [| M(x); P(x) |] ==> Q |] ==> Q" by (simp add: rex_def, blast) (*We do not even have (\x[M]. True) <-> True unless A is nonempty!!*) lemma rex_triv [simp]: "(\x[M]. P) \ ((\x. M(x)) \ P)" by (simp add: rex_def) lemma rex_cong [cong]: "(!!x. M(x) ==> P(x) <-> P'(x)) ==> (\x[M]. P(x)) <-> (\x[M]. P'(x))" by (simp add: rex_def cong: conj_cong) lemma rall_is_ball [simp]: "(\x[%z. z\A]. P(x)) <-> (\x\A. P(x))" by blast lemma rex_is_bex [simp]: "(\x[%z. z\A]. P(x)) <-> (\x\A. P(x))" by blast lemma atomize_rall: "(!!x. M(x) ==> P(x)) == Trueprop (\x[M]. P(x))" by (simp add: rall_def atomize_all atomize_imp) declare atomize_rall [symmetric, rulify] lemma rall_simps1: "(\x[M]. P(x) & Q) <-> (\x[M]. P(x)) & ((\x[M]. False) | Q)" "(\x[M]. P(x) | Q) <-> ((\x[M]. P(x)) | Q)" "(\x[M]. P(x) \ Q) <-> ((\x[M]. P(x)) \ Q)" "(~(\x[M]. P(x))) <-> (\x[M]. ~P(x))" by blast+ lemma rall_simps2: "(\x[M]. P & Q(x)) <-> ((\x[M]. False) | P) & (\x[M]. Q(x))" "(\x[M]. P | Q(x)) <-> (P | (\x[M]. Q(x)))" "(\x[M]. P \ Q(x)) <-> (P \ (\x[M]. Q(x)))" by blast+ lemmas rall_simps [simp] = rall_simps1 rall_simps2 lemma rall_conj_distrib: "(\x[M]. P(x) & Q(x)) <-> ((\x[M]. P(x)) & (\x[M]. Q(x)))" by blast lemma rex_simps1: "(\x[M]. P(x) & Q) <-> ((\x[M]. P(x)) & Q)" "(\x[M]. P(x) | Q) <-> (\x[M]. P(x)) | ((\x[M]. True) & Q)" "(\x[M]. P(x) \ Q) <-> ((\x[M]. P(x)) \ ((\x[M]. True) & Q))" "(~(\x[M]. P(x))) <-> (\x[M]. ~P(x))" by blast+ lemma rex_simps2: "(\x[M]. P & Q(x)) <-> (P & (\x[M]. Q(x)))" "(\x[M]. P | Q(x)) <-> ((\x[M]. True) & P) | (\x[M]. Q(x))" "(\x[M]. P \ Q(x)) <-> (((\x[M]. False) | P) \ (\x[M]. Q(x)))" by blast+ lemmas rex_simps [simp] = rex_simps1 rex_simps2 lemma rex_disj_distrib: "(\x[M]. P(x) | Q(x)) <-> ((\x[M]. P(x)) | (\x[M]. Q(x)))" by blast subsubsection\One-point rule for bounded quantifiers\ lemma rex_triv_one_point1 [simp]: "(\x[M]. x=a) <-> ( M(a))" by blast lemma rex_triv_one_point2 [simp]: "(\x[M]. a=x) <-> ( M(a))" by blast lemma rex_one_point1 [simp]: "(\x[M]. x=a & P(x)) <-> ( M(a) & P(a))" by blast lemma rex_one_point2 [simp]: "(\x[M]. a=x & P(x)) <-> ( M(a) & P(a))" by blast lemma rall_one_point1 [simp]: "(\x[M]. x=a \ P(x)) <-> ( M(a) \ P(a))" by blast lemma rall_one_point2 [simp]: "(\x[M]. a=x \ P(x)) <-> ( M(a) \ P(a))" by blast subsubsection\Sets as Classes\ definition setclass :: "[i,i] => o" (\##_\ [40] 40) where "setclass(A) == %x. x \ A" lemma setclass_iff [simp]: "setclass(A,x) <-> x \ A" by (simp add: setclass_def) lemma rall_setclass_is_ball [simp]: "(\x[##A]. P(x)) <-> (\x\A. P(x))" by auto lemma rex_setclass_is_bex [simp]: "(\x[##A]. P(x)) <-> (\x\A. P(x))" by auto ML \ val Ord_atomize = atomize ([(\<^const_name>\oall\, @{thms ospec}), (\<^const_name>\rall\, @{thms rspec})] @ ZF_conn_pairs, ZF_mem_pairs); \ declaration \fn _ => Simplifier.map_ss (Simplifier.set_mksimps (fn ctxt => map mk_eq o Ord_atomize o Variable.gen_all ctxt)) \ text \Setting up the one-point-rule simproc\ simproc_setup defined_rex ("\x[M]. P(x) & Q(x)") = \ - fn _ => Quantifier1.rearrange_bex - (fn ctxt => - unfold_tac ctxt @{thms rex_def} THEN - Quantifier1.prove_one_point_ex_tac ctxt) + fn _ => Quantifier1.rearrange_Bex + (fn ctxt => unfold_tac ctxt @{thms rex_def}) \ simproc_setup defined_rall ("\x[M]. P(x) \ Q(x)") = \ - fn _ => Quantifier1.rearrange_ball - (fn ctxt => - unfold_tac ctxt @{thms rall_def} THEN - Quantifier1.prove_one_point_all_tac ctxt) + fn _ => Quantifier1.rearrange_Ball + (fn ctxt => unfold_tac ctxt @{thms rall_def}) \ end diff --git a/src/ZF/pair.thy b/src/ZF/pair.thy --- a/src/ZF/pair.thy +++ b/src/ZF/pair.thy @@ -1,189 +1,185 @@ (* Title: ZF/pair.thy Author: Lawrence C Paulson, Cambridge University Computer Laboratory Copyright 1992 University of Cambridge *) section\Ordered Pairs\ theory pair imports upair begin ML_file \simpdata.ML\ setup \ map_theory_simpset (Simplifier.set_mksimps (fn ctxt => map mk_eq o ZF_atomize o Variable.gen_all ctxt) #> Simplifier.add_cong @{thm if_weak_cong}) \ ML \val ZF_ss = simpset_of \<^context>\ simproc_setup defined_Bex ("\x\A. P(x) & Q(x)") = \ - fn _ => Quantifier1.rearrange_bex - (fn ctxt => - unfold_tac ctxt @{thms Bex_def} THEN - Quantifier1.prove_one_point_ex_tac ctxt) + fn _ => Quantifier1.rearrange_Bex + (fn ctxt => unfold_tac ctxt @{thms Bex_def}) \ simproc_setup defined_Ball ("\x\A. P(x) \ Q(x)") = \ - fn _ => Quantifier1.rearrange_ball - (fn ctxt => - unfold_tac ctxt @{thms Ball_def} THEN - Quantifier1.prove_one_point_all_tac ctxt) + fn _ => Quantifier1.rearrange_Ball + (fn ctxt => unfold_tac ctxt @{thms Ball_def}) \ (** Lemmas for showing that uniquely determines a and b **) lemma singleton_eq_iff [iff]: "{a} = {b} \ a=b" by (rule extension [THEN iff_trans], blast) lemma doubleton_eq_iff: "{a,b} = {c,d} \ (a=c & b=d) | (a=d & b=c)" by (rule extension [THEN iff_trans], blast) lemma Pair_iff [simp]: " = \ a=c & b=d" by (simp add: Pair_def doubleton_eq_iff, blast) lemmas Pair_inject = Pair_iff [THEN iffD1, THEN conjE, elim!] lemmas Pair_inject1 = Pair_iff [THEN iffD1, THEN conjunct1] lemmas Pair_inject2 = Pair_iff [THEN iffD1, THEN conjunct2] lemma Pair_not_0: " \ 0" apply (unfold Pair_def) apply (blast elim: equalityE) done lemmas Pair_neq_0 = Pair_not_0 [THEN notE, elim!] declare sym [THEN Pair_neq_0, elim!] lemma Pair_neq_fst: "=a ==> P" proof (unfold Pair_def) assume eq: "{{a, a}, {a, b}} = a" have "{a, a} \ {{a, a}, {a, b}}" by (rule consI1) hence "{a, a} \ a" by (simp add: eq) moreover have "a \ {a, a}" by (rule consI1) ultimately show "P" by (rule mem_asym) qed lemma Pair_neq_snd: "=b ==> P" proof (unfold Pair_def) assume eq: "{{a, a}, {a, b}} = b" have "{a, b} \ {{a, a}, {a, b}}" by blast hence "{a, b} \ b" by (simp add: eq) moreover have "b \ {a, b}" by blast ultimately show "P" by (rule mem_asym) qed subsection\Sigma: Disjoint Union of a Family of Sets\ text\Generalizes Cartesian product\ lemma Sigma_iff [simp]: ": Sigma(A,B) \ a \ A & b \ B(a)" by (simp add: Sigma_def) lemma SigmaI [TC,intro!]: "[| a \ A; b \ B(a) |] ==> \ Sigma(A,B)" by simp lemmas SigmaD1 = Sigma_iff [THEN iffD1, THEN conjunct1] lemmas SigmaD2 = Sigma_iff [THEN iffD1, THEN conjunct2] (*The general elimination rule*) lemma SigmaE [elim!]: "[| c \ Sigma(A,B); !!x y.[| x \ A; y \ B(x); c= |] ==> P |] ==> P" by (unfold Sigma_def, blast) lemma SigmaE2 [elim!]: "[| \ Sigma(A,B); [| a \ A; b \ B(a) |] ==> P |] ==> P" by (unfold Sigma_def, blast) lemma Sigma_cong: "[| A=A'; !!x. x \ A' ==> B(x)=B'(x) |] ==> Sigma(A,B) = Sigma(A',B')" by (simp add: Sigma_def) (*Sigma_cong, Pi_cong NOT given to Addcongs: they cause flex-flex pairs and the "Check your prover" error. Most Sigmas and Pis are abbreviated as * or -> *) lemma Sigma_empty1 [simp]: "Sigma(0,B) = 0" by blast lemma Sigma_empty2 [simp]: "A*0 = 0" by blast lemma Sigma_empty_iff: "A*B=0 \ A=0 | B=0" by blast subsection\Projections \<^term>\fst\ and \<^term>\snd\\ lemma fst_conv [simp]: "fst() = a" by (simp add: fst_def) lemma snd_conv [simp]: "snd() = b" by (simp add: snd_def) lemma fst_type [TC]: "p \ Sigma(A,B) ==> fst(p) \ A" by auto lemma snd_type [TC]: "p \ Sigma(A,B) ==> snd(p) \ B(fst(p))" by auto lemma Pair_fst_snd_eq: "a \ Sigma(A,B) ==> = a" by auto subsection\The Eliminator, \<^term>\split\\ (*A META-equality, so that it applies to higher types as well...*) lemma split [simp]: "split(%x y. c(x,y), ) == c(a,b)" by (simp add: split_def) lemma split_type [TC]: "[| p \ Sigma(A,B); !!x y.[| x \ A; y \ B(x) |] ==> c(x,y):C() |] ==> split(%x y. c(x,y), p) \ C(p)" by (erule SigmaE, auto) lemma expand_split: "u \ A*B ==> R(split(c,u)) \ (\x\A. \y\B. u = \ R(c(x,y)))" by (auto simp add: split_def) subsection\A version of \<^term>\split\ for Formulae: Result Type \<^typ>\o\\ lemma splitI: "R(a,b) ==> split(R, )" by (simp add: split_def) lemma splitE: "[| split(R,z); z \ Sigma(A,B); !!x y. [| z = ; R(x,y) |] ==> P |] ==> P" by (auto simp add: split_def) lemma splitD: "split(R,) ==> R(a,b)" by (simp add: split_def) text \ \bigskip Complex rules for Sigma. \ lemma split_paired_Bex_Sigma [simp]: "(\z \ Sigma(A,B). P(z)) \ (\x \ A. \y \ B(x). P())" by blast lemma split_paired_Ball_Sigma [simp]: "(\z \ Sigma(A,B). P(z)) \ (\x \ A. \y \ B(x). P())" by blast end