src/HOL/ex/Primrec.thy
author dixon
Wed, 02 Mar 2005 10:33:10 +0100
changeset 15560 c862d556fb18
parent 11704 3c50a2cd6f00
child 16417 9bc16273c2d4
permissions -rw-r--r--
lucas - fixed bug with name capture variables bound outside redex could (previously)conflict with scheme variables that occur in the conditions of an equation, and which were renamed to avoid conflict with another instantiation. This has now been fixed.

(*  Title:      HOL/ex/Primrec.thy
    ID:         $Id$
    Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
    Copyright   1997  University of Cambridge

Primitive Recursive Functions.  Demonstrates recursive definitions,
the TFL package.
*)

header {* Primitive Recursive Functions *}

theory Primrec = Main:

text {*
  Proof adopted from

  Nora Szasz, A Machine Checked Proof that Ackermann's Function is not
  Primitive Recursive, In: Huet \& Plotkin, eds., Logical Environments
  (CUP, 1993), 317-338.

  See also E. Mendelson, Introduction to Mathematical Logic.  (Van
  Nostrand, 1964), page 250, exercise 11.
  \medskip
*}

consts ack :: "nat * nat => nat"
recdef ack  "less_than <*lex*> less_than"
  "ack (0, n) =  Suc n"
  "ack (Suc m, 0) = ack (m, 1)"
  "ack (Suc m, Suc n) = ack (m, ack (Suc m, n))"

consts list_add :: "nat list => nat"
primrec
  "list_add [] = 0"
  "list_add (m # ms) = m + list_add ms"

consts zeroHd :: "nat list => nat"
primrec
  "zeroHd [] = 0"
  "zeroHd (m # ms) = m"


text {* The set of primitive recursive functions of type @{typ "nat list => nat"}. *}

constdefs
  SC :: "nat list => nat"
  "SC l == Suc (zeroHd l)"

  CONST :: "nat => nat list => nat"
  "CONST k l == k"

  PROJ :: "nat => nat list => nat"
  "PROJ i l == zeroHd (drop i l)"

  COMP :: "(nat list => nat) => (nat list => nat) list => nat list => nat"
  "COMP g fs l == g (map (\<lambda>f. f l) fs)"

  PREC :: "(nat list => nat) => (nat list => nat) => nat list => nat"
  "PREC f g l ==
    case l of
      [] => 0
    | x # l' => nat_rec (f l') (\<lambda>y r. g (r # y # l')) x"
  -- {* Note that @{term g} is applied first to @{term "PREC f g y"} and then to @{term y}! *}

consts PRIMREC :: "(nat list => nat) set"
inductive PRIMREC
  intros
    SC: "SC \<in> PRIMREC"
    CONST: "CONST k \<in> PRIMREC"
    PROJ: "PROJ i \<in> PRIMREC"
    COMP: "g \<in> PRIMREC ==> fs \<in> lists PRIMREC ==> COMP g fs \<in> PRIMREC"
    PREC: "f \<in> PRIMREC ==> g \<in> PRIMREC ==> PREC f g \<in> PRIMREC"


text {* Useful special cases of evaluation *}

lemma SC [simp]: "SC (x # l) = Suc x"
  apply (simp add: SC_def)
  done

lemma CONST [simp]: "CONST k l = k"
  apply (simp add: CONST_def)
  done

lemma PROJ_0 [simp]: "PROJ 0 (x # l) = x"
  apply (simp add: PROJ_def)
  done

lemma COMP_1 [simp]: "COMP g [f] l = g [f l]"
  apply (simp add: COMP_def)
  done

lemma PREC_0 [simp]: "PREC f g (0 # l) = f l"
  apply (simp add: PREC_def)
  done

lemma PREC_Suc [simp]: "PREC f g (Suc x # l) = g (PREC f g (x # l) # x # l)"
  apply (simp add: PREC_def)
  done


text {* PROPERTY A 4 *}

lemma less_ack2 [iff]: "j < ack (i, j)"
  apply (induct i j rule: ack.induct)
    apply simp_all
  done


text {* PROPERTY A 5-, the single-step lemma *}

lemma ack_less_ack_Suc2 [iff]: "ack(i, j) < ack (i, Suc j)"
  apply (induct i j rule: ack.induct)
    apply simp_all
  done


text {* PROPERTY A 5, monotonicity for @{text "<"} *}

lemma ack_less_mono2: "j < k ==> ack (i, j) < ack (i, k)"
  apply (induct i k rule: ack.induct)
    apply simp_all
  apply (blast elim!: less_SucE intro: less_trans)
  done


text {* PROPERTY A 5', monotonicity for @{text \<le>} *}

lemma ack_le_mono2: "j \<le> k ==> ack (i, j) \<le> ack (i, k)"
  apply (simp add: order_le_less)
  apply (blast intro: ack_less_mono2)
  done


text {* PROPERTY A 6 *}

lemma ack2_le_ack1 [iff]: "ack (i, Suc j) \<le> ack (Suc i, j)"
  apply (induct j)
   apply simp_all
  apply (blast intro: ack_le_mono2 less_ack2 [THEN Suc_leI] le_trans)
  done


text {* PROPERTY A 7-, the single-step lemma *}

lemma ack_less_ack_Suc1 [iff]: "ack (i, j) < ack (Suc i, j)"
  apply (blast intro: ack_less_mono2 less_le_trans)
  done


text {* PROPERTY A 4'? Extra lemma needed for @{term CONST} case, constant functions *}

lemma less_ack1 [iff]: "i < ack (i, j)"
  apply (induct i)
   apply simp_all
  apply (blast intro: Suc_leI le_less_trans)
  done


text {* PROPERTY A 8 *}

lemma ack_1 [simp]: "ack (Suc 0, j) = j + 2"
  apply (induct j)
   apply simp_all
  done


text {* PROPERTY A 9.  The unary @{text 1} and @{text 2} in @{term
  ack} is essential for the rewriting. *}

lemma ack_2 [simp]: "ack (Suc (Suc 0), j) = 2 * j + 3"
  apply (induct j)
   apply simp_all
  done


text {* PROPERTY A 7, monotonicity for @{text "<"} [not clear why
  @{thm [source] ack_1} is now needed first!] *}

lemma ack_less_mono1_aux: "ack (i, k) < ack (Suc (i +i'), k)"
  apply (induct i k rule: ack.induct)
    apply simp_all
   prefer 2
   apply (blast intro: less_trans ack_less_mono2)
  apply (induct_tac i' n rule: ack.induct)
    apply simp_all
  apply (blast intro: Suc_leI [THEN le_less_trans] ack_less_mono2)
  done

lemma ack_less_mono1: "i < j ==> ack (i, k) < ack (j, k)"
  apply (drule less_imp_Suc_add)
  apply (blast intro!: ack_less_mono1_aux)
  done


text {* PROPERTY A 7', monotonicity for @{text "\<le>"} *}

lemma ack_le_mono1: "i \<le> j ==> ack (i, k) \<le> ack (j, k)"
  apply (simp add: order_le_less)
  apply (blast intro: ack_less_mono1)
  done


text {* PROPERTY A 10 *}

lemma ack_nest_bound: "ack(i1, ack (i2, j)) < ack (2 + (i1 + i2), j)"
  apply (simp add: numerals)
  apply (rule ack2_le_ack1 [THEN [2] less_le_trans])
  apply simp
  apply (rule le_add1 [THEN ack_le_mono1, THEN le_less_trans])
  apply (rule ack_less_mono1 [THEN ack_less_mono2])
  apply (simp add: le_imp_less_Suc le_add2)
  done


text {* PROPERTY A 11 *}

lemma ack_add_bound: "ack (i1, j) + ack (i2, j) < ack (4 + (i1 + i2), j)"
  apply (rule_tac j = "ack (Suc (Suc 0), ack (i1 + i2, j))" in less_trans)
   prefer 2
   apply (rule ack_nest_bound [THEN less_le_trans])
   apply (simp add: Suc3_eq_add_3)
  apply simp
  apply (cut_tac i = i1 and m1 = i2 and k = j in le_add1 [THEN ack_le_mono1])
  apply (cut_tac i = "i2" and m1 = i1 and k = j in le_add2 [THEN ack_le_mono1])
  apply auto
  done


text {* PROPERTY A 12.  Article uses existential quantifier but the ALF proof
  used @{text "k + 4"}.  Quantified version must be nested @{text
  "\<exists>k'. \<forall>i j. ..."} *}

lemma ack_add_bound2: "i < ack (k, j) ==> i + j < ack (4 + k, j)"
  apply (rule_tac j = "ack (k, j) + ack (0, j)" in less_trans)
   prefer 2
   apply (rule ack_add_bound [THEN less_le_trans])
   apply simp
  apply (rule add_less_mono less_ack2 | assumption)+
  done



text {* Inductive definition of the @{term PR} functions *}

text {* MAIN RESULT *}

lemma SC_case: "SC l < ack (1, list_add l)"
  apply (unfold SC_def)
  apply (induct l)
  apply (simp_all add: le_add1 le_imp_less_Suc)
  done

lemma CONST_case: "CONST k l < ack (k, list_add l)"
  apply simp
  done

lemma PROJ_case [rule_format]: "\<forall>i. PROJ i l < ack (0, list_add l)"
  apply (simp add: PROJ_def)
  apply (induct l)
   apply simp_all
  apply (rule allI)
  apply (case_tac i)
  apply (simp (no_asm_simp) add: le_add1 le_imp_less_Suc)
  apply (simp (no_asm_simp))
  apply (blast intro: less_le_trans intro!: le_add2)
  done


text {* @{term COMP} case *}

lemma COMP_map_aux: "fs \<in> lists (PRIMREC \<inter> {f. \<exists>kf. \<forall>l. f l < ack (kf, list_add l)})
  ==> \<exists>k. \<forall>l. list_add (map (\<lambda>f. f l) fs) < ack (k, list_add l)"
  apply (erule lists.induct)
  apply (rule_tac x = 0 in exI)
   apply simp
  apply safe
  apply simp
  apply (rule exI)
  apply (blast intro: add_less_mono ack_add_bound less_trans)
  done

lemma COMP_case:
  "\<forall>l. g l < ack (kg, list_add l) ==>
  fs \<in> lists(PRIMREC Int {f. \<exists>kf. \<forall>l. f l < ack(kf, list_add l)})
  ==> \<exists>k. \<forall>l. COMP g fs  l < ack(k, list_add l)"
  apply (unfold COMP_def)
  apply (frule Int_lower1 [THEN lists_mono, THEN subsetD])
  apply (erule COMP_map_aux [THEN exE])
  apply (rule exI)
  apply (rule allI)
  apply (drule spec)+
  apply (erule less_trans)
  apply (blast intro: ack_less_mono2 ack_nest_bound less_trans)
  done


text {* @{term PREC} case *}

lemma PREC_case_aux:
  "\<forall>l. f l + list_add l < ack (kf, list_add l) ==>
    \<forall>l. g l + list_add l < ack (kg, list_add l) ==>
    PREC f g l + list_add l < ack (Suc (kf + kg), list_add l)"
  apply (unfold PREC_def)
  apply (case_tac l)
   apply simp_all
   apply (blast intro: less_trans)
  apply (erule ssubst) -- {* get rid of the needless assumption *}
  apply (induct_tac a)
   apply simp_all
   txt {* base case *}
   apply (blast intro: le_add1 [THEN le_imp_less_Suc, THEN ack_less_mono1] less_trans)
  txt {* induction step *}
  apply (rule Suc_leI [THEN le_less_trans])
   apply (rule le_refl [THEN add_le_mono, THEN le_less_trans])
    prefer 2
    apply (erule spec)
   apply (simp add: le_add2)
  txt {* final part of the simplification *}
  apply simp
  apply (rule le_add2 [THEN ack_le_mono1, THEN le_less_trans])
  apply (erule ack_less_mono2)
  done

lemma PREC_case:
  "\<forall>l. f l < ack (kf, list_add l) ==>
    \<forall>l. g l < ack (kg, list_add l) ==>
    \<exists>k. \<forall>l. PREC f g l < ack (k, list_add l)"
  apply (rule exI)
  apply (rule allI)
  apply (rule le_less_trans [OF le_add1 PREC_case_aux])
   apply (blast intro: ack_add_bound2)+
  done

lemma ack_bounds_PRIMREC: "f \<in> PRIMREC ==> \<exists>k. \<forall>l. f l < ack (k, list_add l)"
  apply (erule PRIMREC.induct)
      apply (blast intro: SC_case CONST_case PROJ_case COMP_case PREC_case)+
  done

lemma ack_not_PRIMREC: "(\<lambda>l. case l of [] => 0 | x # l' => ack (x, x)) \<notin> PRIMREC"
  apply (rule notI)
  apply (erule ack_bounds_PRIMREC [THEN exE])
  apply (rule less_irrefl)
  apply (drule_tac x = "[x]" in spec)
  apply simp
  done

end