Diferencia entre revisiones de «Razonamiento por casos y por inducci¢n»
De Lógica matemática y fundamentos (2018-19)
Línea 1: | Línea 1: | ||
<source lang="isabelle"> | <source lang="isabelle"> | ||
− | chapter {* Tema | + | chapter {* Tema 7: Razonamiento por casos y por inducción *} |
− | theory | + | theory T7_Razonamiento_por_casos_y_por_induccion |
− | imports Main | + | imports Main HOL.Parity |
begin | begin | ||
− | text {* | + | text {* |
− | En este tema se | + | En este tema se amplían los métodos de demostración por casos y por |
− | + | inducción iniciados en el tema anterior. | |
− | + | *} | |
− | |||
− | |||
− | + | section {* Razonamiento por distinción de casos *} | |
− | + | subsection {* Distinción de casos booleanos *} | |
− | text {* | + | text {* |
− | Ejemplo | + | Ejemplo de demostración por distinción de casos booleanos: |
− | + | Demostrar "¬A ∨ A". | |
− | + | *} | |
− | |||
− | |||
− | + | ― ‹La demostración estructurada es› | |
− | " | + | lemma "¬A ∨ A" |
− | + | proof cases | |
− | + | assume "A" | |
− | + | then show "¬A ∨ A" .. | |
+ | next | ||
+ | assume "¬A" | ||
+ | then show "¬A ∨ A" .. | ||
+ | qed | ||
− | text {* | + | text {* |
− | + | Comentarios de la demostración anterior: | |
− | + | · "proof cases" indica que el método de demostración será por | |
− | + | distinción de casos. | |
+ | · Se generan 2 casos: | ||
+ | 1. ?P ⟹ ¬A ∨ A | ||
+ | 2. ¬?P ⟹ ¬A ∨ A | ||
+ | donde ?P es una variable sobre las fórmulas. | ||
+ | · (assume "A") indica que se está usando "A" en lugar de la variable | ||
+ | ?P. | ||
+ | · "then" indica usando la fórmula anterior. | ||
+ | · ".." indica usando la regla lógica necesaria (las reglas lógicas se | ||
+ | estudiarán en los siguientes temas). | ||
+ | · "next" indica el siguiente caso (se puede observar cómo ha | ||
+ | sustituido ¬?P por ¬A. | ||
+ | *} | ||
− | lemma " | + | ― ‹La demostración automática es› |
− | by | + | lemma "¬A ∨ A" |
+ | by auto | ||
− | text {* | + | text {* |
− | Ejemplo | + | Ejemplo de demostración por distinción de casos booleanos con nombres: |
− | + | Demostrar "¬A ∨ A". | |
− | + | *} | |
− | |||
− | |||
− | |||
− | + | ― ‹La demostración estructurada es› | |
− | " | + | lemma "¬A ∨ A" |
− | + | proof (cases "A") | |
− | + | case True | |
+ | then show "¬A ∨ A" .. | ||
+ | next | ||
+ | case False | ||
+ | thus "¬A ∨ A" .. | ||
+ | qed | ||
text {* | text {* | ||
− | + | Comentarios sobre la demostración anterior: | |
− | + | · (cases "A") indica que la demostración se hará por casos según los | |
− | · | + | distintos valores de "A". |
− | + | · Como "A" es una fórmula, sus posibles valores son verdadero o falso. | |
− | + | · "case True" indica que se está suponiendo que A es verdadera. Es | |
− | + | equivalente a "assume A". | |
+ | · "case False" indica que se está suponiendo que A es falsa. Es | ||
+ | equivalente a "assume ¬A". | ||
+ | · En general, | ||
+ | · el método (cases F) es una abreviatura de la aplicación de la regla | ||
+ | ⟦F ⟹ Q; ¬F ⟹ Q⟧ ⟹ Q | ||
+ | · La expresión "case True" es una abreviatura de F. | ||
+ | · La expresión "case False" es una abreviatura de ¬F. | ||
+ | · Ventajas de "cases" con nombre: | ||
+ | · reduce la escritura de la fórmula y | ||
+ | · es independiente del orden de los casos. | ||
*} | *} | ||
− | + | subsection {* Distinción de casos sobre otros tipos de datos *} | |
− | |||
− | |||
− | |||
− | + | text {* | |
− | + | Ejemplo de distinción de casos sobre listas: | |
− | + | Demostrar que la longitud del resto de una lista es la longitud de la | |
− | + | lista menos 1. | |
+ | *} | ||
− | + | ― ‹La demostración detallada es› | |
− | lemma " | + | lemma "length (tl xs) = length xs - 1" |
− | + | proof (cases xs) | |
− | + | assume "xs = []" | |
− | + | then show "length (tl xs) = length xs - 1" by simp | |
− | + | next | |
− | + | fix y ys | |
− | + | assume "xs = y#ys" | |
− | + | then show "length(tl xs) = length xs - 1" by simp | |
qed | qed | ||
text {* | text {* | ||
− | + | Comentarios sobre la demostración anterior: | |
− | · | + | · "(cases xs)" indica que la demostración se hará por casos sobre los |
− | + | posibles valores de xs. | |
− | + | · Como xs es una lista, sus posibles valores son la lista vacía ([]) o | |
− | + | una lista no vacía (de la forma (y#ys)). | |
− | + | · Se generan 2 casos: | |
− | + | 1. xs = [] ⟹ length (tl xs) = length xs - 1 | |
− | · | + | 2. ⋀a list. xs = a # list ⟹ length (tl xs) = length xs - 1 |
− | |||
− | |||
− | |||
− | |||
− | · | ||
− | |||
*} | *} | ||
− | + | ― ‹La demostración simplificada es› | |
− | lemma " | + | lemma "length (tl xs) = length xs - 1" |
− | + | proof (cases xs) | |
− | + | case Nil | |
− | + | then show ?thesis by simp | |
− | + | next | |
+ | case Cons | ||
+ | then show ?thesis by simp | ||
qed | qed | ||
text {* | text {* | ||
− | + | Comentarios sobre la dmostración anterior: | |
− | + | · "case Nil" es una abreviatura de | |
+ | "assume xs =[]". | ||
+ | · "case Cons" es una abreviatura de | ||
+ | "fix y ys assume xs = y#ys" | ||
+ | · ?thesis es una abreviatura de la conclusión del lema. | ||
*} | *} | ||
− | + | ― ‹La demostración automática es› | |
− | lemma " | + | lemma "length (tl xs) = length xs - 1" |
− | + | by auto | |
− | text {* | + | text {* |
− | + | En el siguiente ejemplo vamos a demostrar una propiedad de la función | |
− | + | drop que está definida en la teoría List de forma que (drop n xs) la | |
− | + | lista obtenida eliminando en xs} los n primeros elementos. Su | |
− | + | definición es la siguiente | |
− | + | drop_Nil: "drop n [] = []" | |
− | + | drop_Cons: "drop n (x#xs) = (case n of | |
− | + | 0 => x#xs | | |
− | + | Suc(m) => drop m xs)" | |
− | + | *} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | ( | ||
− | |||
− | |||
− | |||
text {* | text {* | ||
− | + | Ejemplo de análisis de casos: | |
− | + | Demostrar que el resultado de eliminar los n+1 primeros elementos de | |
− | + | xs es el mismo que eliminar los n primeros elementos del resto de xs. | |
− | |||
− | |||
*} | *} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ― ‹La demostración detallada es› | |
− | lemma " | + | lemma "drop (n + 1) xs = drop n (tl xs)" |
− | + | proof (cases xs) | |
− | + | case Nil | |
− | + | then show ?thesis by simp | |
− | + | next | |
− | + | case Cons | |
− | + | then show ?thesis by simp | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
qed | qed | ||
− | + | ― ‹La demostración automática es› | |
− | lemma " | + | lemma "drop (n + 1) xs = drop n (tl xs)" |
− | + | by (cases xs) auto | |
− | section {* | + | section {* Inducción matemática *} |
text {* | text {* | ||
− | [Principio de inducción | + | [Principio de inducción matemática] |
− | + | Para demostrar una propiedad P para todos los números naturales basta | |
− | + | probar que el 0 tiene la propiedad P y que si n tiene la propiedad P, | |
− | + | entonces n+1 también la tiene. | |
⟦P 0; ⋀n. P n ⟹ P (Suc n)⟧ ⟹ P m | ⟦P 0; ⋀n. P n ⟹ P (Suc n)⟧ ⟹ P m | ||
− | En Isabelle el principio de inducción | + | En Isabelle el principio de inducción matemática está formalizado en |
− | + | el teorema nat.induct y puede verse con | |
thm nat.induct | thm nat.induct | ||
*} | *} | ||
− | text {* | + | text {* |
− | Ejemplo | + | Ejemplo de demostración por inducción: Usaremos el principio de |
− | + | inducción matemática para demostrar que | |
− | + | 1 + 3 + ... + (2n-1) = n^2 | |
− | + | ||
− | + | Definición. [Suma de los primeros impares] | |
− | + | (suma_impares n) la suma de los n números impares. Por ejemplo, | |
+ | suma_impares 3 = 9 | ||
+ | *} | ||
− | fun | + | fun suma_impares :: "nat ⇒ nat" where |
− | " | + | "suma_impares 0 = 0" |
− | | " | + | | "suma_impares (Suc n) = (2*(Suc n) - 1) + suma_impares n" |
− | value " | + | value "suma_impares 3" |
− | text {* | + | text {* |
− | Ejemplo | + | Ejemplo de demostración por inducción matemática: |
− | + | Demostrar que la suma de los n primeros números impares es n^2. | |
− | + | *} | |
− | (* | + | ― ‹Demostración del lema anterior por inducción y razonamiento |
− | + | ecuacional› | |
− | + | lemma "suma_impares n = n * n" | |
− | + | proof (induct n) | |
− | + | show "suma_impares 0 = 0 * 0" by simp | |
+ | next | ||
+ | fix n assume HI: "suma_impares n = n * n" | ||
+ | have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n" | ||
+ | by simp | ||
+ | also have "… = (2 * (Suc n) - 1) + n * n" using HI by simp | ||
+ | also have "… = n * n + 2 * n + 1" by simp | ||
+ | finally show "suma_impares (Suc n) = (Suc n) * (Suc n)" by simp | ||
+ | qed | ||
− | + | ― ‹Demostración del lema anterior con patrones y razonamiento | |
− | lemma " | + | ecuacional› |
+ | lemma "suma_impares n = n * n" (is "?P n") | ||
proof (induct n) | proof (induct n) | ||
− | show " | + | show "?P 0" by simp |
− | next | + | next |
− | fix n | + | fix n |
− | assume HI: " | + | assume HI: "?P n" |
− | have " | + | have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n" |
by simp | by simp | ||
− | also have " | + | also have "… = (2 * (Suc n) - 1) + n * n" using HI by simp |
− | also have " | + | also have "… = n * n + 2 * n + 1" by simp |
− | finally show " | + | finally show "?P (Suc n)" by simp |
qed | qed | ||
text {* | text {* | ||
− | + | Comentario sobre la demostración anterior: | |
− | · | + | · Con la expresión |
− | + | "suma_impares n = n * n" (is "?P n") | |
− | + | se abrevia "suma_impares n = n * n" como "?P n". Por tanto, | |
− | + | "?P 0" es una abreviatura de "suma_impares 0 = 0 * 0" | |
− | + | "?P (Suc n)" es una abreviatura de "suma_impares (Suc n) = (Suc n) * (Suc n)" | |
− | + | · En general, cualquier fórmula seguida de (is patrón) equipara el | |
− | + | patrón con la fórmula. | |
− | |||
− | |||
− | |||
− | |||
− | · | ||
*} | *} | ||
− | + | ― ‹La demostración usando patrones es› | |
− | + | lemma "suma_impares n = n * n" (is "?P n") | |
− | + | proof (induct n) | |
+ | show "?P 0" by simp | ||
+ | next | ||
+ | fix n | ||
+ | assume "?P n" | ||
+ | then show "?P (Suc n)" by simp | ||
+ | qed | ||
+ | |||
+ | ― ‹La demostración automática es› | ||
+ | lemma "suma_impares n = n * n" | ||
+ | by (induct n) auto | ||
− | + | text {* | |
+ | Ejemplo de definición con existenciales. | ||
+ | Un número natural n es par si existe un natural m tal que n=m+m. | ||
+ | *} | ||
− | + | definition par :: "nat ⇒ bool" where | |
− | + | "par n ≡ ∃m. n=m+m" | |
− | |||
− | |||
− | |||
− | + | text {* | |
− | + | Ejemplo de inducción y existenciales: | |
− | + | Demostrar que para todo número natural n, se verifica que n*(n+1) par. | |
− | |||
− | |||
*} | *} | ||
− | + | ― ‹Demostración detallada por inducción› | |
− | + | lemma | |
− | + | fixes n :: "nat" | |
− | + | shows "par (n*(n+1))" | |
− | + | proof (induct n) | |
− | + | show "par (0*(0+1))" by (simp add: par_def) | |
− | + | next | |
+ | fix n | ||
+ | assume "par (n*(n+1))" | ||
+ | then have "∃m. n*(n+1) = m+m" by (simp add:par_def) | ||
+ | then obtain m where m: "n*(n+1) = m+m" .. | ||
+ | then have "(Suc n)*((Suc n)+1) = (m+n+1)+(m+n+1)" by auto | ||
+ | then have "∃m. (Suc n)*((Suc n)+1) = m+m" .. | ||
+ | then show "par ((Suc n)*((Suc n)+1))" by (simp add:par_def) | ||
+ | qed | ||
− | + | text {* | |
− | + | Comentarios sobre la demostración anterior: | |
− | + | · (fixes n :: "nat") es una abreviatura de "sea n un número natural". | |
+ | *} | ||
− | + | text {* | |
+ | En Isabelle puede demostrarse de manera más simple un lema equivalente | ||
+ | usando en lugar de la función "par" la función "even" definida en la | ||
+ | teoría Parity por | ||
+ | even x ⟷ x mod 2 = 0" | ||
+ | *} | ||
− | + | lemma | |
− | + | fixes n :: "nat" | |
− | + | shows "even (n*(n+1))" | |
− | + | by auto | |
− | + | text {* | |
− | + | Comentarios sobre la demostración anterior: | |
− | + | · Para poder usar la función "even" de la librería Parity es necesario | |
− | + | importar dicha librería. Por ello, antes del inicio de la teoría | |
− | + | aparece | |
− | + | imports Main Parity | |
− | + | *} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
text {* | text {* | ||
− | + | Para completar la demostración basta demostrar la equivalencia de las | |
− | + | funciones "par" y "even". | |
− | |||
− | |||
− | |||
*} | *} | ||
− | + | lemma | |
− | + | fixes n :: "nat" | |
− | by | + | shows "par n = even n" |
+ | proof - | ||
+ | have "par n = (∃m. n = m+m)" by (simp add:par_def) | ||
+ | then show "par n = even n" by presburger | ||
+ | qed | ||
− | text {* | + | text {* |
− | + | Comentarios sobre la demostración anterior: | |
− | + | · "by presburger" indica que se use como método de demostración el | |
− | + | algoritmo de decisión de la aritmética de Presburger. | |
+ | *} | ||
− | + | section {* Inducción estructural *} | |
− | |||
− | |||
− | text {* | + | text {* |
− | + | Inducción estructural: | |
− | + | · En Isabelle puede hacerse inducción estructural sobre cualquier tipo | |
+ | recursivo. | ||
+ | · La inducción matemática es la inducción estructural sobre el tipo de | ||
+ | los naturales. | ||
+ | · El esquema de inducción estructural sobre listas es | ||
+ | · list.induct: ⟦P []; ⋀x ys. P ys ⟹ P (x # ys)⟧ ⟹ P zs | ||
+ | · Para demostrar una propiedad para todas las listas basta demostrar | ||
+ | que la lista vacía tiene la propiedad y que al añadir un elemento a una | ||
+ | lista que tiene la propiedad se obtiene una lista que también tiene la | ||
+ | propiedad. | ||
+ | · En Isabelle el principio de inducción sobre listas está formalizado | ||
+ | mediante el teorema list.induct que puede verse con | ||
+ | thm list.induct | ||
+ | *} | ||
− | text {* | + | text {* |
− | + | Concatenación de listas: | |
− | + | En la teoría List.thy está definida la concatenación de listas (que | |
− | + | se representa por @) como sigue | |
+ | append_Nil: "[]@ys = ys" | ||
+ | append_Cons: "(x#xs)@ys = x#(xs@ys)" | ||
+ | *} | ||
− | + | text {* | |
− | + | Lema. [Ejemplo de inducción sobre listas] | |
− | + | Demostrar que la concatenación de listas es asociativa. | |
− | + | *} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ― ‹La demostración estructurada es› | |
− | lemma " | + | lemma conc_asociativa: "xs @ (ys @ zs) = (xs @ ys) @ zs" |
proof (induct xs) | proof (induct xs) | ||
− | show " | + | show "[] @ (ys @ zs) = ([] @ ys) @ zs" |
+ | proof - | ||
+ | have "[] @ (ys @ zs) = ys @ zs" by simp | ||
+ | also have "… = ([] @ ys) @ zs" by simp | ||
+ | finally show ?thesis . | ||
+ | qed | ||
next | next | ||
fix x xs | fix x xs | ||
− | assume HI: " | + | assume HI: "xs @ (ys @ zs) = (xs @ ys) @ zs" |
− | + | show "(x#xs) @ (ys @ zs) = ((x#xs) @ ys) @ zs" | |
− | + | proof - | |
− | + | have "(x#xs) @ (ys @ zs) = x#(xs @ (ys @ zs))" by simp | |
− | + | also have "… = x#((xs @ ys) @ zs)" using HI by simp | |
− | + | also have "… = (x#(xs @ ys)) @ zs" by simp | |
− | + | also have "… = ((x#xs) @ ys) @ zs" by simp | |
− | + | finally show ?thesis . | |
+ | qed | ||
qed | qed | ||
− | + | ― ‹La demostración automática es› | |
− | lemma " | + | lemma conc_asociativa_1: "xs @ (ys @ zs) = (xs @ ys) @ zs" |
− | + | by (induct xs) auto | |
− | section {* | + | section {* Heurísticas para la inducción *} |
− | text {* | + | text {* |
− | + | Definición. [Definición recursiva de inversa] | |
− | + | (inversa xs) la inversa de la lista xs. Por ejemplo, | |
− | + | inversa [a,b,c] = [c,b,a] | |
− | + | *} | |
− | |||
− | |||
− | fun | + | fun inversa :: "'a list ⇒ 'a list" where |
− | " | + | "inversa [] = []" |
− | + | | "inversa (x#xs) = (inversa xs) @ [x]" | |
− | | " | ||
− | |||
− | |||
− | + | value "inversa [a,b,c]" | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | value " | ||
text {* | text {* | ||
− | + | Definición. [Definición de inversa con acumuladores] | |
− | + | (inversaAc xs) es la inversa de la lista xs calculada con | |
− | + | acumuladores. Por ejemplo, | |
− | + | inversaAc [a,b,c] = [c,b,a] | |
− | + | inversaAcAux [a,b,c] [] = [c,b,a] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
*} | *} | ||
− | + | fun inversaAcAux :: "'a list ⇒ 'a list ⇒ 'a list" where | |
− | + | "inversaAcAux [] ys = ys" | |
− | + | | "inversaAcAux (x#xs) ys = inversaAcAux xs (x#ys)" | |
− | + | definition inversaAc :: "'a list ⇒ 'a list" where | |
+ | "inversaAc xs ≡ inversaAcAux xs []" | ||
− | + | value "inversaAcAux [a,b,c] []" | |
− | + | value "inversaAc [a,b,c]" | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | text {* | |
− | + | Lema. [Ejemplo de equivalencia entre las definiciones] | |
− | + | La inversa de [a,b,c] es lo mismo calculada con la primera definición | |
− | + | que con la segunda. | |
− | |||
− | |||
− | |||
− | text {* | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
*} | *} | ||
− | + | lemma "inversaAc [a,b,c] = inversa [a,b,c]" | |
− | lemma " | + | by (simp add: inversaAc_def) |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
text {* | text {* | ||
− | + | Nota. [Ejemplo fallido de demostración por inducción] | |
− | + | El siguiente intento de demostrar que para cualquier lista xs, se | |
− | + | tiene que "inversaAc xs = inversa xs" falla. | |
− | |||
*} | *} | ||
− | + | lemma "inversaAc xs = inversa xs" | |
− | lemma " | + | proof (induct xs) |
− | proof ( | + | show "inversaAc [] = inversa []" by (simp add: inversaAc_def) |
− | |||
− | |||
next | next | ||
− | + | fix a xs assume HI: "inversaAc xs = inversa xs" | |
− | + | have "inversaAc (a#xs) = inversaAcAux (a#xs) []" | |
− | + | by (simp add: inversaAc_def) | |
− | + | also have "… = inversaAcAux xs [a]" by simp | |
− | + | also have "… = inversa (a#xs)" | |
− | + | (* Problema: la hipótesis de inducción no es aplicable. *) | |
− | + | oops | |
− | |||
− | |||
text {* | text {* | ||
− | Heurística de generalización | + | Nota. [Heurística de generalización] |
− | + | Cuando se use demostración estructural, cuantificar universalmente las | |
− | + | variables libres (o, equivalentemente, considerar las variables libres | |
− | + | como variables arbitrarias). | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Lema. [Lema con generalización] | |
− | + | Para toda lista ys se tiene | |
− | |||
− | |||
− | |||
− | |||
− | |||
inversaAcAux xs ys = (inversa xs) @ ys | inversaAcAux xs ys = (inversa xs) @ ys | ||
− | + | *} | |
− | + | ― ‹La demostración estructurada es› | |
lemma inversaAcAux_es_inversa: | lemma inversaAcAux_es_inversa: | ||
− | "inversaAcAux xs ys = (inversa xs) @ ys" | + | "inversaAcAux xs ys = (inversa xs)@ys" |
proof (induct xs arbitrary: ys) | proof (induct xs arbitrary: ys) | ||
− | show "⋀ys. inversaAcAux [] ys = inversa [] @ ys" by simp | + | show "⋀ys. inversaAcAux [] ys = (inversa [])@ys" by simp |
next | next | ||
fix a xs | fix a xs | ||
Línea 569: | Línea 472: | ||
have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)" by simp | have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)" by simp | ||
also have "… = inversa xs@(a#ys)" using HI by simp | also have "… = inversa xs@(a#ys)" using HI by simp | ||
− | also have "… = inversa (a#xs)@ys" by simp | + | also have "… = inversa (a#xs)@ys" using [[simp_trace]] by simp |
finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys" by simp | finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys" by simp | ||
qed | qed | ||
qed | qed | ||
+ | |||
+ | ― ‹La demostración automática es› | ||
+ | lemma inversaAcAux_es_inversa_1: | ||
+ | "inversaAcAux xs ys = (inversa xs)@ys" | ||
+ | by (induct xs arbitrary: ys) auto | ||
text {* | text {* | ||
− | + | Corolario. Para cualquier lista xs, se tiene que | |
− | + | inversaAc xs = inversa xs | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
*} | *} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
corollary "inversaAc xs = inversa xs" | corollary "inversaAc xs = inversa xs" | ||
− | by (simp add: inversaAcAux_es_inversa) | + | using [[simp_trace]] |
+ | by (simp add: inversaAcAux_es_inversa inversaAc_def) | ||
text {* | text {* | ||
− | + | Nota. En el paso "inversa xs@(a#ys) = inversa (a#xs)@ys" se usan | |
− | · | + | lemas de la teoría List. Se puede observar, insertano |
− | + | using [[simp_trace]] | |
− | + | entre la igualdad y by simp, que los lemas usados son | |
+ | · List.append_simps_1: []@ys = ys | ||
+ | · List.append_simps_2: (x#xs)@ys = x#(xs@ys) | ||
+ | · List.append_assoc: (xs @ ys) @ zs = xs @ (ys @ zs) | ||
+ | Las dos primeras son las ecuaciones de la definición de append. | ||
+ | |||
+ | En la siguiente demostración se detallan los lemas utilizados. | ||
*} | *} | ||
− | + | lemma "(inversa xs)@(a#ys) = (inversa (a#xs))@ys" | |
+ | proof - | ||
+ | have "(inversa xs)@(a#ys) = (inversa xs)@(a#([]@ys))" | ||
+ | by (simp only: append.simps(1)) | ||
+ | also have "… = (inversa xs)@([a]@ys)" by (simp only: append.simps(2)) | ||
+ | also have "… = ((inversa xs)@[a])@ys" by (simp only: append_assoc) | ||
+ | also have "… = (inversa (a#xs))@ys" by (simp only: inversa.simps(2)) | ||
+ | finally show ?thesis . | ||
+ | qed | ||
− | + | section {* Recursión general. La función de Ackermann *} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | text {* | |
− | + | El objetivo de esta sección es mostrar el uso de las definiciones | |
− | + | recursivas generales y sus esquemas de inducción. Como ejemplo se usa la | |
+ | función de Ackermann (se puede consultar información sobre dicha función en | ||
+ | http://en.wikipedia.org/wiki/Ackermann_function). | ||
− | + | Definición. La función de Ackermann se define por | |
+ | A(m,n) = n+1, si m=0, | ||
+ | A(m-1,1), si m>0 y n=0, | ||
+ | A(m-1,A(m,n-1)), si m>0 y n>0 | ||
+ | para todo los números naturales. | ||
− | + | La función de Ackermann es recursiva, pero no es primitiva recursiva. | |
− | + | *} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | fun | + | fun ack :: "nat ⇒ nat ⇒ nat" where |
− | " | + | "ack 0 n = n+1" |
− | | " | + | | "ack (Suc m) 0 = ack m 1" |
+ | | "ack (Suc m) (Suc n) = ack m (ack (Suc m) n)" | ||
− | value " | + | ― ‹Ejemplo de evaluación› |
+ | value "ack 2 3" (* devuelve 9 *) | ||
− | text {* | + | text {* |
− | + | Esquema de inducción correspondiente a una función: | |
− | + | · Al definir una función recursiva general se genera una regla de | |
− | + | inducción. En la definición anterior, la regla generada es | |
+ | ack.induct: | ||
+ | ⟦⋀n. P 0 n; | ||
+ | ⋀m. P m 1 ⟹ P (Suc m) 0; | ||
+ | ⋀m n. ⟦P (Suc m) n; P m (ack (Suc m) n)⟧ ⟹ P (Suc m) (Suc n)⟧ | ||
+ | ⟹ P a b | ||
+ | *} | ||
− | + | text {* | |
− | + | Ejemplo de demostración por la inducción correspondiente a una función: | |
− | + | Demostrar que para todos m y n, A(m,n) > n. | |
− | + | *} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ― ‹La demostración detallada es› | |
− | lemma " | + | lemma "ack m n > n" |
− | + | proof (induct m n rule: ack.induct) | |
− | + | fix n | |
− | + | show "ack 0 n > n" by simp | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | show " | ||
next | next | ||
− | fix | + | fix m |
− | assume | + | assume "ack m 1 > 1" |
− | + | then show "ack (Suc m) 0 > 0" by simp | |
− | + | next | |
− | + | fix m n | |
− | + | assume "n < ack (Suc m) n" and | |
− | + | "ack (Suc m) n < ack m (ack (Suc m) n)" | |
+ | then show "Suc n < ack (Suc m) (Suc n)" by simp | ||
qed | qed | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
text {* | text {* | ||
− | + | Comentarios sobre la demostración anterior: | |
− | · | + | · (induct m n rule: ack.induct) indica que el método de demostración |
− | + | es el esquema de recursión correspondiente a la definición de | |
− | · | + | (ack m n). |
− | + | · Se generan 3 casos: | |
− | + | 1. ⋀n. n < ack 0 n | |
− | + | 2. ⋀m. 1 < ack m 1 ⟹ 0 < ack (Suc m) 0 | |
+ | 3. ⋀m n. ⟦n < ack (Suc m) n; | ||
+ | ack (Suc m) n < ack m (ack (Suc m) n)⟧ | ||
+ | ⟹ Suc n < ack (Suc m) (Suc n) | ||
*} | *} | ||
+ | |||
+ | ― ‹La demostración automática es› | ||
+ | lemma "ack m n > n" | ||
+ | by (induct m n rule: ack.induct) auto | ||
end | end | ||
</source> | </source> |
Revisión del 13:06 7 feb 2019
chapter {* Tema 7: Razonamiento por casos y por inducción *}
theory T7_Razonamiento_por_casos_y_por_induccion
imports Main HOL.Parity
begin
text {*
En este tema se amplían los métodos de demostración por casos y por
inducción iniciados en el tema anterior.
*}
section {* Razonamiento por distinción de casos *}
subsection {* Distinción de casos booleanos *}
text {*
Ejemplo de demostración por distinción de casos booleanos:
Demostrar "¬A ∨ A".
*}
― ‹La demostración estructurada es›
lemma "¬A ∨ A"
proof cases
assume "A"
then show "¬A ∨ A" ..
next
assume "¬A"
then show "¬A ∨ A" ..
qed
text {*
Comentarios de la demostración anterior:
· "proof cases" indica que el método de demostración será por
distinción de casos.
· Se generan 2 casos:
1. ?P ⟹ ¬A ∨ A
2. ¬?P ⟹ ¬A ∨ A
donde ?P es una variable sobre las fórmulas.
· (assume "A") indica que se está usando "A" en lugar de la variable
?P.
· "then" indica usando la fórmula anterior.
· ".." indica usando la regla lógica necesaria (las reglas lógicas se
estudiarán en los siguientes temas).
· "next" indica el siguiente caso (se puede observar cómo ha
sustituido ¬?P por ¬A.
*}
― ‹La demostración automática es›
lemma "¬A ∨ A"
by auto
text {*
Ejemplo de demostración por distinción de casos booleanos con nombres:
Demostrar "¬A ∨ A".
*}
― ‹La demostración estructurada es›
lemma "¬A ∨ A"
proof (cases "A")
case True
then show "¬A ∨ A" ..
next
case False
thus "¬A ∨ A" ..
qed
text {*
Comentarios sobre la demostración anterior:
· (cases "A") indica que la demostración se hará por casos según los
distintos valores de "A".
· Como "A" es una fórmula, sus posibles valores son verdadero o falso.
· "case True" indica que se está suponiendo que A es verdadera. Es
equivalente a "assume A".
· "case False" indica que se está suponiendo que A es falsa. Es
equivalente a "assume ¬A".
· En general,
· el método (cases F) es una abreviatura de la aplicación de la regla
⟦F ⟹ Q; ¬F ⟹ Q⟧ ⟹ Q
· La expresión "case True" es una abreviatura de F.
· La expresión "case False" es una abreviatura de ¬F.
· Ventajas de "cases" con nombre:
· reduce la escritura de la fórmula y
· es independiente del orden de los casos.
*}
subsection {* Distinción de casos sobre otros tipos de datos *}
text {*
Ejemplo de distinción de casos sobre listas:
Demostrar que la longitud del resto de una lista es la longitud de la
lista menos 1.
*}
― ‹La demostración detallada es›
lemma "length (tl xs) = length xs - 1"
proof (cases xs)
assume "xs = []"
then show "length (tl xs) = length xs - 1" by simp
next
fix y ys
assume "xs = y#ys"
then show "length(tl xs) = length xs - 1" by simp
qed
text {*
Comentarios sobre la demostración anterior:
· "(cases xs)" indica que la demostración se hará por casos sobre los
posibles valores de xs.
· Como xs es una lista, sus posibles valores son la lista vacía ([]) o
una lista no vacía (de la forma (y#ys)).
· Se generan 2 casos:
1. xs = [] ⟹ length (tl xs) = length xs - 1
2. ⋀a list. xs = a # list ⟹ length (tl xs) = length xs - 1
*}
― ‹La demostración simplificada es›
lemma "length (tl xs) = length xs - 1"
proof (cases xs)
case Nil
then show ?thesis by simp
next
case Cons
then show ?thesis by simp
qed
text {*
Comentarios sobre la dmostración anterior:
· "case Nil" es una abreviatura de
"assume xs =[]".
· "case Cons" es una abreviatura de
"fix y ys assume xs = y#ys"
· ?thesis es una abreviatura de la conclusión del lema.
*}
― ‹La demostración automática es›
lemma "length (tl xs) = length xs - 1"
by auto
text {*
En el siguiente ejemplo vamos a demostrar una propiedad de la función
drop que está definida en la teoría List de forma que (drop n xs) la
lista obtenida eliminando en xs} los n primeros elementos. Su
definición es la siguiente
drop_Nil: "drop n [] = []"
drop_Cons: "drop n (x#xs) = (case n of
0 => x#xs |
Suc(m) => drop m xs)"
*}
text {*
Ejemplo de análisis de casos:
Demostrar que el resultado de eliminar los n+1 primeros elementos de
xs es el mismo que eliminar los n primeros elementos del resto de xs.
*}
― ‹La demostración detallada es›
lemma "drop (n + 1) xs = drop n (tl xs)"
proof (cases xs)
case Nil
then show ?thesis by simp
next
case Cons
then show ?thesis by simp
qed
― ‹La demostración automática es›
lemma "drop (n + 1) xs = drop n (tl xs)"
by (cases xs) auto
section {* Inducción matemática *}
text {*
[Principio de inducción matemática]
Para demostrar una propiedad P para todos los números naturales basta
probar que el 0 tiene la propiedad P y que si n tiene la propiedad P,
entonces n+1 también la tiene.
⟦P 0; ⋀n. P n ⟹ P (Suc n)⟧ ⟹ P m
En Isabelle el principio de inducción matemática está formalizado en
el teorema nat.induct y puede verse con
thm nat.induct
*}
text {*
Ejemplo de demostración por inducción: Usaremos el principio de
inducción matemática para demostrar que
1 + 3 + ... + (2n-1) = n^2
Definición. [Suma de los primeros impares]
(suma_impares n) la suma de los n números impares. Por ejemplo,
suma_impares 3 = 9
*}
fun suma_impares :: "nat ⇒ nat" where
"suma_impares 0 = 0"
| "suma_impares (Suc n) = (2*(Suc n) - 1) + suma_impares n"
value "suma_impares 3"
text {*
Ejemplo de demostración por inducción matemática:
Demostrar que la suma de los n primeros números impares es n^2.
*}
― ‹Demostración del lema anterior por inducción y razonamiento
ecuacional›
lemma "suma_impares n = n * n"
proof (induct n)
show "suma_impares 0 = 0 * 0" by simp
next
fix n assume HI: "suma_impares n = n * n"
have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n"
by simp
also have "… = (2 * (Suc n) - 1) + n * n" using HI by simp
also have "… = n * n + 2 * n + 1" by simp
finally show "suma_impares (Suc n) = (Suc n) * (Suc n)" by simp
qed
― ‹Demostración del lema anterior con patrones y razonamiento
ecuacional›
lemma "suma_impares n = n * n" (is "?P n")
proof (induct n)
show "?P 0" by simp
next
fix n
assume HI: "?P n"
have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n"
by simp
also have "… = (2 * (Suc n) - 1) + n * n" using HI by simp
also have "… = n * n + 2 * n + 1" by simp
finally show "?P (Suc n)" by simp
qed
text {*
Comentario sobre la demostración anterior:
· Con la expresión
"suma_impares n = n * n" (is "?P n")
se abrevia "suma_impares n = n * n" como "?P n". Por tanto,
"?P 0" es una abreviatura de "suma_impares 0 = 0 * 0"
"?P (Suc n)" es una abreviatura de "suma_impares (Suc n) = (Suc n) * (Suc n)"
· En general, cualquier fórmula seguida de (is patrón) equipara el
patrón con la fórmula.
*}
― ‹La demostración usando patrones es›
lemma "suma_impares n = n * n" (is "?P n")
proof (induct n)
show "?P 0" by simp
next
fix n
assume "?P n"
then show "?P (Suc n)" by simp
qed
― ‹La demostración automática es›
lemma "suma_impares n = n * n"
by (induct n) auto
text {*
Ejemplo de definición con existenciales.
Un número natural n es par si existe un natural m tal que n=m+m.
*}
definition par :: "nat ⇒ bool" where
"par n ≡ ∃m. n=m+m"
text {*
Ejemplo de inducción y existenciales:
Demostrar que para todo número natural n, se verifica que n*(n+1) par.
*}
― ‹Demostración detallada por inducción›
lemma
fixes n :: "nat"
shows "par (n*(n+1))"
proof (induct n)
show "par (0*(0+1))" by (simp add: par_def)
next
fix n
assume "par (n*(n+1))"
then have "∃m. n*(n+1) = m+m" by (simp add:par_def)
then obtain m where m: "n*(n+1) = m+m" ..
then have "(Suc n)*((Suc n)+1) = (m+n+1)+(m+n+1)" by auto
then have "∃m. (Suc n)*((Suc n)+1) = m+m" ..
then show "par ((Suc n)*((Suc n)+1))" by (simp add:par_def)
qed
text {*
Comentarios sobre la demostración anterior:
· (fixes n :: "nat") es una abreviatura de "sea n un número natural".
*}
text {*
En Isabelle puede demostrarse de manera más simple un lema equivalente
usando en lugar de la función "par" la función "even" definida en la
teoría Parity por
even x ⟷ x mod 2 = 0"
*}
lemma
fixes n :: "nat"
shows "even (n*(n+1))"
by auto
text {*
Comentarios sobre la demostración anterior:
· Para poder usar la función "even" de la librería Parity es necesario
importar dicha librería. Por ello, antes del inicio de la teoría
aparece
imports Main Parity
*}
text {*
Para completar la demostración basta demostrar la equivalencia de las
funciones "par" y "even".
*}
lemma
fixes n :: "nat"
shows "par n = even n"
proof -
have "par n = (∃m. n = m+m)" by (simp add:par_def)
then show "par n = even n" by presburger
qed
text {*
Comentarios sobre la demostración anterior:
· "by presburger" indica que se use como método de demostración el
algoritmo de decisión de la aritmética de Presburger.
*}
section {* Inducción estructural *}
text {*
Inducción estructural:
· En Isabelle puede hacerse inducción estructural sobre cualquier tipo
recursivo.
· La inducción matemática es la inducción estructural sobre el tipo de
los naturales.
· El esquema de inducción estructural sobre listas es
· list.induct: ⟦P []; ⋀x ys. P ys ⟹ P (x # ys)⟧ ⟹ P zs
· Para demostrar una propiedad para todas las listas basta demostrar
que la lista vacía tiene la propiedad y que al añadir un elemento a una
lista que tiene la propiedad se obtiene una lista que también tiene la
propiedad.
· En Isabelle el principio de inducción sobre listas está formalizado
mediante el teorema list.induct que puede verse con
thm list.induct
*}
text {*
Concatenación de listas:
En la teoría List.thy está definida la concatenación de listas (que
se representa por @) como sigue
append_Nil: "[]@ys = ys"
append_Cons: "(x#xs)@ys = x#(xs@ys)"
*}
text {*
Lema. [Ejemplo de inducción sobre listas]
Demostrar que la concatenación de listas es asociativa.
*}
― ‹La demostración estructurada es›
lemma conc_asociativa: "xs @ (ys @ zs) = (xs @ ys) @ zs"
proof (induct xs)
show "[] @ (ys @ zs) = ([] @ ys) @ zs"
proof -
have "[] @ (ys @ zs) = ys @ zs" by simp
also have "… = ([] @ ys) @ zs" by simp
finally show ?thesis .
qed
next
fix x xs
assume HI: "xs @ (ys @ zs) = (xs @ ys) @ zs"
show "(x#xs) @ (ys @ zs) = ((x#xs) @ ys) @ zs"
proof -
have "(x#xs) @ (ys @ zs) = x#(xs @ (ys @ zs))" by simp
also have "… = x#((xs @ ys) @ zs)" using HI by simp
also have "… = (x#(xs @ ys)) @ zs" by simp
also have "… = ((x#xs) @ ys) @ zs" by simp
finally show ?thesis .
qed
qed
― ‹La demostración automática es›
lemma conc_asociativa_1: "xs @ (ys @ zs) = (xs @ ys) @ zs"
by (induct xs) auto
section {* Heurísticas para la inducción *}
text {*
Definición. [Definición recursiva de inversa]
(inversa xs) la inversa de la lista xs. Por ejemplo,
inversa [a,b,c] = [c,b,a]
*}
fun inversa :: "'a list ⇒ 'a list" where
"inversa [] = []"
| "inversa (x#xs) = (inversa xs) @ [x]"
value "inversa [a,b,c]"
text {*
Definición. [Definición de inversa con acumuladores]
(inversaAc xs) es la inversa de la lista xs calculada con
acumuladores. Por ejemplo,
inversaAc [a,b,c] = [c,b,a]
inversaAcAux [a,b,c] [] = [c,b,a]
*}
fun inversaAcAux :: "'a list ⇒ 'a list ⇒ 'a list" where
"inversaAcAux [] ys = ys"
| "inversaAcAux (x#xs) ys = inversaAcAux xs (x#ys)"
definition inversaAc :: "'a list ⇒ 'a list" where
"inversaAc xs ≡ inversaAcAux xs []"
value "inversaAcAux [a,b,c] []"
value "inversaAc [a,b,c]"
text {*
Lema. [Ejemplo de equivalencia entre las definiciones]
La inversa de [a,b,c] es lo mismo calculada con la primera definición
que con la segunda.
*}
lemma "inversaAc [a,b,c] = inversa [a,b,c]"
by (simp add: inversaAc_def)
text {*
Nota. [Ejemplo fallido de demostración por inducción]
El siguiente intento de demostrar que para cualquier lista xs, se
tiene que "inversaAc xs = inversa xs" falla.
*}
lemma "inversaAc xs = inversa xs"
proof (induct xs)
show "inversaAc [] = inversa []" by (simp add: inversaAc_def)
next
fix a xs assume HI: "inversaAc xs = inversa xs"
have "inversaAc (a#xs) = inversaAcAux (a#xs) []"
by (simp add: inversaAc_def)
also have "… = inversaAcAux xs [a]" by simp
also have "… = inversa (a#xs)"
(* Problema: la hipótesis de inducción no es aplicable. *)
oops
text {*
Nota. [Heurística de generalización]
Cuando se use demostración estructural, cuantificar universalmente las
variables libres (o, equivalentemente, considerar las variables libres
como variables arbitrarias).
Lema. [Lema con generalización]
Para toda lista ys se tiene
inversaAcAux xs ys = (inversa xs) @ ys
*}
― ‹La demostración estructurada es›
lemma inversaAcAux_es_inversa:
"inversaAcAux xs ys = (inversa xs)@ys"
proof (induct xs arbitrary: ys)
show "⋀ys. inversaAcAux [] ys = (inversa [])@ys" by simp
next
fix a xs
assume HI: "⋀ys. inversaAcAux xs ys = inversa xs@ys"
show "⋀ys. inversaAcAux (a#xs) ys = inversa (a#xs)@ys"
proof -
fix ys
have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)" by simp
also have "… = inversa xs@(a#ys)" using HI by simp
also have "… = inversa (a#xs)@ys" using [[simp_trace]] by simp
finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys" by simp
qed
qed
― ‹La demostración automática es›
lemma inversaAcAux_es_inversa_1:
"inversaAcAux xs ys = (inversa xs)@ys"
by (induct xs arbitrary: ys) auto
text {*
Corolario. Para cualquier lista xs, se tiene que
inversaAc xs = inversa xs
*}
corollary "inversaAc xs = inversa xs"
using [[simp_trace]]
by (simp add: inversaAcAux_es_inversa inversaAc_def)
text {*
Nota. En el paso "inversa xs@(a#ys) = inversa (a#xs)@ys" se usan
lemas de la teoría List. Se puede observar, insertano
using [[simp_trace]]
entre la igualdad y by simp, que los lemas usados son
· List.append_simps_1: []@ys = ys
· List.append_simps_2: (x#xs)@ys = x#(xs@ys)
· List.append_assoc: (xs @ ys) @ zs = xs @ (ys @ zs)
Las dos primeras son las ecuaciones de la definición de append.
En la siguiente demostración se detallan los lemas utilizados.
*}
lemma "(inversa xs)@(a#ys) = (inversa (a#xs))@ys"
proof -
have "(inversa xs)@(a#ys) = (inversa xs)@(a#([]@ys))"
by (simp only: append.simps(1))
also have "… = (inversa xs)@([a]@ys)" by (simp only: append.simps(2))
also have "… = ((inversa xs)@[a])@ys" by (simp only: append_assoc)
also have "… = (inversa (a#xs))@ys" by (simp only: inversa.simps(2))
finally show ?thesis .
qed
section {* Recursión general. La función de Ackermann *}
text {*
El objetivo de esta sección es mostrar el uso de las definiciones
recursivas generales y sus esquemas de inducción. Como ejemplo se usa la
función de Ackermann (se puede consultar información sobre dicha función en
http://en.wikipedia.org/wiki/Ackermann_function).
Definición. La función de Ackermann se define por
A(m,n) = n+1, si m=0,
A(m-1,1), si m>0 y n=0,
A(m-1,A(m,n-1)), si m>0 y n>0
para todo los números naturales.
La función de Ackermann es recursiva, pero no es primitiva recursiva.
*}
fun ack :: "nat ⇒ nat ⇒ nat" where
"ack 0 n = n+1"
| "ack (Suc m) 0 = ack m 1"
| "ack (Suc m) (Suc n) = ack m (ack (Suc m) n)"
― ‹Ejemplo de evaluación›
value "ack 2 3" (* devuelve 9 *)
text {*
Esquema de inducción correspondiente a una función:
· Al definir una función recursiva general se genera una regla de
inducción. En la definición anterior, la regla generada es
ack.induct:
⟦⋀n. P 0 n;
⋀m. P m 1 ⟹ P (Suc m) 0;
⋀m n. ⟦P (Suc m) n; P m (ack (Suc m) n)⟧ ⟹ P (Suc m) (Suc n)⟧
⟹ P a b
*}
text {*
Ejemplo de demostración por la inducción correspondiente a una función:
Demostrar que para todos m y n, A(m,n) > n.
*}
― ‹La demostración detallada es›
lemma "ack m n > n"
proof (induct m n rule: ack.induct)
fix n
show "ack 0 n > n" by simp
next
fix m
assume "ack m 1 > 1"
then show "ack (Suc m) 0 > 0" by simp
next
fix m n
assume "n < ack (Suc m) n" and
"ack (Suc m) n < ack m (ack (Suc m) n)"
then show "Suc n < ack (Suc m) (Suc n)" by simp
qed
text {*
Comentarios sobre la demostración anterior:
· (induct m n rule: ack.induct) indica que el método de demostración
es el esquema de recursión correspondiente a la definición de
(ack m n).
· Se generan 3 casos:
1. ⋀n. n < ack 0 n
2. ⋀m. 1 < ack m 1 ⟹ 0 < ack (Suc m) 0
3. ⋀m n. ⟦n < ack (Suc m) n;
ack (Suc m) n < ack m (ack (Suc m) n)⟧
⟹ Suc n < ack (Suc m) (Suc n)
*}
― ‹La demostración automática es›
lemma "ack m n > n"
by (induct m n rule: ack.induct) auto
end