(* author: wzh*)

theory Exercise2_1
  imports Main

begin
(* Exer 2.1 *)
value "1 + (2 :: nat)"
value "1 + (2 :: int)"
value "1 - (2 :: nat)"
value "1 - (2 :: int)"

(* Exer 2.2 *)
fun add :: "nat \<Rightarrow> nat \<Rightarrow> nat" where
"add 0 n = n" |
"add (Suc m) n = Suc(add m n)"

theorem add_assoc [simp]: "add (add x y) z = add x (add y z)"
  apply(induction x)
   apply(auto)
  done

lemma add_zero [simp]:  "add x 0 = x"
  apply(induction x)
   apply(auto)
  done

lemma add_suc1 [simp]: "add x (Suc(y)) = Suc(add x y) "
  apply(induction x)
  apply(auto)
  done

lemma add_suc2 [simp]: "add x (Suc(y)) = Suc(add y x) "
  apply(induction x)
  apply(auto)
  done

theorem add_commu [simp]: "add x y = add y x"
  apply(induction y)
   apply(auto)
  done

fun double :: "nat \<Rightarrow> nat" where
"double x = x*2"

theorem dou: "double x = add x x"
  apply(induction x)
   apply(auto)
  done

(* Exer 2.3 *)
fun count :: "'a \<Rightarrow> 'a list \<Rightarrow> nat" where
"count x Nil = 0" |
"count x xs = (if x = (hd xs) then 1 + count x (tl xs) else count x (tl xs))"

theorem count_len: "count x xs \<le> length xs"
apply(induction xs)
  apply(auto)
  done

(* Exer 2.4 *)
fun snoc2 :: "'a list \<Rightarrow> 'a \<Rightarrow> 'a list" where
"snoc2 [] x = [x]" |
"snoc2 (x # xs) ys = (x # (snoc2 xs ys))"

fun reverse2 :: "'a list \<Rightarrow> 'a list" where
"reverse2 [] = []" |
"reverse2 (x#xs) = snoc2 (reverse2(xs)) x"

theorem [simp]: "reverse2 (reverse2 xs) = xs"
  apply(induction xs)
  apply(auto)
  done

(* Exer 2.5 *)
fun sum_upto :: "nat \<Rightarrow> nat" where
"sum_upto 0 = 0" |
"sum_upto x = x + sum_upto (x-1)"

theorem sum: "sum_upto n*2 = n*(n+1)"
  apply(induction n)
   apply(auto)
  done

end


(*  Title:      ZF/ex/NatSum.thy
    Author:     Tobias Nipkow & Lawrence C Paulson

A summation operator. sum(f,n+1) is the sum of all f(i), i=0...n.

Note: n is a natural number but the sum is an integer,
                            and f maps integers to integers

Summing natural numbers, squares, cubes, etc.

Originally demonstrated permutative rewriting, but add_ac is no longer needed
  thanks to new simprocs.

Thanks to Sloane's On-Line Encyclopedia of Integer Sequences,
  http://www.research.att.com/\<not>njas/sequences/
*)

theory NatSum imports ZF begin

consts sum :: "[i\<Rightarrow>i, i] \<Rightarrow> i"
primrec
  "sum (f,0) = #0"
  "sum (f, succ(n)) = f($#n) $+ sum(f,n)"

declare zadd_zmult_distrib [simp]  zadd_zmult_distrib2 [simp]
declare zdiff_zmult_distrib [simp] zdiff_zmult_distrib2 [simp]

(*The sum of the first n odd numbers equals n squared.*)
lemma sum_of_odds: "n \<in> nat \<Longrightarrow> sum (\<lambda>i. i $+ i $+ #1, n) = $#n $* $#n"
by (induct_tac "n", auto)

(*The sum of the first n odd squares*)
lemma sum_of_odd_squares:
     "n \<in> nat \<Longrightarrow> #3 $* sum (\<lambda>i. (i $+ i $+ #1) $* (i $+ i $+ #1), n) =
      $#n $* (#4 $* $#n $* $#n $- #1)"
by (induct_tac "n", auto)

(*The sum of the first n odd cubes*)
lemma sum_of_odd_cubes:
     "n \<in> nat
      \<Longrightarrow> sum (\<lambda>i. (i $+ i $+ #1) $* (i $+ i $+ #1) $* (i $+ i $+ #1), n) =
          $#n $* $#n $* (#2 $* $#n $* $#n $- #1)"
by (induct_tac "n", auto)

(*The sum of the first n positive integers equals n(n+1)/2.*)
lemma sum_of_naturals:
     "n \<in> nat \<Longrightarrow> #2 $* sum(\<lambda>i. i, succ(n)) = $#n $* $#succ(n)"
by (induct_tac "n", auto)

lemma sum_of_squares:
     "n \<in> nat \<Longrightarrow> #6 $* sum (\<lambda>i. i$*i, succ(n)) =
                  $#n $* ($#n $+ #1) $* (#2 $* $#n $+ #1)"
by (induct_tac "n", auto)

lemma sum_of_cubes:
     "n \<in> nat \<Longrightarrow> #4 $* sum (\<lambda>i. i$*i$*i, succ(n)) =
                  $#n $* $#n $* ($#n $+ #1) $* ($#n $+ #1)"
by (induct_tac "n", auto)

(** Sum of fourth powers **)

lemma sum_of_fourth_powers:
     "n \<in> nat \<Longrightarrow> #30 $* sum (\<lambda>i. i$*i$*i$*i, succ(n)) =
                    $#n $* ($#n $+ #1) $* (#2 $* $#n $+ #1) $*
                    (#3 $* $#n $* $#n $+ #3 $* $#n $- #1)"
by (induct_tac "n", auto)

end