theory Demo06
  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)"
  try0 (* try0 should be eliminated after success *)
  by metis

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 split: prod.splits dest: split_len)

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

lemma sorted_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: sorted_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)"
  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
  text \<open>Each sorry can be removed by a proof search via @{command try} or @{command sledgehammer}.\<close>
  assume "\<exists> q :: rat. q^2 = 2"
  then obtain q :: rat where "q^2 = 2" sorry
  obtain m n where "q = of_int m / of_int n"  "coprime m n" sorry
  then have "of_int m ^ 2 = (2::rat) * of_int n ^ 2" sorry
  then have "2 dvd m" sorry
  then obtain r where "m = 2*r" sorry
  then have "(2 :: rat) * of_int r ^ 2 = of_int n ^ 2" sorry
  then have "2 dvd n" sorry
  then show False sorry
qed

end