Añadidos inductivos, finitud y naturales
Some checks failed
Lean Action CI / build (push) Has been cancelled
Some checks failed
Lean Action CI / build (push) Has been cancelled
This commit is contained in:
parent
12d608d061
commit
899adc8f53
106
Curso2026/Finitud.lean
Normal file
106
Curso2026/Finitud.lean
Normal file
@ -0,0 +1,106 @@
|
||||
import Mathlib.Tactic
|
||||
|
||||
open Set
|
||||
/-
|
||||
# Conjuntos y tipos finitos
|
||||
|
||||
En Lean hay varias nociones de finitud (en parte porque en las propias matemáticas también las hay):
|
||||
- Tipos finitos (`Fintype`)
|
||||
- Conjuntos finitos (`Finset`)
|
||||
- Tipos ordinarios que tienen la propiedad de ser finitos (`Finite`)
|
||||
- Conjuntos ordinarios que tienen la propiedad de ser finitos (`Set.Finite`)
|
||||
- ...
|
||||
|
||||
De momento vamos a centrarnos sólo en los dos últimos casos, es decir, vamos a trabajar
|
||||
con conjuntos o tipos como antes, pero usaremos en ocasiones la propiedad de que son finitos
|
||||
|
||||
Que un tipo sea finito quiere decir que es biyectivo con {0,1,..,n} para algún n. Que un
|
||||
conjunto sea finito quiere decir que su correspondiente tipo sea finito.
|
||||
-/
|
||||
|
||||
|
||||
-- un conjunto es finito si y sólo si su tipo correspondiente es finito
|
||||
|
||||
lemma tipo_finito_sii_conjunto_finito (X : Type) (S : Set X) : Finite ↥S ↔ Set.Finite S := by
|
||||
exact finite_coe_iff
|
||||
|
||||
|
||||
-- un conjunto es finito si y sólo si es biyectivo con {0,1,...,n} para algún natural n
|
||||
|
||||
lemma Set_Finite_iff_bijective_fin_n (X : Type) ( S : Set X) : Set.Finite S ↔ ∃ n : ℕ, ∃ (a : ↥S → (Fin n)), Function.Bijective a := by
|
||||
rw [← tipo_finito_sii_conjunto_finito]
|
||||
fconstructor
|
||||
. intro h
|
||||
cases' h with n hn
|
||||
use n
|
||||
use hn
|
||||
exact Equiv.bijective hn
|
||||
. intro h
|
||||
cases' h with n hn
|
||||
cases' hn with a ha
|
||||
fconstructor
|
||||
· use n
|
||||
· apply Equiv.ofBijective a ha
|
||||
|
||||
|
||||
|
||||
/-
|
||||
Una propiedad importante es que los conjuntos finitos tienen principio de inducción:
|
||||
si una propiedad es cierta para el conjunto vacío, y si es cierta para un conjunto finito
|
||||
entonceses cierta para el conjunto obtenido añadiendo un elemento, entonces es cierta
|
||||
para cualquier conjunto finito.
|
||||
|
||||
Veamos el ejemplo de lo que ocurre con la unión de cerrados en una topología
|
||||
-/
|
||||
|
||||
example
|
||||
(X : Type)
|
||||
(P : Set X → Prop)
|
||||
(hu : ∀ A B : Set X, P A → P B → P (A ∪ B))
|
||||
(S : Set (Set X))
|
||||
(hSI : ∀ x ∈ S, P x)
|
||||
(h0 : P ∅ )
|
||||
(hfin : Set.Finite S) :
|
||||
P (⋃₀ S) := by
|
||||
|
||||
revert hSI -- esto es necesario porque queremos "arrastrar" la hipótesis a la inducción
|
||||
induction' S, hfin using Set.Finite.induction_on with a T ha hT huT hSI
|
||||
. simp only [Set.sUnion_empty]
|
||||
intro h
|
||||
exact h0
|
||||
. simp only [Set.sUnion_insert]
|
||||
intro h
|
||||
apply hu
|
||||
. apply h
|
||||
left
|
||||
rfl
|
||||
· apply huT
|
||||
intro x hx
|
||||
apply h
|
||||
right
|
||||
exact hx
|
||||
|
||||
-- Para ver el recíproco, símplemente hay que ver que los conjuntos de dos elementos son finitos
|
||||
|
||||
|
||||
example (X : Type) (a b : X) : Set.Finite ({a, b} : Set X) := by
|
||||
exact toFinite {a, b}
|
||||
|
||||
-- y que la unión de dos conjuntos es lo mismo que la unión del conjunto formado por ambos
|
||||
|
||||
example (X : Type) (a b : Set X) : a ∪ b = ⋃₀ ({a , b} : Set (Set X)) := by
|
||||
rw [sUnion_insert]
|
||||
rw [sUnion_singleton]
|
||||
|
||||
|
||||
/-
|
||||
# Ejercicio
|
||||
|
||||
Demuestra que todo conjunto finito no vacío de los naturales tiene un elemento maximal
|
||||
|
||||
(puede ser útil la ráctica `linarith`, que intenta demostrar (des)igualdades que se puedan deducir
|
||||
mediante operaciones lineales)
|
||||
-/
|
||||
|
||||
example ( S : Set ℕ ) (hf : Set.Finite S) : S ≠ ∅ → ∃ m ∈ S, ∀ n ∈ S, n ≤ m := by
|
||||
sorry
|
||||
187
Curso2026/Inductivos.lean
Normal file
187
Curso2026/Inductivos.lean
Normal file
@ -0,0 +1,187 @@
|
||||
import Mathlib.Tactic
|
||||
|
||||
/-
|
||||
# Tipos inductivos
|
||||
|
||||
Los tipos inductivos son tipos en los que cada objeto se obtiene mediante una o varias
|
||||
funciones. Estas funciones pueden no tomar ninguna entrada (casos primitivos) o pueden tomar
|
||||
como entradas otros objetos de ese mismo tipo.
|
||||
|
||||
El ejemplo más habitual es el de los números naturales: cada número natural es uno (y sólo uno)
|
||||
de estos casos:
|
||||
- El número 0.
|
||||
- El siguiente de otro número natural.
|
||||
|
||||
Y además, usando estas funciones, se obtienen exactamente todos los naturales: 1 es el siguiente de 0
|
||||
2 es el siguiente de 1...
|
||||
|
||||
Podemos definir el tipo de los naturales así:
|
||||
-/
|
||||
|
||||
|
||||
inductive natural
|
||||
| cero : natural
|
||||
| siguiente : natural → natural
|
||||
|
||||
open natural
|
||||
|
||||
instance : Zero natural := { zero := cero }
|
||||
|
||||
-- a partir de ahora, podemos usar "cero" y "siguiente" en lugar de "natural.cero" y "natural.siguiente"
|
||||
|
||||
|
||||
|
||||
/-
|
||||
Se pueden definir funciones (o demostrar teoremas) sobre un tipo inductivo, diciendo
|
||||
como proceder en cada uno de sus casos:
|
||||
-/
|
||||
|
||||
def suma : natural → natural → natural
|
||||
| n, 0 => n
|
||||
| n, siguiente m => siguiente (suma n m)
|
||||
|
||||
|
||||
|
||||
/-
|
||||
Esto lo hacemos para poder usar "a + b" en lugar de "suma a b"
|
||||
-/
|
||||
|
||||
instance : Add natural := { add := suma }
|
||||
|
||||
@[simp]
|
||||
lemma suma_cero (n : natural) : n + 0 = n := by
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
lemma suma_siguiente ( n m : natural) : n + (siguiente m) = siguiente ( n + m ) := by
|
||||
rfl
|
||||
|
||||
|
||||
/-
|
||||
Con tipos inductivos, se puede usar el principio de inducción: demostrando el teorema
|
||||
para cada posible forma de construir un elemento del tipo, usando la hipótesis de que
|
||||
el teorema es cierto para los objetos que se usan en la construcción.
|
||||
|
||||
Por definición tenemos que n + 0 = n, veamos que 0 + n = n
|
||||
-/
|
||||
|
||||
@[simp]
|
||||
lemma cerosuma (n : natural) : 0 + n = n := by
|
||||
induction' n with n h -- como lo queremos ver para todo n, veamos los posibles casos
|
||||
· rfl
|
||||
· rw [suma_siguiente] -- aplicamos la definición de suma de un siguiente
|
||||
rw [h]
|
||||
|
||||
/-
|
||||
Veamos algunas propiedades más de la suma de naturales
|
||||
-/
|
||||
|
||||
@[simp]
|
||||
lemma sigsuma (n m : natural) : (siguiente n) + m = siguiente (n + m) := by
|
||||
induction' m with m h
|
||||
· rfl
|
||||
· rw [suma_siguiente]
|
||||
rw [h]
|
||||
rw [suma_siguiente]
|
||||
|
||||
|
||||
/-
|
||||
Usando lo anterior, podemos demostrar que la suma es conmutativa
|
||||
-/
|
||||
|
||||
lemma sumacomm (n m : natural) : n + m = m + n := by
|
||||
induction' n with n h
|
||||
· change 0 + m = m + 0
|
||||
simp only [suma_cero, eq_self_iff_true, cerosuma]
|
||||
· simp only [sigsuma, suma_siguiente, h ]
|
||||
|
||||
|
||||
/-
|
||||
Y asociativa
|
||||
-/
|
||||
|
||||
@[simp]
|
||||
lemma sumaasoc (a b c : natural) : a + (b + c) = a + b + c:= by
|
||||
induction' c with c h
|
||||
· rfl
|
||||
· simp only [suma_siguiente, h]
|
||||
|
||||
/-
|
||||
# Ejercicios
|
||||
|
||||
Define el producto de números naturales, y demuestra algunas de sus propiedades:
|
||||
|
||||
- Multiplicar por cero (a derecha e izquierda) da cero.
|
||||
- El uno (siguiente del cero), es elemento neutro del producto (a derecha e izquierda)
|
||||
- La propuedad distributiva
|
||||
-/
|
||||
|
||||
|
||||
def mul : natural → natural → natural
|
||||
| n, cero => sorry
|
||||
| n, (siguiente m ) => sorry
|
||||
|
||||
instance : Mul natural := ⟨ mul⟩
|
||||
|
||||
@[simp]
|
||||
lemma mul_cero (n : natural) : n * 0 = 0 := by
|
||||
sorry
|
||||
|
||||
@[simp]
|
||||
lemma mul_siguiente (n m : natural) : n * siguiente m = n * m + n := by
|
||||
sorry
|
||||
|
||||
@[simp]
|
||||
lemma mulcero (n : natural ) : 0 * n = 0 := by
|
||||
sorry
|
||||
|
||||
def uno := siguiente cero
|
||||
|
||||
instance : One natural := ⟨ uno⟩
|
||||
|
||||
@[simp]
|
||||
lemma muluno (n : natural ) : n * 1 = n := by
|
||||
sorry
|
||||
|
||||
@[simp]
|
||||
lemma unomul (n : natural ) : 1 * n = n := by
|
||||
sorry
|
||||
|
||||
@[simp]
|
||||
lemma mul_suma (a b c : natural) : a * (b + c) = a * b + a * c := by
|
||||
sorry
|
||||
|
||||
/-
|
||||
Aquí puede ser útil la tática `calc`, que permite razonar (des)igualdades en varios pasos
|
||||
justificando cada paso.
|
||||
|
||||
Por ejemplo, si estamos en un momento en que hay que demostrar que
|
||||
`a * c + b * c + a + b = a * c + a + b * c + b ` se puede hacer así:
|
||||
|
||||
|
||||
calc
|
||||
a * c + b * c + a + b = a * c + (b * c + a) + b := by simp
|
||||
_ = a * c + (a + b * c)+ b := by rw [sumacomm a (b *c)]
|
||||
_ = a * c + a + b * c + b := by simp
|
||||
|
||||
-/
|
||||
@[simp]
|
||||
lemma suma_mul (a b c : natural) : (a + b) * c = a * c + b * c := by
|
||||
sorry
|
||||
|
||||
|
||||
/-
|
||||
# Nota:
|
||||
|
||||
Los números naturales ya vienen definidos de serie en lean como el tipo `nat`,y muchas de sus propiedades
|
||||
están demostradas en mathlib. Además, viene de serie con varias notaciones útiles, se pueden
|
||||
usar los numerales habituales, etc.
|
||||
-/
|
||||
|
||||
|
||||
/-
|
||||
# Ejercicio extra
|
||||
|
||||
Define algún otro tipo inductivo. Por ejemplo, las listas de números naturales. Piensa que una lista
|
||||
es o bien la lista vacía, o bien el resultado de añadir un elemento a una lista más corta.
|
||||
-/
|
||||
161
Curso2026/Naturales.lean
Normal file
161
Curso2026/Naturales.lean
Normal file
@ -0,0 +1,161 @@
|
||||
import Mathlib.Tactic
|
||||
|
||||
|
||||
open Finset Nat
|
||||
|
||||
|
||||
/-
|
||||
# Números naturales
|
||||
|
||||
Vamos a hacer algunos ejercicios sobre propiedades de los naturales.
|
||||
La principal herramienta que vamos a usar es la inducción. Para ello aplicaremos la
|
||||
táctica `induction`.
|
||||
|
||||
Usaremos la notación de sumatorios. Por ejemplo, la expresión `∑ i in range (n), i^2`
|
||||
representa la suma de los cuadrados de los números `0,1,..,(n-1)`. De hecho, puede aplicarse
|
||||
a cualquier `finset` (de momento, quedémonos con que es otra noción de conjunto finito).
|
||||
La función `range` devuelve el finset correspondiente al número que se le pase
|
||||
|
||||
Lo que vamos a usar fundamentalmente es un lema llamado `sum_range_succ` que permite separar
|
||||
el último término de una suma. Otros resultados que pueden ser útiles son `sum_range_one` y
|
||||
`sum_range_zero`.
|
||||
|
||||
Tamién es útil, cuando queremos demostrar igualdades que se obtienen símplemente
|
||||
manipulando sumas y productos en un anillo, usar la táctica `ring`.
|
||||
-/
|
||||
|
||||
-- Demostremos la fórmula para la suma de los cubos de los primeros números
|
||||
lemma ejer1 ( n : ℕ ) : (∑ i ∈ range (n + 1), i ^3) * 4 = ((n * (n + 1) ))^2 := by
|
||||
induction' n with n hind -- aplicamos inducción sobre n
|
||||
· rfl -- caso n = 0 se cumple por definición ·
|
||||
· rw [sum_range_succ] -- separamos el último sumando del sumatorio
|
||||
rw [add_mul] -- aplicamos la distributiva, para tener exactamente
|
||||
-- la misma expresión que en la hipótesis de inducción
|
||||
rw [hind] -- aplicamos la hipótesis de inducción
|
||||
ring -- y operamos en la expresión
|
||||
-- Ahora podemos usar el anterior ejercicio para despejar el `4`
|
||||
lemma ejer1' ( n : ℕ ) : (∑ i ∈ range (n.succ), i ^3) = (n *(n + 1)) ^ 2 / 4 := by
|
||||
have h1 := ejer1 n
|
||||
have h4m : 4 > 0
|
||||
· linarith
|
||||
rw [← h1]
|
||||
simp
|
||||
|
||||
-- Dar esta vuelta puede parecer distinto a lo que haríamos normalmente con papel
|
||||
-- y lápiz. Esto es porque nos estamos restringiendo a operaciones entre números
|
||||
-- naturales, y en este contexto la divión `/` es la división con resto.
|
||||
|
||||
-- Si quisiéramos hacerlo en el espíritu usual de las matemáticas, debemos llevarnos
|
||||
-- el problema al contexto de los racionales
|
||||
|
||||
lemma ejer1_racional (n : ℕ ) : ((∑ i ∈ range (n.succ), i ^3): ℚ) = (n *(n + 1)) ^ 2 / 4 := by
|
||||
induction' n with n hind
|
||||
· simp
|
||||
· rw [sum_range_succ] -- separar el último término de la suma
|
||||
rw [hind] -- aplicar la hipótesis de inducción
|
||||
simp -- convertimos los sucesores en sumas
|
||||
ring -- para poder aplicar la simplificación de expresiones en un anillo
|
||||
|
||||
-- # Ejercicios
|
||||
|
||||
-- demuestra que el producto de dos números consecutivos es par
|
||||
-- puedes usar el hecho de que todo natural es par o impar (`nat.even_or_odd`)
|
||||
-- también se puede hacer por inducción
|
||||
|
||||
lemma prod_consec_par (n : ℕ ) : 2 ∣ (n * (n + 1)) := by
|
||||
sorry,
|
||||
|
||||
/-
|
||||
Demostrar la fórmula para la suma de los primeros números naturales.
|
||||
Primero como igualdad en los racionales:
|
||||
|
||||
-/
|
||||
|
||||
lemma suma_primeros_en_Q ( n : ℕ ) : (∑ i ∈ range n, i : ℚ ) = n * (n - 1) / 2 := by
|
||||
sorry
|
||||
|
||||
/-
|
||||
Ahora como igualdad en los naturales, igual es más fácil hacerlo primero quitando
|
||||
denominadores.
|
||||
-/
|
||||
|
||||
lemma suma_primeros_en_N_2 ( n : ℕ ) : 2 * (∑ i ∈ range n, i) = n * (n - 1) := by
|
||||
sorry
|
||||
|
||||
/-
|
||||
y luego usar lo anterior para obtener la fórmula con fracciones
|
||||
-/
|
||||
|
||||
lemma suma_primeros_en_N (n : ℕ ) : (∑ i ∈ range n, i) = n * (n - 1) / 2 := by
|
||||
sorry
|
||||
|
||||
|
||||
/-
|
||||
# Ejemplos con Fibonaci
|
||||
|
||||
Demostremos ahora algunas propiedades de la sucesión de Fibonaci. Empezamos definiendola
|
||||
recursivamente:
|
||||
-/
|
||||
def Fib : ℕ → ℕ
|
||||
| 0 => 0
|
||||
| 1 => 1
|
||||
| (n + 2) => Fib n + Fib (n +1)
|
||||
|
||||
|
||||
/-
|
||||
Veamos que dos términos consecutivos son coprimos
|
||||
-/
|
||||
lemma cons_fib_coprimos (n : ℕ ) : Nat.gcd (Fib n) (Fib (n + 1)) = 1 := by
|
||||
induction' n with n h
|
||||
· simp [Fib]
|
||||
· cases' n with n
|
||||
· simp [Fib]
|
||||
· simp [Fib] at *
|
||||
rw [Nat.gcd_comm]
|
||||
exact h
|
||||
/-
|
||||
Marcamos los siguientes resultados como `@[simp]` para que la táctica `simp` los use.
|
||||
-/
|
||||
|
||||
@[simp]
|
||||
lemma fib0 : Fib 0 = 0 := by rfl
|
||||
|
||||
@[simp]
|
||||
lemma fib1 : Fib 1 = 1 := by rfl
|
||||
|
||||
@[simp]
|
||||
lemma fib2 : Fib 2 = 1 := by rfl
|
||||
|
||||
@[simp]
|
||||
lemma fib2a (n : ℕ) : Fib (2 + n) = Fib (n) + Fib (1 + n) := by
|
||||
rw [add_comm,Fib]
|
||||
ring_nf
|
||||
|
||||
@[simp]
|
||||
lemma fib_suma (m n : ℕ) :
|
||||
Fib (m + n + 1) = Fib m * Fib n + Fib (m + 1) * Fib (n + 1) := by
|
||||
induction' n with n ih generalizing m
|
||||
· simp
|
||||
· specialize ih (m+1)
|
||||
ring_nf at *
|
||||
rw [ih]
|
||||
simp
|
||||
ring
|
||||
|
||||
/-
|
||||
Aquí podemos ver un ejemplo de usar la táctica `calc`
|
||||
Veamos que la función de fibonacci respeta divisibilidad
|
||||
(notar que el símbolo de dividir `∣` es distinto del que
|
||||
se usa para definir conjuntos: `\|` frente a `|` )
|
||||
-/
|
||||
lemma fib_div (n r : ℕ ) : Fib n ∣ Fib (n * r) := by
|
||||
cases' n with n
|
||||
· simp
|
||||
· induction' r with r ih
|
||||
· simp
|
||||
· choose a1 ha1 using ih
|
||||
use (a1 * Fib (n ) + Fib ((n + 1) * r + 1))
|
||||
calc Fib ((n + 1) * (r + 1)) = Fib ((n + 1) * r + n + 1) := by ring_nf
|
||||
_ = Fib ((n + 1) * r) * Fib n + Fib ((n + 1) * r + 1) * Fib (n + 1) := by rw [fib_suma]
|
||||
_ = Fib (n + 1) * a1 * Fib n + Fib ((n + 1) * r + 1) * Fib (n + 1) := by rw [ha1]
|
||||
_ = Fib (n + 1) * (a1 * Fib n + Fib ((n + 1) * r + 1)) := by ring
|
||||
Loading…
Reference in New Issue
Block a user