# HG changeset patch # User paulson # Date 1666014789 -3600 # Node ID f89f4aab1cc445aa39a7dcf09a1a08d3df7a0f60 # Parent 73b120e0dbfea3fb804fd5003e93f4c8fed09ced# Parent 8d2bf9ce53021f4f44c93ddf75e69c64f4a02de1 merged diff -r 73b120e0dbfe -r f89f4aab1cc4 src/HOL/Examples/Ackermann.thy --- a/src/HOL/Examples/Ackermann.thy Mon Oct 17 13:04:00 2022 +0200 +++ b/src/HOL/Examples/Ackermann.thy Mon Oct 17 14:53:09 2022 +0100 @@ -4,7 +4,7 @@ section \A Tail-Recursive, Stack-Based Ackermann's Function\ -theory Ackermann imports Main +theory Ackermann imports "HOL-Library.Multiset_Order" "HOL-Library.Product_Lexorder" begin @@ -17,7 +17,9 @@ | "ack (Suc m) 0 = ack m 1" | "ack (Suc m) (Suc n) = ack m (ack (Suc m) n)" -text\Here is the stack-based version, which uses lists.\ +subsection \Example of proving termination by reasoning about the domain\ + +text\The stack-based version uses lists.\ function (domintros) ackloop :: "nat list \ nat" where "ackloop (n # 0 # l) = ackloop (Suc n # l)" @@ -86,4 +88,53 @@ theorem ack: "ack m n = ackloop [n,m]" by (simp add: ackloop_acklist) +subsection \Example of proving termination using a multiset ordering\ + +text \This termination proof uses the argument from +Nachum Dershowitz and Zohar Manna. Proving termination with multiset orderings. +Communications of the ACM 22 (8) 1979, 465–476.\ + +text\Setting up the termination proof. Note that Dershowitz had @{term z} as a global variable. +The top two stack elements are treated differently from the rest.\ + +fun ack_mset :: "nat list \ (nat\nat) multiset" where + "ack_mset [] = {#}" +| "ack_mset [x] = {#}" +| "ack_mset (z#y#l) = mset ((y,z) # map (\x. (Suc x, 0)) l)" + +lemma base: "ack_mset (Suc n # l) < add_mset (0,n) {# (Suc x, 0). x \# mset l #}" +proof (cases l) + case (Cons m list) + have "{#(m, Suc n)#} < {#(Suc m, 0)#}" + by auto + also have "\ \ {#(Suc m, 0), (0,n)#}" + by auto + finally show ?thesis + by (simp add: Cons) +qed auto + +text\The stack-based version again. We need a fresh copy because + we've already proved the termination of @{term ackloop}.\ + +function Ackloop :: "nat list \ nat" where + "Ackloop (n # 0 # l) = Ackloop (Suc n # l)" +| "Ackloop (0 # Suc m # l) = Ackloop (1 # m # l)" +| "Ackloop (Suc n # Suc m # l) = Ackloop (n # Suc m # m # l)" +| "Ackloop [m] = m" +| "Ackloop [] = 0" + by pat_completeness auto + + +text \In each recursive call, the function @{term ack_mset} decreases according to the multiset +ordering.\ +termination + by (relation "inv_image {(x,y). xAnother shortcut compared with before: equivalence follows directly from this lemma.\ +lemma Ackloop_ack: "Ackloop (n # m # l) = Ackloop (ack m n # l)" + by (induction m n arbitrary: l rule: ack.induct) auto + +theorem "ack m n = Ackloop [n,m]" + by (simp add: Ackloop_ack) + end