theory Inductive_Relations imports Main begin section\A simple example\ inductive is_even :: "nat \ bool" where "is_even 0" | "is_even m \ is_even (Suc (Suc m))" print_theorems thm is_even.induct thm is_even.intros term "is_even" (*proving properties of is_even is simple using the generated induction principle*) lemma is_even_plus [intro]: (*intro: mark this theorem for use as an introduction rule by automation*) assumes "is_even m" and "is_even n" shows "is_even (m + n)" using assms proof(induction rule: is_even.induct) assume "is_even n" thus "is_even (0 + n)" by force next fix m assume "is_even n \ is_even (m + n)" and "is_even n" hence "is_even (m + n)" by auto hence "is_even (Suc (Suc (m + n)))" using is_even.intros by auto thus "is_even ((Suc (Suc m)) + n)" by auto qed (*how about working backwards?*) lemma assumes "is_even (Suc (Suc m))" shows "is_even m" using assms oops (*stuck, no obvious way to work forwards from is_even (Suc (Suc m))*) (*the inductive_cases command will produce an elimination procedure for an inductive relation*) inductive_cases is_even_Suc_Suc_elim: "is_even (Suc (Suc m))" (*note that is_even_Suc_Suc_elim is describing all the possible ways that is_even (Suc (Suc m)) could have been derived from the definition of is_even above*) thm is_even_Suc_Suc_elim lemma assumes "is_even (Suc (Suc m))" shows "is_even m" using assms apply - apply(erule is_even_Suc_Suc_elim) apply assumption done lemma assumes "is_even (Suc (Suc m))" shows "is_even m" using assms by(auto elim: is_even_Suc_Suc_elim) (*tell auto to use the elim rule*) (*alternatively use the [elim] attribute*) declare is_even_Suc_Suc_elim [elim] section\A slightly more complex example\ (*mutual relations are declared using "and", and then just listing all the introduction rules for the two relations*) inductive is_even' :: "nat \ bool" and is_odd' :: "nat \ bool" where "is_even' 0" | "is_odd' m \ is_even' (Suc m)" | "is_even' m \ is_odd' (Suc m)" print_theorems thm is_even'_is_odd'.induct thm is_even'_is_odd'.intros (*intro attribute for auto tells automation to use the listed rules as introduction rules*) lemma is_odd'_One: shows "is_odd' 1" by(auto intro: is_even'_is_odd'.intros) (*adding the intro attribute everywhere is a pain: instead you can declare the relation's introduction rules as intro rules for the purposes of automation at the point of definition, like so:*) inductive is_even'' :: "nat \ bool" and is_odd'' :: "nat \ bool" where is_even''_Zero [intro!]: "is_even'' 0" | is_even''_Suc [intro!]: "is_odd'' m \ is_even'' (Suc m)" | is_odd''_Suc [intro!]: "is_even'' m \ is_odd'' (Suc m)" (*note also we have now given the introduction rules explicit names*) thm is_even''_Zero thm is_odd''_Suc lemma is_odd''_One: shows "is_odd'' 1" by auto (*much easier!*) (*note for mutually inductive relations there are two relevant induction principles automatically generated*) thm is_even''_is_odd''.induct thm is_even''_is_odd''.inducts (*mutually recursive definitions very often require proofs by mutual induction!*) lemma shows "is_even'' m \ is_even'' n \ is_even'' (m + n)" and "is_odd'' m \ is_even'' n \ is_odd'' (m + n)" proof(induction rule: is_even''_is_odd''.inducts) assume "is_even'' n" thus "is_even'' (0 + n)" by auto next fix m assume "is_even'' n \ is_odd'' (m + n)" and "is_even'' n" hence "is_odd'' (m + n)" by auto thus "is_even'' (Suc m + n)" by auto next fix m assume "is_even'' n \ is_even'' (m + n)" and "is_even'' n" hence "is_even'' (m + n)" by auto thus "is_odd'' (Suc m + n)" by auto qed lemma is_even''_is_odd''_plus1 [intro!]: shows "is_even'' m \ is_even'' n \ is_even'' (m + n)" and "is_odd'' m \ is_even'' n \ is_odd'' (m + n)" by(induction rule: is_even''_is_odd''.inducts, auto) (*isabelle's automation is pretty smart...*) lemma is_even''_is_odd''_plus2 [intro!]: shows "is_even'' m \ is_odd'' n \ is_odd'' (m + n)" and "is_odd'' m \ is_odd'' n \ is_even'' (m + n)" by(induction rule: is_even''_is_odd''.inducts, auto) section\Another example\ inductive is_finite :: "'a set \ bool" where "is_finite {}" | "is_finite ss \ is_finite ({s} \ ss)" thm is_finite.induct thm is_finite.intros (*can declare introduction rules after the fact using a declare command*) declare is_finite.intros [intro!] (*alternatively:*) lemmas [intro!] = is_finite.intros (*isabelle tells us that it's ignoring the duplicate rules*) lemma assumes "is_finite ss" and "s \ ss" shows "is_finite ({s} \ ss)" using assms proof(induction rule: is_finite.induct) show "is_finite ({s} \ {})" by force next fix ss and t assume "s \ {t} \ ss" and "s \ ss \ is_finite ({s} \ ss)" hence "is_finite ({s} \ ss)" by auto hence "is_finite ({t} \ ({s} \ ss))" using is_finite.intros by force thus "is_finite ({s} \ ({t} \ ss))" by(clarsimp simp add: insert_commute) qed lemma is_finite_notin_induct: assumes "is_finite ss" and "s \ ss" shows "is_finite ({s} \ ss)" using assms by(induction rule: is_finite.induct; force) lemma is_finite_Un [intro!]: assumes "is_finite ss" and "is_finite ts" shows "is_finite (ss \ ts)" using assms proof(induction rule: is_finite.induct) assume "is_finite ts" thus "is_finite ({} \ ts)" by force next fix ss s assume "is_finite ts" and "is_finite ts \ is_finite (ss \ ts)" hence "is_finite (ss \ ts)" by auto hence "is_finite ({s} \ (ss \ ts))" by blast thus "is_finite (({s} \ ss) \ ts)" by auto qed lemma assumes "is_finite ss" and "\i. i \ ss \ is_finite (f i)" shows "is_finite (\i\ss. f i)" using assms proof(induction rule: is_finite.induct) show "is_finite (UNION {} f)" by auto next fix ss s assume 1: "\i. i \ {s} \ ss \ is_finite (f i)" and 2: "(\i. i \ ss \ is_finite (f i)) \ is_finite (UNION ss f)" (*first show the equivalence of the goal with something simpler (a useful trick)...*) have 3: "is_finite (UNION ({s} \ ss) f) \ is_finite (f s \ (UNION ss f))" by simp have "is_finite (f s)" using 1 by auto also have "is_finite (UNION ss f)" using 2 1 by auto ultimately have "is_finite (f s \ (UNION ss f))" by auto (*use the equivalence proved above to finally show the goal*) thus "is_finite (UNION ({s} \ ss) f)" using 3 by auto qed lemma is_finite_UNION [intro!]: assumes "is_finite ss" and "\i. i \ ss \ is_finite (f i)" shows "is_finite (\i\ss. f i)" using assms by(induction rule: is_finite.induct, auto) section\Inductively defined sets\ inductive_set example :: "nat set" where example_0 [intro!]: "0 \ example" | example_1 [intro!]: "1 \ example" | example_plus [intro]: "\m \ example; n \ example\ \ (m + n) \ example" thm example.induct thm example_0 lemma all_nats_in_example [intro!]: shows "x \ example" proof(induction x) show "0 \ example" by auto next fix x assume "x \ example" hence "1 + x \ example" by blast thus "Suc x \ example" by auto qed lemma example_is_UNIV: shows "example = UNIV" by force section\In-depth example: Kolmogorov's double-negation translation\ (*one can embed classical logic into intuitionistic logic through so-called double negation translations (the most famous being the Goedel-Gentzen translation for FOL). with the trivial embedding of intuitionistic logic into classical logic, we have that classical and intuitionistic logics can both be embedded in each other. here we study a translation due to kolmogorov. notably, from a computer science perspective, this translation corresponds to a call-by-name continuation passing translation for the simply-typed lambda-calculus under the curry-howard correspondence. (if you know any type theory you might try to show that last claim is indeed true...)*) (*propositional formulae*) datatype frm = FF ("\") | TT ("\") | Imp "frm" "frm" (infixr "\" 65) | Conj "frm" "frm" (infixr "andalso" 65) | Disj "frm" "frm" (infixr "orelse" 65) | Not "frm" (*we could have made the set of formulae much smaller and used definitions or abbreviations to add disjunction, negation, and so on...*) (*natural deduction for intuitionistic propositional logic*) inductive intuitionistic_natural_deduction :: "frm set \ frm \ bool" (infix "\\<^sub>I" 50) where "\ \ \ \ \ \\<^sub>I \" | "\ \\<^sub>I \" | "\ \\<^sub>I \ \ \ \\<^sub>I \" | "\ \\<^sub>I \ \ \ \ \ \\<^sub>I \ \ \ \\<^sub>I \" | "\ \ {\} \\<^sub>I \ \ \ \\<^sub>I \ \ \" | "\ \\<^sub>I \ \ \ \\<^sub>I \ \ \ \\<^sub>I \ andalso \" | "\ \\<^sub>I \ andalso \ \ \ \\<^sub>I \" | "\ \\<^sub>I \ andalso \ \ \ \\<^sub>I \" | "\ \\<^sub>I \ orelse \ \ \ \ {\} \\<^sub>I \ \ \ \ {\} \\<^sub>I \ \ \ \\<^sub>I \" | "\ \\<^sub>I \ \ \ \\<^sub>I \ orelse \" | "\ \\<^sub>I \ \ \ \\<^sub>I \ orelse \" | "\ \\<^sub>I Not \ \ \ \\<^sub>I \ \ \ \\<^sub>I \" | "\ \ {\} \\<^sub>I \ \ \ \\<^sub>I Not \" (*example proof: a derived version of the NotE rule*) lemma intuitionistic_not_elim': assumes 1: "\ \\<^sub>I Not \" and 2: "\ \\<^sub>I \" shows "\ \\<^sub>I \" proof - have "\ \\<^sub>I \" using 1 2 by(rule intuitionistic_natural_deduction.intros) thus "\ \\<^sub>I \" by(rule intuitionistic_natural_deduction.intros) qed (*natural deduction for classical propositional logic*) inductive classical_natural_deduction :: "frm set \ frm \ bool" (infix "\\<^sub>C" 50) where "\ \ \ \ \ \\<^sub>C \" | "\ \\<^sub>C \" | "\ \\<^sub>C \ \ \ \\<^sub>C \" | "\ \\<^sub>C \ \ \ \ \ \\<^sub>C \ \ \ \\<^sub>C \" | "\ \ {\} \\<^sub>C \ \ \ \\<^sub>C \ \ \" | "\ \\<^sub>C \ \ \ \\<^sub>C \ \ \ \\<^sub>C \ andalso \" | "\ \\<^sub>C \ andalso \ \ \ \\<^sub>C \" | "\ \\<^sub>C \ andalso \ \ \ \\<^sub>C \" | "\ \\<^sub>C \ orelse \ \ \ \ {\} \\<^sub>C \ \ \ \ {\} \\<^sub>C \ \ \ \\<^sub>C \" | "\ \\<^sub>C \ \ \ \\<^sub>C \ orelse \" | "\ \\<^sub>C \ \ \ \\<^sub>C \ orelse \" | "\ \\<^sub>C Not \ \ \ \\<^sub>C \ \ \ \\<^sub>C \" | "\ \ {\} \\<^sub>C \ \ \ \\<^sub>C Not \" | "\ \\<^sub>C Not \ orelse \" (*the double negation translation, due to kolmogorov. note compared to some other double negation translations this is extremely "inefficient" as it places double negations at every subformula occurence. the glivenko, goedel, and kurota translations are much more efficient as they use fewer double negations...*) fun dnt :: "frm \ frm" where "dnt \ = Not (Not \)" | "dnt \ = Not (Not \)" | "dnt (\ \ \) = Not (Not (dnt \ \ dnt \))" | "dnt (\ andalso \) = Not (Not (dnt \ andalso dnt \))" | "dnt (\ orelse \) = Not (Not (dnt \ orelse dnt \))" | "dnt (Not \) = Not (Not (Not (dnt \)))" (*the dnt function prepends two Nots in front of everything. this lemma will be used extensively later on to "add a bit of structure" to translated formulae so that we can work with them using the introduction rules of the ND relations above...*) lemma dnt_Not_Not_obtain: shows "\\'. dnt \ = Not (Not \')" by(induction \, auto) (*the weakening lemma for intuitionistic ND. this is both a standard result in proof (and type) theory which shows our definitions are reasonable and also very useful later on down the file*) theorem intuitionistic_natural_deduction_weaken: assumes "\ \\<^sub>I \" and "\ \ \'" shows "\' \\<^sub>I \" using assms proof(induction arbitrary: \' rule: intuitionistic_natural_deduction.induct) fix \ \' and \ \ assume "\\'. \ \ {\} \ \' \ \' \\<^sub>I \" and "\ \ \'" hence "\' \ {\} \\<^sub>I \" by auto thus "\' \\<^sub>I \ \ \" by(blast intro: intuitionistic_natural_deduction.intros) next fix \ \' and \ \ \ assume "\\'. \ \ \' \ \' \\<^sub>I \ orelse \" and "\\'. \ \ {\} \ \' \ \' \\<^sub>I \" and "\\'. \ \ {\} \ \' \ \' \\<^sub>I \" and "\ \ \'" hence "\' \\<^sub>I \ orelse \" and "\' \ {\} \\<^sub>I \" and "\' \ {\} \\<^sub>I \" by(auto simp add: sup.absorb_iff1) thus "\' \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) next fix \ \' and \ assume "\\'. \ \ \' \ \' \\<^sub>I Not \" and "\\'. \ \ \' \ \' \\<^sub>I \" and "\ \ \'" hence "\' \\<^sub>I Not \" and "\' \\<^sub>I \" by auto thus "\' \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) next fix \ \' and \ assume "\\'. \ \ {\} \ \' \ \' \\<^sub>I \" and "\ \ \'" hence "\' \ {\} \\<^sub>I \" by auto thus "\' \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) qed (blast intro: intuitionistic_natural_deduction.intros)+ (*in IPL you can freely introduce double negations*) lemma intuitionistic_natural_deduction_Not_Not_intro: assumes "\ \\<^sub>I \" shows "\ \\<^sub>I Not (Not \)" proof - have "\ \ {Not \} \\<^sub>I \" by(rule intuitionistic_natural_deduction_weaken) (rule assms, force) also have "\ \ {Not \} \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "\ \ {Not \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) thus "\ \\<^sub>I Not (Not \)" by(blast intro: intuitionistic_natural_deduction.intros) qed (*the dnt function preserves derivability in IPL*) lemma intuitionistic_natural_deduction_dnt_closed: assumes "\ \\<^sub>I \" shows "dnt ` \ \\<^sub>I dnt \" using assms proof(induction rule: intuitionistic_natural_deduction.induct) fix \ and \ :: "frm set" assume "\ \ \" hence "dnt \ \ dnt ` \" by simp thus "dnt ` \ \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) next fix \ :: "frm set" have "dnt ` \ \ {Not \} \\<^sub>I Not \" and "dnt ` \ \ {Not \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros)+ hence "dnt ` \ \ {Not \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" by(auto intro: intuitionistic_natural_deduction.intros) next fix \ and \ :: "frm set" assume "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \\<^sub>I Not (Not \)" by auto also have "dnt ` \ \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately show "dnt ` \ \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) next fix \ \ and \ :: "frm set" assume 1: "dnt ` \ \\<^sub>I dnt (\ \ \)" and 2: "dnt ` \ \\<^sub>I dnt \" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by blast from 2 have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I dnt \ \ dnt \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I Not (Not \')" using * by auto also have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ \ dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) from 1 and this also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ \ dnt \))" by - (rule intuitionistic_natural_deduction_weaken, force+) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not \')" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by auto next fix \ \ and \ :: "frm set" assume "dnt ` (\ \ {\}) \\<^sub>I dnt \" hence "dnt ` \ \ {dnt \} \\<^sub>I dnt \" by auto hence "dnt ` \ \\<^sub>I dnt \ \ dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {frm.Not (dnt \ \ dnt \)} \\<^sub>I dnt \ \ dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ {frm.Not (dnt \ \ dnt \)} \\<^sub>I Not (dnt \ \ dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {frm.Not (dnt \ \ dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I frm.Not (frm.Not (dnt \ \ dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ \ \)" by clarsimp next fix \ \ and \ :: "frm set" assume "dnt ` \ \\<^sub>I dnt \" and "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \\<^sub>I dnt \ andalso dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {frm.Not (dnt \ andalso dnt \)} \\<^sub>I dnt \ andalso dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ {frm.Not (dnt \ andalso dnt \)} \\<^sub>I Not (dnt \ andalso dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {frm.Not (dnt \ andalso dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I frm.Not (frm.Not (dnt \ andalso dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ andalso \)" by clarsimp next fix \ \ and \ :: "frm set" assume 1: "dnt ` \ \\<^sub>I dnt (\ andalso \)" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by blast hence "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not (Not \')" by(auto intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ andalso dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ andalso dnt \))" using 1 by - (rule intuitionistic_natural_deduction_weaken, force+) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by - (rule intuitionistic_natural_deduction.intros, force+) hence "dnt ` \ \\<^sub>I Not (Not \')" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by auto next fix \ \ and \ :: "frm set" assume 1: "dnt ` \ \\<^sub>I dnt (\ andalso \)" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by blast hence "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not (Not \')" by(auto intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ andalso dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ andalso dnt \))" using 1 by - (rule intuitionistic_natural_deduction_weaken, force+) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by - (rule intuitionistic_natural_deduction.intros, force+) hence "dnt ` \ \\<^sub>I Not (Not \')" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by auto next fix \ \ \ and \ :: "frm set" assume 1: "dnt ` \ \\<^sub>I dnt (\ orelse \)" and 2: "dnt ` (\ \ {\}) \\<^sub>I dnt \" and 3: "dnt ` (\ \ {\}) \\<^sub>I dnt \" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by blast hence "dnt ` \ \\<^sub>I Not (Not (dnt \ orelse dnt \))" and "dnt ` \ \ {dnt \} \\<^sub>I Not (Not \')" and "dnt ` \ \ {dnt \} \\<^sub>I Not (Not \')" using 1 2 3 by clarsimp+ have "dnt ` \ \ {Not \', dnt \ orelse dnt \} \\<^sub>I dnt \ orelse dnt \" by(blast intro: intuitionistic_natural_deduction.intros) moreover have "dnt ` \ \ {Not \', dnt \ orelse dnt \, dnt \} \\<^sub>I Not (Not \')" using 2 * by - (rule intuitionistic_natural_deduction_weaken, force+) moreover have "dnt ` \ \ {Not \', dnt \ orelse dnt \, dnt \} \\<^sub>I Not (Not \')" using 3 * by - (rule intuitionistic_natural_deduction_weaken, force+) ultimately have "dnt ` \ \ {Not \', dnt \ orelse dnt \} \\<^sub>I Not (Not \')" by - (rule intuitionistic_natural_deduction.intros, (force simp add: insert_commute)+) also have "dnt ` \ \ {Not \', dnt \ orelse dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ orelse dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ orelse dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) from this and 1 also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ orelse dnt \))" by - (rule intuitionistic_natural_deduction_weaken, force+) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not \')" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by clarsimp next fix \ \ and \ :: "frm set" assume "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) hence "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I dnt \ orelse dnt \" by(blast intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I Not (dnt \ orelse dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (dnt \ orelse dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ orelse \)" by clarsimp next fix \ \ and \ :: "frm set" assume "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) hence "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I dnt \ orelse dnt \" by(blast intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I Not (dnt \ orelse dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (dnt \ orelse dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (dnt \ orelse dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ orelse \)" by clarsimp next fix \ and \ :: "frm set" assume "dnt ` \ \\<^sub>I dnt (frm.Not \)" and "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \\<^sub>I Not (Not (Not (dnt \)))" and "dnt ` \ \\<^sub>I Not (Not (dnt \))" by(auto intro: intuitionistic_natural_deduction_Not_Not_intro) hence "dnt ` \ \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \} \\<^sub>I \" by(rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ {Not \} \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not \)" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" by clarsimp next fix \ and \ :: "frm set" assume "dnt ` (\ \ {\}) \\<^sub>I dnt \" hence "dnt ` \ \ {dnt \} \\<^sub>I dnt \" by auto hence "dnt ` \ \ {Not (Not (dnt \)), dnt \} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ {Not (Not (dnt \)), dnt \} \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (Not (dnt \)), dnt \} \\<^sub>I \" by(auto intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not (Not (dnt \))} \\<^sub>I Not (dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) also have "dnt ` \ \ {Not (Not (dnt \))} \\<^sub>I Not (Not (dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (Not (dnt \))} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (Not (dnt \)))" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (Not \)" by clarsimp qed (*conjunction and disjunction have a useful property in IPL*) lemma intuitionistic_natural_deduction_Disj_Conj: shows "\ \ {Not (\ orelse \)} \\<^sub>I Not \ andalso Not \" proof - have "\ \ {Not (\ orelse \), \} \\<^sub>I \ orelse \" by(blast intro: intuitionistic_natural_deduction.intros) also have "\ \ {Not (\ orelse \), \} \\<^sub>I Not (\ orelse \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "\ \ {Not (\ orelse \), \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence 1: "\ \ {Not (\ orelse \)} \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) have "\ \ {Not (\ orelse \), \} \\<^sub>I \ orelse \" by(blast intro: intuitionistic_natural_deduction.intros) also have "\ \ {Not (\ orelse \), \} \\<^sub>I Not (\ orelse \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "\ \ {Not (\ orelse \), \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence 2: "\ \ {Not (\ orelse \)} \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) show "\ \ {Not (\ orelse \)} \\<^sub>I Not \ andalso Not \" using 1 2 by(blast intro: intuitionistic_natural_deduction.intros) qed (*classical propositional logic can be embedded into intuitionistic propositional logic using kolmogorov's translation (the reverse direction is trivial)...*) theorem kolmogorov: assumes "\ \\<^sub>C \" shows "dnt ` \ \\<^sub>I (dnt \)" using assms proof(induction rule: classical_natural_deduction.induct) fix \ and \ :: "frm set" assume "\ \ \" hence "\ \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_dnt_closed) next fix \ have "dnt ` \ \ {Not \} \\<^sub>I Not \" and "dnt ` \ \ {Not \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros)+ have "dnt ` \ \ {Not \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" by(auto intro: intuitionistic_natural_deduction.intros) next fix \ and \ assume "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \\<^sub>I Not (Not \)" by simp also have "dnt ` \ \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately show "dnt ` \ \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) next fix \ \ and \ assume 1: "dnt ` \ \\<^sub>I dnt (\ \ \)" and 2: "dnt ` \ \\<^sub>I dnt \" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by auto hence 3: "dnt ` \ \\<^sub>I Not (Not (dnt \ \ dnt \))" using 1 by simp have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken[OF 2], force) also have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I dnt \ \ dnt \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I Not (Not \')" using * by auto also have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ \ dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ \ dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ \ dnt \))" using 1 by clarsimp (rule intuitionistic_natural_deduction_weaken, force+) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not \')" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by auto next fix \ \ and \ assume "dnt ` (\ \ {\}) \\<^sub>I dnt \" hence "dnt ` \ \ {dnt \} \\<^sub>I dnt \" by auto hence "dnt ` \ \\<^sub>I dnt \ \ dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ { Not (dnt \ \ dnt \) } \\<^sub>I dnt \ \ dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ { Not (dnt \ \ dnt \) } \\<^sub>I Not (dnt \ \ dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ { Not (dnt \ \ dnt \) } \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (dnt \ \ dnt \))" by(rule intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ \ \)" by auto next fix \ \ and \ assume "dnt ` \ \\<^sub>I dnt \" and "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \\<^sub>I dnt \ andalso dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not (dnt \ andalso dnt \)} \\<^sub>I dnt \ andalso dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ {Not (dnt \ andalso dnt \)} \\<^sub>I Not (dnt \ andalso dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (dnt \ andalso dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (dnt \ andalso dnt \))" by(rule intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ andalso \)" by clarsimp next fix \ \ and \ assume 1: "dnt ` \ \\<^sub>I dnt (\ andalso \)" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by auto have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not (Not \')" using * by auto also have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ andalso dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ andalso dnt \))" by(rule intuitionistic_natural_deduction_weaken) (rule 1[simplified], force) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not \')" by(rule intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by auto next fix \ \ and \ assume 1: "dnt ` \ \\<^sub>I dnt (\ andalso \)" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by auto have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not (Not \')" using * by auto also have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ andalso dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ andalso dnt \)" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ andalso dnt \))" by(rule intuitionistic_natural_deduction_weaken) (rule 1[simplified], force) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not \')" by(rule intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by auto next fix \ \ \ and \ assume 1: "dnt ` \ \\<^sub>I dnt (\ orelse \)" and 2: "dnt ` (\ \ {\}) \\<^sub>I dnt \" and 3: "dnt ` (\ \ {\}) \\<^sub>I dnt \" obtain \' where *: "dnt \ = Not (Not \')" using dnt_Not_Not_obtain by auto have "dnt ` \ \ {Not \', dnt \ orelse dnt \} \\<^sub>I Not (Not \')" apply - (*you can mix apply-style proofs with Isar...*) apply(rule intuitionistic_natural_deduction.intros(9)) apply(rule intuitionistic_natural_deduction.intros(1), force) apply(subst *[symmetric]) apply(rule intuitionistic_natural_deduction_weaken[OF 2], force) apply(subst *[symmetric]) apply(rule intuitionistic_natural_deduction_weaken[OF 3], force) done also have "dnt ` \ \ {Not \', dnt \ orelse dnt \} \\<^sub>I Not \'" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not \', dnt \ orelse dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not \'} \\<^sub>I Not (dnt \ orelse dnt \)" by - (rule intuitionistic_natural_deduction.intros(13), clarsimp simp add: insert_commute) also have "dnt ` \ \ {Not \'} \\<^sub>I Not (Not (dnt \ orelse dnt \))" using 1 by clarsimp (rule intuitionistic_natural_deduction_weaken, force+) ultimately have "dnt ` \ \ {Not \'} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not \')" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt \" using * by auto next fix \ \ and \ assume "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) hence "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I dnt \ orelse dnt \" by(blast intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I frm.Not (dnt \ orelse dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I frm.Not (frm.Not (dnt \ orelse dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ orelse \)" by clarsimp next fix \ \ and \ assume "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken, force+) hence "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I dnt \ orelse dnt \" by(blast intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I frm.Not (dnt \ orelse dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {frm.Not (dnt \ orelse dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I frm.Not (frm.Not (dnt \ orelse dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (\ orelse \)" by clarsimp next fix \ and \ assume 1: "dnt ` \ \\<^sub>I dnt (Not \)" and "dnt ` \ \\<^sub>I dnt \" hence "dnt ` \ \ {Not (dnt \)} \\<^sub>I dnt \" by - (rule intuitionistic_natural_deduction_weaken, force+) also have "dnt ` \ \ {Not (dnt \)} \\<^sub>I Not (dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \\<^sub>I frm.Not (frm.Not (frm.Not (dnt \)))" using 1 by clarsimp ultimately show "dnt ` \ \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) next fix \ and \ assume "dnt ` (\ \ {\}) \\<^sub>I dnt \" hence "dnt ` \ \ {dnt \} \\<^sub>I dnt \" by auto hence "dnt ` \ \ {Not (Not (dnt \)), dnt \} \\<^sub>I dnt \" by(rule intuitionistic_natural_deduction_weaken, force) also have "dnt ` \ \ {Not (Not (dnt \)), dnt \} \\<^sub>I Not \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (Not (dnt \)), dnt \} \\<^sub>I \" by(auto intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not (Not (dnt \))} \\<^sub>I Not (dnt \)" by - (rule intuitionistic_natural_deduction.intros(13), simp add: insert_commute) also have "dnt ` \ \ {Not (Not (dnt \))} \\<^sub>I Not (Not (dnt \))" by(rule intuitionistic_natural_deduction.intros, force) ultimately have "dnt ` \ \ {Not (Not (dnt \))} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (Not (dnt \)))" by(rule intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (Not \)" by auto next fix \ and \ have "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \)), dnt \} \\<^sub>I Not (Not (Not (frm.Not (dnt \)))) andalso Not (dnt \)" using intuitionistic_natural_deduction_Disj_Conj by simp hence "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \)), dnt \} \\<^sub>I Not (Not (Not (frm.Not (dnt \))))" and "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \)), dnt \} \\<^sub>I Not (dnt \)" by(blast intro: intuitionistic_natural_deduction.intros)+ also have "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \)), dnt \} \\<^sub>I dnt \" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \)), dnt \} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \))} \\<^sub>I frm.Not (dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \))} \\<^sub>I Not (frm.Not (dnt \))" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \), Not (frm.Not (dnt \))} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \)} \\<^sub>I Not (Not (frm.Not (dnt \)))" by - (rule intuitionistic_natural_deduction.intros, simp add: insert_commute) hence "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \)} \\<^sub>I Not (Not (frm.Not (dnt \))) orelse dnt \" by(blast intro: intuitionistic_natural_deduction.intros) also have "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \)} \\<^sub>I Not (Not (Not (frm.Not (dnt \))) orelse dnt \)" by(blast intro: intuitionistic_natural_deduction.intros) ultimately have "dnt ` \ \ {Not (Not (Not (frm.Not (dnt \))) orelse dnt \)} \\<^sub>I \" by(blast intro: intuitionistic_natural_deduction.intros) hence "dnt ` \ \\<^sub>I Not (Not (Not (Not (frm.Not (dnt \))) orelse dnt \))" by(rule intuitionistic_natural_deduction.intros) thus "dnt ` \ \\<^sub>I dnt (Not \ orelse \)" by clarsimp qed (*and we are done...*) end