src/HOL/Examples/Ackermann.thy
author paulson <lp15@cam.ac.uk>
Tue, 09 Jun 2020 12:13:15 +0100
changeset 71930 35a2ac83a262
child 72029 83456d9f0ed5
permissions -rw-r--r--
New Ackermann development
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
71930
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     1
section \<open>A Tail-Recursive, Stack-Based Ackermann's Function\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     2
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     3
theory Ackermann imports Main
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     4
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     5
begin
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     6
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     7
text\<open>This theory investigates a stack-based implementation of Ackermann's function.
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     8
Let's recall the traditional definition,
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
     9
as modified by R{\'o}zsa P\'eter and Raphael Robinson.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    10
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    11
fun ack :: "[nat,nat] \<Rightarrow> nat" where
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    12
  "ack 0 n             = Suc n"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    13
| "ack (Suc m) 0       = ack m 1"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    14
| "ack (Suc m) (Suc n) = ack m (ack (Suc m) n)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    15
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    16
text\<open>Here is the stack-based version, which uses lists.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    17
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    18
function (domintros) ackloop :: "nat list \<Rightarrow> nat" where
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    19
  "ackloop (n # 0 # l)         = ackloop (Suc n # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    20
| "ackloop (0 # Suc m # l)     = ackloop (1 # m # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    21
| "ackloop (Suc n # Suc m # l) = ackloop (n # Suc m # m # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    22
| "ackloop [m] = m"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    23
| "ackloop [] =  0"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    24
  by pat_completeness auto
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    25
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    26
text\<open>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    27
The key task is to prove termination. In the first recursive call, the head of the list gets bigger
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    28
while the list gets shorter, suggesting that the length of the list should be the primary
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    29
termination criterion. But in the third recursive call, the list gets longer. The idea of trying
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    30
a multiset-based termination argument is frustrated by the second recursive call when m = 0:
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    31
the list elements are simply permuted.
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    32
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    33
Fortunately, the function definition package allows us to define a function and only later identify its domain of termination.
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    34
Instead, it makes all the recursion equations conditional on satisfying
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    35
the function's domain predicate. Here we shall eventually be able
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    36
to show that the predicate is always satisfied.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    37
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    38
text\<open>@{thm [display] ackloop.domintros[no_vars]}\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    39
declare ackloop.domintros [simp]
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    40
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    41
text \<open>Termination is trivial if the length of the list is less then two.
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    42
The following lemma is the key to proving termination for longer lists.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    43
lemma "\<And>n l. ackloop_dom (ack m n # l) \<Longrightarrow> ackloop_dom (n # m # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    44
proof (induction m)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    45
  case 0
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    46
  then show ?case
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    47
    by auto
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    48
next
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    49
  case (Suc m)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    50
  note IH = Suc
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    51
  have "\<And>l. ackloop_dom (ack (Suc m) n # l) \<Longrightarrow> ackloop_dom (n # Suc m # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    52
  proof (induction n)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    53
    case 0
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    54
    then show ?case
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    55
      by (simp add: IH)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    56
  next
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    57
    case (Suc n)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    58
    then show ?case
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    59
      by (auto simp: IH)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    60
  qed
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    61
  then show ?case
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    62
    using Suc.prems by blast
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    63
qed
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    64
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    65
text \<open>The proof above (which actually is unused) can be expressed concisely as follows.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    66
lemma ackloop_dom_longer:
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    67
  "ackloop_dom (ack m n # l) \<Longrightarrow> ackloop_dom (n # m # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    68
  by (induction m n arbitrary: l rule: ack.induct) auto
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    69
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    70
lemma "ackloop_dom (ack m n # l) \<Longrightarrow> ackloop_dom (n # m # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    71
  by (induction m n arbitrary: l rule: ack.induct) auto
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    72
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    73
text\<open>This function codifies what @{term ackloop} is designed to do.
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    74
Proving the two functions equivalent also shows that @{term ackloop} can be used
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    75
to compute Ackermann's function.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    76
fun acklist :: "nat list \<Rightarrow> nat" where
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    77
  "acklist (n#m#l) = acklist (ack m n # l)"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    78
| "acklist [m] = m"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    79
| "acklist [] =  0"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    80
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    81
text\<open>The induction rule for @{term acklist} is @{thm [display] acklist.induct[no_vars]}.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    82
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    83
lemma ackloop_dom: "ackloop_dom l"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    84
  by (induction l rule: acklist.induct) (auto simp: ackloop_dom_longer)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    85
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    86
termination ackloop
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    87
  by (simp add: ackloop_dom)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    88
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    89
text\<open>This result is trivial even by inspection of the function definitions
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    90
(which faithfully follow the definition of Ackermann's function).
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    91
All that we needed was termination.\<close>
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    92
lemma ackloop_acklist: "ackloop l = acklist l"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    93
  by (induction l rule: ackloop.induct) auto
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    94
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    95
theorem ack: "ack m n = ackloop [n,m]"
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    96
  by (simp add: ackloop_acklist)
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    97
35a2ac83a262 New Ackermann development
paulson <lp15@cam.ac.uk>
parents:
diff changeset
    98
end