Diferencia entre revisiones de «Razonamiento por casos y por inducci¢n»
De Lógica matemática y fundamentos (2018-19)
(No se muestra una edición intermedia del mismo usuario) | |||
Línea 1: | Línea 1: | ||
<source lang="isabelle"> | <source lang="isabelle"> | ||
− | chapter | + | chapter ‹Tema 7: Razonamiento por casos y por inducción› |
theory T7_Razonamiento_por_casos_y_por_induccion | theory T7_Razonamiento_por_casos_y_por_induccion | ||
Línea 6: | Línea 6: | ||
begin | begin | ||
− | text | + | text ‹En este tema se amplían los métodos de demostración por casos y |
− | + | por inducción iniciados en el tema anterior.› | |
− | inducción iniciados en el tema anterior. | ||
− | |||
− | section | + | section ‹Razonamiento por distinción de casos› |
− | subsection | + | subsection ‹Distinción de casos booleanos› |
− | text | + | text ‹Ejemplo de demostración por distinción de casos booleanos: |
− | + | Demostrar "¬A ∨ A".› | |
− | Demostrar "¬A ∨ A". | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
― ‹La demostración estructurada es› | ― ‹La demostración estructurada es› | ||
Línea 49: | Línea 26: | ||
qed | qed | ||
− | text | + | text ‹Comentarios de la demostración anterior: |
− | |||
· "proof cases" indica que el método de demostración será por | · "proof cases" indica que el método de demostración será por | ||
distinción de casos. | distinción de casos. | ||
Línea 63: | Línea 39: | ||
estudiarán en los siguientes temas). | estudiarán en los siguientes temas). | ||
· "next" indica el siguiente caso (se puede observar cómo ha | · "next" indica el siguiente caso (se puede observar cómo ha | ||
− | sustituido ¬?P por ¬A. | + | sustituido ¬?P por ¬A.› |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
― ‹La demostración aplicativa es› | ― ‹La demostración aplicativa es› | ||
lemma "¬A ∨ A" | lemma "¬A ∨ A" | ||
− | apply | + | apply cases |
− | + | apply simp_all | |
− | apply | ||
− | |||
done | done | ||
− | ― ‹La demostración | + | ― ‹La demostración automática es› |
lemma "¬A ∨ A" | lemma "¬A ∨ A" | ||
− | + | by cases simp_all | |
− | + | ||
− | + | 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› | ― ‹La demostración estructurada es› | ||
Línea 97: | Línea 65: | ||
next | next | ||
case False | case False | ||
− | + | then show "¬A ∨ A" .. | |
qed | qed | ||
− | text | + | text ‹Comentarios sobre la demostración anterior: |
− | |||
· (cases "A") indica que la demostración se hará por casos según los | · (cases "A") indica que la demostración se hará por casos según los | ||
distintos valores de "A". | distintos valores de "A". | ||
Línea 116: | Línea 83: | ||
· Ventajas de "cases" con nombre: | · Ventajas de "cases" con nombre: | ||
· reduce la escritura de la fórmula y | · reduce la escritura de la fórmula y | ||
− | · es independiente del orden de los casos. | + | · es independiente del orden de los casos.› |
− | |||
− | subsection | + | subsection ‹Distinción de casos sobre otros tipos de datos› |
− | text | + | text ‹Ejemplo de distinción de casos sobre listas: |
− | |||
Demostrar que la longitud del resto de una lista es la longitud de la | Demostrar que la longitud del resto de una lista es la longitud de la | ||
− | lista menos 1. | + | lista menos 1.› |
− | |||
− | ― ‹La demostración | + | ― ‹La demostración estructurada es› |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
lemma "length (tl xs) = length xs - 1" | lemma "length (tl xs) = length xs - 1" | ||
proof (cases xs) | proof (cases xs) | ||
assume "xs = []" | assume "xs = []" | ||
− | then show "length (tl xs) = length xs - 1" by | + | then have "length (tl xs) = 0" |
+ | by simp | ||
+ | also have "… = 0 - 1" | ||
+ | by simp | ||
+ | also have "… = length xs - 1" | ||
+ | using ‹xs = []› | ||
+ | by simp | ||
+ | finally show "length (tl xs) = length xs - 1" | ||
+ | by this | ||
next | next | ||
fix y ys | fix y ys | ||
assume "xs = y#ys" | assume "xs = y#ys" | ||
− | then show "length(tl xs) = length xs - 1" by | + | then have "length (tl xs) = length ys" |
+ | by simp | ||
+ | also have "… = (1 + length ys) - 1" | ||
+ | by simp | ||
+ | also have "… = length (y#ys) - 1" | ||
+ | by simp | ||
+ | also have "… = length xs - 1" | ||
+ | using ‹xs = y#ys› | ||
+ | by simp | ||
+ | finally show "length (tl xs) = length xs - 1" | ||
+ | by this | ||
qed | qed | ||
− | text | + | text ‹Comentarios sobre la demostración anterior: |
− | |||
· "(cases xs)" indica que la demostración se hará por casos sobre los | · "(cases xs)" indica que la demostración se hará por casos sobre los | ||
posibles valores de xs. | posibles valores de xs. | ||
Línea 164: | Línea 127: | ||
· Se generan 2 casos: | · Se generan 2 casos: | ||
1. xs = [] ⟹ length (tl xs) = length xs - 1 | 1. xs = [] ⟹ length (tl xs) = length xs - 1 | ||
− | 2. ⋀a list. xs = a # list ⟹ length (tl xs) = length xs - 1 | + | 2. ⋀a list. xs = a # list ⟹ length (tl xs) = length xs - 1› |
− | + | ||
+ | ― ‹La demostración detallada es› | ||
+ | lemma "length (tl xs) = length xs - 1" | ||
+ | proof (cases xs) | ||
+ | assume "xs = []" | ||
+ | then have "length (tl xs) = 0" | ||
+ | by (simp only: list.sel(2) | ||
+ | list.size(3)) | ||
+ | also have "… = 0 - 1" | ||
+ | by (simp only: natural_zero_minus_one) | ||
+ | also have "… = length xs - 1" | ||
+ | using ‹xs = []› | ||
+ | by (simp only: list.size(3)) | ||
+ | finally show "length (tl xs) = length xs - 1" | ||
+ | by this | ||
+ | next | ||
+ | fix y ys | ||
+ | assume "xs = y#ys" | ||
+ | then have "length (tl xs) = length ys" | ||
+ | by (simp only: list.sel(3)) | ||
+ | also have "… = length (y#ys) - 1" | ||
+ | by (simp only: length_Cons) | ||
+ | also have "… = length xs - 1" | ||
+ | using ‹xs = y#ys› | ||
+ | by (simp only:) | ||
+ | finally show "length (tl xs) = length xs - 1" | ||
+ | by this | ||
+ | qed | ||
― ‹La demostración simplificada es› | ― ‹La demostración simplificada es› | ||
Línea 177: | Línea 167: | ||
qed | qed | ||
− | text | + | text ‹Comentarios sobre la demostración anterior: |
− | |||
· "case Nil" es una abreviatura de | · "case Nil" es una abreviatura de | ||
"assume xs =[]". | "assume xs =[]". | ||
· "case Cons" es una abreviatura de | · "case Cons" es una abreviatura de | ||
"fix y ys assume xs = y#ys" | "fix y ys assume xs = y#ys" | ||
− | · ?thesis es una abreviatura de la conclusión del lema. | + | · ?thesis es una abreviatura de la conclusión del lema.› |
− | + | ||
+ | ― ‹La demostración aplicativa es› | ||
+ | lemma "length (tl xs) = length xs - 1" | ||
+ | apply (cases xs) | ||
+ | apply simp_all | ||
+ | done | ||
+ | |||
+ | ― ‹La demostración automática es› | ||
+ | lemma "length (tl xs) = length xs - 1" | ||
+ | by (cases xs) simp_all | ||
− | 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 que está definida en la teoría List de forma que (drop n xs) la | + | (drop n xs) es la lista obtenida eliminando en xs los n primeros |
− | + | elementos. Su definición es la siguiente | |
− | |||
drop_Nil: "drop n [] = []" | drop_Nil: "drop n [] = []" | ||
drop_Cons: "drop n (x#xs) = (case n of | drop_Cons: "drop n (x#xs) = (case n of | ||
0 => x#xs | | 0 => x#xs | | ||
− | Suc(m) => drop m 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 | 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. | + | xs es el mismo que eliminar los n primeros elementos del resto de xs.› |
− | |||
− | ― ‹La demostración | + | ― ‹La demostración estructurada es› |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
lemma "drop (n + 1) xs = drop n (tl xs)" | lemma "drop (n + 1) xs = drop n (tl xs)" | ||
proof (cases xs) | proof (cases xs) | ||
Línea 227: | Línea 207: | ||
qed | qed | ||
− | + | ― ‹La demostración aplicativa es› | |
+ | lemma "drop (n + 1) xs = drop n (tl xs)" | ||
+ | apply (cases xs) | ||
+ | apply simp_all | ||
+ | done | ||
− | + | ― ‹La demostración automática es› | |
− | [Principio de inducción matemática] | + | lemma "drop (n + 1) xs = drop n (tl xs)" |
+ | by (cases xs) simp_all | ||
+ | |||
+ | section ‹Inducción matemática› | ||
+ | |||
+ | text ‹[Principio de inducción matemática] | ||
Para demostrar una propiedad P para todos los números naturales basta | 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, | probar que el 0 tiene la propiedad P y que si n tiene la propiedad P, | ||
Línea 239: | Línea 228: | ||
el teorema nat.induct y puede verse con | el teorema nat.induct y puede verse con | ||
thm nat.induct | thm nat.induct | ||
− | + | › | |
− | text | + | text ‹Ejemplo de demostración por inducción: Usaremos el principio de |
− | |||
inducción matemática para demostrar que | inducción matemática para demostrar que | ||
1 + 3 + ... + (2n-1) = n^2 | 1 + 3 + ... + (2n-1) = n^2 | ||
Línea 249: | Línea 237: | ||
(suma_impares n) la suma de los n números impares. Por ejemplo, | (suma_impares n) la suma de los n números impares. Por ejemplo, | ||
suma_impares 3 = 9 | suma_impares 3 = 9 | ||
− | + | › | |
fun suma_impares :: "nat ⇒ nat" where | fun suma_impares :: "nat ⇒ nat" where | ||
Línea 257: | Línea 245: | ||
value "suma_impares 3" | value "suma_impares 3" | ||
− | text | + | text ‹ Ejemplo de demostración por inducción matemática: |
− | + | Demostrar que la suma de los n primeros números impares es n^2.› | |
− | Demostrar que la suma de los n primeros números impares es n^2. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | ― ‹Demostración del lema anterior por inducción y razonamiento | + | ― ‹Demostración estructurada del lema anterior por inducción y |
− | + | razonamiento ecuacional› | |
lemma "suma_impares n = n * n" | lemma "suma_impares n = n * n" | ||
proof (induct n) | proof (induct n) | ||
− | show "suma_impares 0 = 0 * 0" by simp | + | show "suma_impares 0 = 0 * 0" |
+ | by simp | ||
next | next | ||
fix n assume HI: "suma_impares n = n * n" | fix n assume HI: "suma_impares n = n * n" | ||
have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n" | have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n" | ||
by simp | by simp | ||
− | also have "… = (2 * (Suc n) - 1) + n * n" using HI by simp | + | also have "… = (2 * (Suc n) - 1) + n * n" |
− | also have "… = n * n + 2 * n + 1" by simp | + | using HI by simp |
− | finally show "suma_impares (Suc n) = (Suc n) * (Suc n)" by | + | also have "… = n * n + 2 * n + 1" |
+ | by simp | ||
+ | also have "… = (Suc n) * (Suc n)" | ||
+ | by simp | ||
+ | finally show "suma_impares (Suc n) = (Suc n) * (Suc n)" | ||
+ | by this | ||
qed | qed | ||
Línea 294: | Línea 272: | ||
lemma "suma_impares n = n * n" (is "?P n") | lemma "suma_impares n = n * n" (is "?P n") | ||
proof (induct n) | proof (induct n) | ||
− | show "?P 0" by simp | + | show "?P 0" |
+ | by simp | ||
next | next | ||
fix n | fix n | ||
Línea 300: | Línea 279: | ||
have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n" | have "suma_impares (Suc n) = (2 * (Suc n) - 1) + suma_impares n" | ||
by simp | by simp | ||
− | also have "… = (2 * (Suc n) - 1) + n * n" using HI by simp | + | also have "… = (2 * (Suc n) - 1) + n * n" |
− | also have "… = n * n + 2 * n + 1" by simp | + | using HI by simp |
− | finally show "?P (Suc n)" by | + | also have "… = n * n + 2 * n + 1" |
+ | by simp | ||
+ | also have "… = Suc n * Suc n" | ||
+ | by simp | ||
+ | finally show "?P (Suc n)" | ||
+ | by this | ||
qed | qed | ||
− | text | + | text ‹Comentario sobre la demostración anterior: |
− | |||
· Con la expresión | · Con la expresión | ||
"suma_impares n = n * n" (is "?P n") | "suma_impares n = n * n" (is "?P n") | ||
se abrevia "suma_impares n = n * n" como "?P n". Por tanto, | se abrevia "suma_impares n = n * n" como "?P n". Por tanto, | ||
"?P 0" es una abreviatura de "suma_impares 0 = 0 * 0" | "?P 0" es una abreviatura de "suma_impares 0 = 0 * 0" | ||
− | "?P (Suc n)" es una abreviatura de "suma_impares (Suc n) = | + | "?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 | · En general, cualquier fórmula seguida de (is patrón) equipara el | ||
− | patrón con la fórmula. | + | patrón con la fórmula. › |
− | |||
― ‹La demostración usando patrones es› | ― ‹La demostración usando patrones es› | ||
Línea 327: | Línea 309: | ||
qed | qed | ||
− | + | ― ‹La demostración aplicativa es› | |
− | + | lemma "suma_impares n = n * n" | |
− | Un número natural n es par si existe un natural m tal que n=m+m. | + | apply (induct n) |
− | + | apply simp_all | |
+ | done | ||
+ | |||
+ | ― ‹La demostración automática es› | ||
+ | lemma "suma_impares n = n * n" | ||
+ | by (induct n) simp_all | ||
+ | |||
+ | 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 | definition par :: "nat ⇒ bool" where | ||
"par n ≡ ∃m. n=m+m" | "par n ≡ ∃m. n=m+m" | ||
− | text | + | text ‹Ejemplo de inducción y existenciales: |
− | + | Demostrar que para todo número natural n, se verifica que n*(n+1) | |
− | Demostrar que para todo número natural n, se verifica que n*(n+1) par. | + | es par.› |
− | |||
− | ― ‹Demostración | + | ― ‹Demostración estructurada por inducción› |
− | lemma | + | lemma "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" | |
− | + | by (rule exE) | |
− | + | then have "(Suc n)*((Suc n)+1) = (m+n+1)+(m+n+1)" | |
− | + | by simp | |
− | + | then have "∃p. (Suc n)*((Suc n)+1) = p+p" | |
− | + | by (rule exI) | |
− | + | then show "par ((Suc n)*((Suc n)+1))" | |
− | + | by (simp add: par_def) | |
− | + | qed | |
− | |||
− | |||
− | ― ‹Demostración | + | ― ‹Demostración casi detallada por inducción› |
− | lemma | + | lemma "par (n*(n+1))" |
− | |||
− | |||
proof (induct n) | proof (induct n) | ||
− | show "par (0*(0+1))" by (simp | + | have "(0::nat) = 0 + 0" |
+ | by (simp only: add_0) | ||
+ | then have "∃m. (0::nat) = m + m" | ||
+ | by (rule exI) | ||
+ | then have "par 0" | ||
+ | by (simp only: par_def) | ||
+ | then show "par (0*(0+1))" | ||
+ | by (simp only: mult_0) | ||
next | next | ||
fix n | fix n | ||
assume "par (n*(n+1))" | assume "par (n*(n+1))" | ||
− | then have "∃m. n*(n+1) = m+m" by (simp | + | then have "∃m. n*(n+1) = m+m" |
− | then obtain m where m: "n*(n+1) = m+m" | + | by (simp only: par_def) |
− | then have "(Suc n)*((Suc n)+1) = (m+n+1)+(m+n+1)" by | + | then obtain m where m: "n*(n+1) = m+m" |
− | then have " | + | by (rule exE) |
− | then show "par ((Suc n)*((Suc n)+1))" by (simp | + | then have "(Suc n)*((Suc n)+1) = (m+n+1)+(m+n+1)" |
+ | by simp | ||
+ | then have "∃p. (Suc n)*((Suc n)+1) = p+p" | ||
+ | by (rule exI) | ||
+ | then show "par ((Suc n)*((Suc n)+1))" | ||
+ | by (simp only: par_def) | ||
qed | qed | ||
− | + | ― ‹Demostración aplicativa por inducción› | |
− | + | lemma "par (n*(n+1))" | |
− | + | apply (induct n) | |
− | + | apply (simp add: par_def) | |
+ | apply (simp add: par_def) | ||
+ | apply arith | ||
+ | done | ||
+ | |||
+ | ― ‹Demostración automática› | ||
+ | lemma "par (n*(n+1))" | ||
+ | by (induct n) (auto simp add: par_def, arith) | ||
− | text | + | 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" | |
− | usando en lugar de la función "par" la función "even" definida en la | + | definida en la teoría Parity por |
− | + | even x ⟷ x mod 2 = 0 › | |
− | even x ⟷ x mod 2 = 0 | ||
− | |||
lemma | lemma | ||
fixes n :: "nat" | fixes n :: "nat" | ||
shows "even (n*(n+1))" | shows "even (n*(n+1))" | ||
− | by auto | + | by auto |
− | text | + | text ‹Comentarios sobre la demostración anterior: |
− | |||
· Para poder usar la función "even" de la librería Parity es necesario | · 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 | importar dicha librería. Por ello, antes del inicio de la teoría | ||
aparece | aparece | ||
− | imports Main Parity | + | imports Main HOL.Parity |
− | + | › | |
− | text | + | text ‹Para completar la demostración basta demostrar la equivalencia de |
− | + | las funciones "par" y "even".› | |
− | funciones "par" y "even". | ||
− | |||
− | lemma | + | lemma "par n = even n" |
− | |||
− | |||
proof - | proof - | ||
− | have "par n = (∃m. n = m+m)" by (simp | + | have "par n = (∃m. n = m+m)" |
− | then show "par n = even n" by presburger | + | by (simp only: par_def) |
+ | then show "par n = even n" | ||
+ | (* try *) | ||
+ | by presburger | ||
qed | qed | ||
− | text | + | text ‹Comentarios sobre la demostración anterior: |
− | |||
· "by presburger" indica que se use como método de demostración el | · "by presburger" indica que se use como método de demostración el | ||
− | algoritmo de decisión de la aritmética de Presburger. | + | algoritmo de decisión de la aritmética de Presburger.› |
− | |||
− | + | ― ‹Demostración declarativa› | |
− | + | lemma "par n = even n" | |
− | + | apply (unfold par_def) | |
− | + | apply presburger | |
− | + | done | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | ― | ||
− | lemma | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ― ‹Demostración automática› | |
− | + | lemma "par n = even n" | |
− | + | by (simp only: par_def, presburger) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | ― | ||
− | lemma | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | by (simp | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | section | + | section ‹Recursión general. La función de Ackermann› |
− | text | + | 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 | |
− | 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 de Ackermann (se puede consultar información sobre dicha función en | + | función en http://en.wikipedia.org/wiki/Ackermann_function). |
− | |||
Definición. La función de Ackermann se define por | Definición. La función de Ackermann se define por | ||
Línea 619: | Línea 443: | ||
para todo los números naturales. | para todo los números naturales. | ||
− | La función de Ackermann es recursiva, pero no es primitiva recursiva. | + | La función de Ackermann es recursiva, pero no es primitiva recursiva.› |
− | |||
fun ack :: "nat ⇒ nat ⇒ nat" where | fun ack :: "nat ⇒ nat ⇒ nat" where | ||
Línea 630: | Línea 453: | ||
value "ack 2 3" (* devuelve 9 *) | 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 | · Al definir una función recursiva general se genera una regla de | ||
inducción. En la definición anterior, la regla generada es | inducción. En la definición anterior, la regla generada es | ||
Línea 639: | Línea 461: | ||
⋀m n. ⟦P (Suc m) n; P m (ack (Suc m) n)⟧ ⟹ P (Suc m) (Suc n)⟧ | ⋀m n. ⟦P (Suc m) n; P m (ack (Suc m) n)⟧ ⟹ P (Suc m) (Suc n)⟧ | ||
⟹ P a b | ⟹ P a b | ||
− | + | › | |
− | text | + | 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. | + | Demostrar que para todos m y n, A(m,n) > n.› |
− | |||
― ‹La demostración detallada es› | ― ‹La demostración detallada es› | ||
Línea 650: | Línea 471: | ||
proof (induct m n rule: ack.induct) | proof (induct m n rule: ack.induct) | ||
fix n | fix n | ||
− | show "ack 0 n > n" by simp | + | show "ack 0 n > n" |
+ | by (simp only: ack.simps(1)) | ||
next | next | ||
fix m | fix m | ||
assume "ack m 1 > 1" | assume "ack m 1 > 1" | ||
− | then show "ack (Suc m) 0 > 0" by simp | + | then show "ack (Suc m) 0 > 0" |
+ | by (simp only: ack.simps(2)) | ||
next | next | ||
fix m n | fix m n | ||
− | assume "n < ack (Suc m) n" and | + | 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 | + | then show "Suc n < ack (Suc m) (Suc n)" |
+ | by (simp only: ack.simps(3)) | ||
qed | qed | ||
− | text | + | text ‹Comentarios sobre la demostración anterior: |
− | |||
· (induct m n rule: ack.induct) indica que el método de demostración | · (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 | es el esquema de recursión correspondiente a la definición de | ||
Línea 673: | Línea 496: | ||
ack (Suc m) n < ack m (ack (Suc m) n)⟧ | ack (Suc m) n < ack m (ack (Suc m) n)⟧ | ||
⟹ Suc n < ack (Suc m) (Suc n) | ⟹ Suc n < ack (Suc m) (Suc n) | ||
− | + | › | |
― ‹La demostración automática es› | ― ‹La demostración automática es› | ||
lemma "ack m n > n" | lemma "ack m n > n" | ||
− | by (induct m n rule: ack.induct) auto | + | by (induct m n rule: ack.induct) auto |
end | end | ||
</source> | </source> |
Revisión actual del 19:00 6 may 2020
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 aplicativa es›
lemma "¬A ∨ A"
apply cases
apply simp_all
done
― ‹La demostración automática es›
lemma "¬A ∨ A"
by cases simp_all
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
then show "¬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 estructurada es›
lemma "length (tl xs) = length xs - 1"
proof (cases xs)
assume "xs = []"
then have "length (tl xs) = 0"
by simp
also have "… = 0 - 1"
by simp
also have "… = length xs - 1"
using ‹xs = []›
by simp
finally show "length (tl xs) = length xs - 1"
by this
next
fix y ys
assume "xs = y#ys"
then have "length (tl xs) = length ys"
by simp
also have "… = (1 + length ys) - 1"
by simp
also have "… = length (y#ys) - 1"
by simp
also have "… = length xs - 1"
using ‹xs = y#ys›
by simp
finally show "length (tl xs) = length xs - 1"
by this
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 detallada es›
lemma "length (tl xs) = length xs - 1"
proof (cases xs)
assume "xs = []"
then have "length (tl xs) = 0"
by (simp only: list.sel(2)
list.size(3))
also have "… = 0 - 1"
by (simp only: natural_zero_minus_one)
also have "… = length xs - 1"
using ‹xs = []›
by (simp only: list.size(3))
finally show "length (tl xs) = length xs - 1"
by this
next
fix y ys
assume "xs = y#ys"
then have "length (tl xs) = length ys"
by (simp only: list.sel(3))
also have "… = length (y#ys) - 1"
by (simp only: length_Cons)
also have "… = length xs - 1"
using ‹xs = y#ys›
by (simp only:)
finally show "length (tl xs) = length xs - 1"
by this
qed
― ‹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 demostració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 aplicativa es›
lemma "length (tl xs) = length xs - 1"
apply (cases xs)
apply simp_all
done
― ‹La demostración automática es›
lemma "length (tl xs) = length xs - 1"
by (cases xs) simp_all
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) es 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 estructurada 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 aplicativa es›
lemma "drop (n + 1) xs = drop n (tl xs)"
apply (cases xs)
apply simp_all
done
― ‹La demostración automática es›
lemma "drop (n + 1) xs = drop n (tl xs)"
by (cases xs) simp_all
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 estructurada 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
also have "… = (Suc n) * (Suc n)"
by simp
finally show "suma_impares (Suc n) = (Suc n) * (Suc n)"
by this
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
also have "… = Suc n * Suc n"
by simp
finally show "?P (Suc n)"
by this
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 aplicativa es›
lemma "suma_impares n = n * n"
apply (induct n)
apply simp_all
done
― ‹La demostración automática es›
lemma "suma_impares n = n * n"
by (induct n) simp_all
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)
es par.›
― ‹Demostración estructurada por inducción›
lemma "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"
by (rule exE)
then have "(Suc n)*((Suc n)+1) = (m+n+1)+(m+n+1)"
by simp
then have "∃p. (Suc n)*((Suc n)+1) = p+p"
by (rule exI)
then show "par ((Suc n)*((Suc n)+1))"
by (simp add: par_def)
qed
― ‹Demostración casi detallada por inducción›
lemma "par (n*(n+1))"
proof (induct n)
have "(0::nat) = 0 + 0"
by (simp only: add_0)
then have "∃m. (0::nat) = m + m"
by (rule exI)
then have "par 0"
by (simp only: par_def)
then show "par (0*(0+1))"
by (simp only: mult_0)
next
fix n
assume "par (n*(n+1))"
then have "∃m. n*(n+1) = m+m"
by (simp only: par_def)
then obtain m where m: "n*(n+1) = m+m"
by (rule exE)
then have "(Suc n)*((Suc n)+1) = (m+n+1)+(m+n+1)"
by simp
then have "∃p. (Suc n)*((Suc n)+1) = p+p"
by (rule exI)
then show "par ((Suc n)*((Suc n)+1))"
by (simp only: par_def)
qed
― ‹Demostración aplicativa por inducción›
lemma "par (n*(n+1))"
apply (induct n)
apply (simp add: par_def)
apply (simp add: par_def)
apply arith
done
― ‹Demostración automática›
lemma "par (n*(n+1))"
by (induct n) (auto simp add: par_def, arith)
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 HOL.Parity
›
text ‹Para completar la demostración basta demostrar la equivalencia de
las funciones "par" y "even".›
lemma "par n = even n"
proof -
have "par n = (∃m. n = m+m)"
by (simp only: par_def)
then show "par n = even n"
(* try *)
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.›
― ‹Demostración declarativa›
lemma "par n = even n"
apply (unfold par_def)
apply presburger
done
― ‹Demostración automática›
lemma "par n = even n"
by (simp only: par_def, presburger)
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 only: ack.simps(1))
next
fix m
assume "ack m 1 > 1"
then show "ack (Suc m) 0 > 0"
by (simp only: ack.simps(2))
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 only: ack.simps(3))
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