theory LiveDemo06
  imports 
    Main
    HOL.Rat (* import rational numbers *)
begin

section \<open>Methods\<close>

text \<open>Difference between Elimination and Destruction Rules\<close>

thm conjE (* elimination *)
  conjunct1 (* destruction *)


lemma "\<forall>x. \<exists>y. P x y \<Longrightarrow> \<exists>f. \<forall>x. P x (f x)"
  by meson (* try0 should be eliminated after success *)

text \<open>Split-Modifier\<close>

lemma "sorted (case g x of [] \<Rightarrow> [5] | y # ys \<Rightarrow> ys @ zs @ [y])" 
  apply (simp only: split: list.splits)
  oops


text \<open>Modifiers-Demo: Mergesort\<close>

fun split_list :: "'a list \<Rightarrow> 'a list \<times> 'a list" where
  "split_list (x # y # xs) = (case split_list xs of (one,two) \<Rightarrow> (x # one, y # two))" 
| "split_list xs = (xs,[])" 

fun merge :: "'a :: linorder list \<Rightarrow> 'a list \<Rightarrow> 'a list" where
  "merge [] ys = ys" 
| "merge xs [] = xs" 
| "merge (x # xs) (y # ys) = (if x \<le> y then x # merge xs (y # ys) else y # merge (x # xs) ys)" 

function (sequential) msort :: "'a :: linorder list \<Rightarrow> 'a list" where
  "msort [] = []" 
| "msort [x] = [x]"
| "msort xs = (case split_list xs of (one,two) \<Rightarrow>
     merge (msort one) (msort two))" 
  by pat_completeness auto 

lemma split_len: "split_list xs = (one,two) \<Longrightarrow> max (length one) (length two) \<le> length xs" 
  by (induction xs arbitrary: one two rule: split_list.induct) (auto split: prod.splits)

termination by (relation "measure length") (auto dest: split_len split: prod.splits)

lemma set_merge[simp]: "set (merge xs ys) = set xs \<union> set ys" 
  by (induction xs ys rule: merge.induct) auto

lemma merge: "sorted xs \<Longrightarrow> sorted ys \<Longrightarrow> sorted (merge xs ys)" 
  by (induction xs ys rule: merge.induct) auto

lemma merge_sort: "sorted (msort xs)" 
  by (induction xs rule: msort.induct) (auto split: prod.splits intro: merge)


text \<open>Sequential composition\<close>

lemma "\<forall> x :: nat. x < 30 \<longrightarrow> (\<exists> y z. y + x \<le> z \<and> odd y \<and> odd z)"
  apply (intro allI impI)
  thm exI
  apply (rule exI[of _ 5])
  apply (rule exI[of _ 35])
  by auto

lemma "\<forall> x :: nat. x < 30 \<longrightarrow> (\<exists> y z. y + x \<le> z \<and> odd y \<and> odd z)"
  by (intro allI impI, rule exI[of _ 5], intro exI[of _ 35], auto)

lemma "True \<and> True" 
  apply (rule conjI; (rule TrueI; rule TrueI))
  oops

lemma "True \<and> True" 
  apply (rule conjI, rule TrueI, rule TrueI)
  oops

lemma "True \<and> True" 
  apply (rule conjI, rule TrueI)
  oops

lemma "True \<and> True"
  apply (rule conjI; rule TrueI)
  oops


section \<open>Sledgehammer\<close>

lemma sqrt_2_irrational: "\<not> (\<exists> q :: rat. q^2 = 2)"
proof
  assume "\<exists> q :: rat. q^2 = 2"
  then obtain q :: rat where "q^2 = 2" by blast
  obtain m n where "q = of_int m / of_int n"  "coprime m n"
    by (metis Fract_of_int_quotient Rat_cases)
  then have "of_int m ^ 2 = (2::rat) * of_int n ^ 2"
    by (metis \<open>q\<^sup>2 = 2\<close> divide_eq_eq_numeral(1) power_divide zero_neq_numeral)
  then have "2 dvd m"
    by (metis (mono_tags, lifting) even_mult_iff even_numeral of_int_eq_iff of_int_mult of_int_numeral power2_eq_square)
  then obtain r where "m = 2*r" 
    by blast
  then have "(2 :: rat) * of_int r ^ 2 = of_int n ^ 2"
    using \<open>(rat_of_int m)\<^sup>2 = 2 * (rat_of_int n)\<^sup>2\<close> by auto
  then have "2 dvd n" 
    by (metis even_mult_iff even_numeral of_int_eq_of_int_power_cancel_iff of_int_mult of_int_numeral power2_eq_square)
  then show False
    using \<open>coprime m n\<close> \<open>even m\<close> by fastforce
qed

end 