theory Demo06
imports Main
begin

section {* Proof about sets *}

text{*A manual proof in set theory*}

thm equalityI subsetI
thm UnI1 UnI2 UnE

lemma "A \<union> B = B \<union> A" 
  apply(rule equalityI)
   apply(rule subsetI)
   apply(erule UnE)
    apply(rule UnI2)
    apply(assumption)
   apply(rule UnI1)
   apply(assumption)
   apply(rule subsetI)
  apply(erule UnE)
   apply(rule UnI2)
   apply(assumption)
  apply(rule UnI1)
  apply(assumption)
  done


text{* Most simple proofs in set theory are automatic *}

lemma "-(A \<union> B) = (-A \<inter> -B)"
  by blast

lemma "{x. P x \<and> Q x} = {x. P x} \<inter> {x. Q x}"
  by blast


-- ------------------------------------------------------------------------

section {*Inductive definitions*}

inductive_set Fin :: "'a set set"
  where
    emptyI:  "{} \<in> Fin"
  | insertI: "A \<in> Fin \<Longrightarrow> insert a A \<in> Fin"

print_theorems

inductive_set Ev :: "nat set"
  where
    ZeroI: "0 \<in> Ev"
  | Add2I: "n \<in> Ev \<Longrightarrow> Suc(Suc n) \<in> Ev"

print_theorems


text{* Using the introduction rules: *}
lemma "Suc(Suc(Suc(Suc 0))) \<in> Ev"
  apply(rule Add2I)
  apply(rule Add2I)
  apply(rule ZeroI)
  done

text{* Using the elimination rules: *}
lemma "n \<in> Ev \<Longrightarrow> n = 0 \<or> (\<exists>n' \<in> Ev. n = Suc (Suc n'))"
  -- {* case analysis *}
  apply (erule Ev.cases)
   apply blast
  apply blast
  done


subsection {* Rule Induction *}

text{*A simple inductive proof: *}
lemma "n \<in> Ev \<Longrightarrow> n+n \<in> Ev"
  apply(erule Ev.inducts)
   apply(simp)
   apply(rule ZeroI)
  apply(simp)
  apply(rule Add2I)
  apply(rule Add2I)
  apply(assumption)
  done

text{*
  You can also use the rules for @{term Ev} Ev as conditional
  simplification rules. This can shorten proofs considerably.
  \emph{Warning}:
  conditional rules can lead to nontermination of the simplifier.  The
  rules for @{term Ev} are OK because the premises are always
  `smaller' than the conclusion. The list of rules for @{term Ev} is
  contained in @{thm [source] Ev.intros}.  *}

declare Ev.intros [simp]

text{* A shorter proof: *}

lemma "n \<in> Ev \<Longrightarrow> n+n \<in> Ev"
  apply(erule Ev.inducts)
   apply(auto)
  done

text{*
  Nice example, but overkill: don't need assumption @{prop"n \<in> Ev"}
  because @{prop"n+n \<in> Ev"} is true for all @{text n}.

  However, here we really need the assumptions: *}

lemma "\<lbrakk> m \<in> Ev; n \<in> Ev \<rbrakk> \<Longrightarrow> m+n \<in> Ev"
  apply(erule Ev.inducts)
   apply(auto)
  done

text{* An inductive proof of @{prop"1 \<notin> Ev"}: *}

lemma "n \<in> Ev \<Longrightarrow> n \<noteq> 1"
  apply(erule Ev.inducts)
   apply(auto)
  done

text{* The general case: *}
lemma "n \<in> Ev \<Longrightarrow> \<not>(\<exists>k. n = 2*k+1)"
  apply(erule Ev.inducts)
   apply(simp)
  apply arith
  done


-- -------------------------------------------------------

subsection {* Cases and Induction in Isar *}

text {* Cases (rule inversion) in Isar *}

lemma "n \<in> Ev \<Longrightarrow> n = 0 \<or> (\<exists>n' \<in> Ev. n = Suc (Suc n'))"
proof -
  assume "n \<in> Ev"
  from this show "n = 0 \<or> (\<exists>n' \<in> Ev. n = Suc (Suc n'))"
  proof cases
    assume "n = 0"
    then show ?thesis ..
  next
    fix n' 
    assume "n = Suc (Suc n')" and "n' \<in> Ev"
    then show ?thesis by blast
  qed
qed


lemma 
  assumes n: "n \<in> Ev" 
  shows "n = 0 \<or> (\<exists>n' \<in> Ev. n = Suc (Suc n'))" 
using n  -- "chain fact in prove mode"
proof cases
  case ZeroI
  then show ?thesis ..
next
  case (Add2I m)
  then show ?thesis by blast
qed
-- "Demo what happens if Add2I is used instead of (Add2I m)"

text {* Rule induction in Isar *}

lemma "n \<in> Ev \<Longrightarrow> \<exists>k. n = 2*k"
proof (induct rule: Ev.induct)
  case ZeroI then show ?case by simp
next
  case (Add2I m) then show ?case by arith
qed


lemma assumes n: "n \<in> Ev" shows "\<exists>k. n = 2*k"
using n proof induct
  case ZeroI then show ?case by simp
next
  case (Add2I m) then show ?case by arith
qed


lemma assumes n: "n \<in> Ev" shows "\<exists>k. n = 2*k"
using n proof induct
  case ZeroI then show ?case by simp
next
  case (Add2I m)
  then obtain k where "m = 2*k" by blast
  then have "Suc (Suc m) = 2*(k+1)" by simp
  then show "\<exists>k. Suc (Suc m) = 2*k" ..
qed

-- -------------------------------------------------------

subsection{* Proofs about finite sets *}

text{*
  Above we declared @{text Ev.intros} as simplification rules.
  Now we declare @{text Fin.intros} as introduction rules (via
  attribute ``intro''). Then fast and blast use them automatically.*}

declare Fin.intros [intro]

lemma "\<lbrakk> A \<in> Fin; B \<in> Fin \<rbrakk> \<Longrightarrow> A \<union> B \<in> Fin"
  apply(erule Fin.inducts)
   apply simp
  apply simp
  apply blast
  done

lemma "\<lbrakk> A \<in> Fin; B \<subseteq> A \<rbrakk> \<Longrightarrow> B \<in> Fin"
  apply(erule Fin.inducts)

txt{* The base case looks funny: why is the premise not @{prop"B \<subseteq> {}"}?
Because @{prop"B \<subseteq> A"} was not part of the conclusion we prove.
Relief: pull @{prop"B \<subseteq> A"} into the conclusion with the help of @{text"\<longrightarrow>"}.
*}
oops

lemma "A \<in> Fin \<Longrightarrow> B \<subseteq> A \<longrightarrow> B \<in> Fin"
  apply(erule Fin.inducts)
   apply(simp)
   apply(fast)

txt{* We only know that @{term "B - {a} \<subseteq> A"}.
  Solution: strengthen the theorem: quantify @{term B}. *}
oops

lemma "A \<in> Fin \<Longrightarrow> \<forall>B. B \<subseteq> A \<longrightarrow> B \<in> Fin"
  apply(erule Fin.inducts)
   apply(simp)
   apply(rule Fin.emptyI)
  apply(rule allI)
  apply(rule impI)
  apply(simp add:subset_insert_iff split:split_if_asm)
  apply(drule_tac A = B in insert_Diff)
  apply(erule subst)
  apply(blast)
  done


text {* Isar version *}

lemma "\<lbrakk> A \<in> Fin; B \<subseteq> A \<rbrakk> \<Longrightarrow> B \<in> Fin"
proof -
  assume "A \<in> Fin" and "B \<subseteq> A"
  then show ?thesis
  -- "chained facts: first selects induction rule,
    remaining ones are pushed into induction statement"
  proof (induct arbitrary: B)
    case emptyI
    then show ?case by (simp) (rule Fin.emptyI)
  next
    case (insertI A a)
    then have "B - {a} \<subseteq> A"
      by (simp add: subset_insert_iff split: split_if_asm)
    with insertI have Ba: "B - {a} \<in> Fin" by blast
    show ?case
    proof (cases "a \<in> B")
      case True with Ba show ?thesis
	by (best dest: insert_Diff elim: subst)
    next
      case False with Ba show ?thesis by simp
    qed
  qed
qed


-- {* Structural induction *}

text {* Induction works for natural numbers as well:
  The cases are @{text 0} and @{text "Suc n"}.  *}


lemma "2 * (\<Sum>i<n+1. i) = n*(n+1::nat)"
  by (induct n, simp_all)


lemma "2 * (\<Sum>i<n+1. i) = n*(n+1::nat)" (is "?P n")
proof (induct n)
  show "?P 0" by simp
next
  fix n assume "?P n"
  then show "?P (Suc n)" by simp
qed

end
