---
title: Pruebas de equivalencia de definiciones de la función de Fibonacci
date: 2024-08-29 06:00:00 UTC+02:00
category: Inducción
has_math: true
---

[mathjax]

En Lean4, se puede definir la función de Fibonacci por
<pre lang="haskell">
   def fibonacci : Nat → Nat
     | 0     => 0
     | 1     => 1
     | n + 2 => fibonacci n + fibonacci (n+1)
</pre>

Otra definición más eficiente es
<pre lang="haskell">
   def fib (n : Nat) : Nat :=
     (aux n).1
   where
     aux : Nat → Nat × Nat
       | 0   => (0, 1)
       | n + 1 =>
         let p := aux n
         (p.2, p.1 + p.2)
</pre>

Demostrar que ambas definiciones son equivalentes; es decir,
<pre lang="haskell">
   fibonacci = fib
</pre>

Para ello, completar la siguiente teoría de Lean4:

<pre lang="lean">
open Nat

-- Para que no use la notación con puntos
set_option pp.fieldNotation false

def fibonacci : Nat → Nat
  | 0     => 0
  | 1     => 1
  | n + 2 => fibonacci n + fibonacci (n+1)

def fib (n : Nat) : Nat :=
  (aux n).1
where
  aux : Nat → Nat × Nat
    | 0   => (0, 1)
    | n + 1 =>
      let p := aux n
      (p.2, p.1 + p.2)

example : fibonacci = fib :=
by sorry
</pre>
<!--more-->

<h2>1. Demostración en lenguaje natural</h2>

En la demostración usaremos el siguiente lema auxiliar
<pre lang="haskell">
   fib_suma (n : Nat) : fib (n + 2) = fib n + fib (n + 1)
</pre>

Tenemos que demostrar que, para todo n ∈ ℕ,
<pre lang="haskell">
   fibonacci n = fib n
</pre>
Lo probaremos por inducción en n.

**Caso 1**: Supongamos que n = 0. Entonces,

    fibonacci n = fibonacci 0
                = 1

y

    fib n = fib 0
          = (aux 0).1
          = (0, 1).1
          = 1

Por tanto,

    fibonacci n = fib n

**Caso 2**: Supongamos que n = 1. Entonces,

    fibonacci n = 1

y

    fib 1 = (aux 1).1
          = (p.2, p.1 + p.2).1
            donde p = aux 0
          = ((0, 1).2, (0, 1).1 + (0, 1).2).1
          = (1, 0 + 1).1
          = 1

**Caso 3**: Supongamos que n = m + 2 y que se verifica las hipótesis de inducción,
<pre lang="haskell">
   HI1 : fibonacci n = fib n
   HI2 : fibonacci (n + 1) = fib (n + 1)
</pre>

Entonces,

    fibonacci n
    = fibonacci (m + 2)
    = fibonacci m + fibonacci (m + 1)
    = fib m + fib (m + 1)                [por HI1, HI2]
    = fib (m + 2)                        [por fib_suma]
    = fib n

<h2>2. Demostraciones con Lean4</h2>

<pre lang="lean">
open Nat

-- Para que no use la notación con puntos
set_option pp.fieldNotation false

def fibonacci : Nat → Nat
  | 0     => 0
  | 1     => 1
  | n + 2 => fibonacci n + fibonacci (n+1)

def fib (n : Nat) : Nat :=
  (aux n).1
where
  aux : Nat → Nat × Nat
    | 0   => (0, 1)
    | n + 1 =>
      let p := aux n
      (p.2, p.1 + p.2)

-- Lema auxiliar
-- =============

theorem fib_suma (n : Nat) : fib (n + 2) = fib n + fib (n + 1) :=
by rfl

-- 1ª demostración
-- ===============

example : fibonacci = fib :=
by
  ext n
  -- n : Nat
  -- ⊢ fibonacci n = fib n
  induction n using fibonacci.induct with
  | case1 =>
    -- ⊢ fibonacci 0 = fib 0
    rfl
  | case2 =>
    -- ⊢ fibonacci 1 = fib 1
    rfl
  | case3 n HI1 HI2 =>
    -- n : Nat
    -- HI1 : fibonacci n = fib n
    -- HI2 : fibonacci (n + 1) = fib (n + 1)
    -- ⊢ fibonacci (succ (succ n)) = fib (succ (succ n))
    rw [fib_suma]
    -- ⊢ fibonacci (succ (succ n)) = fib n + fib (n + 1)
    rw [fibonacci]
    -- ⊢ fibonacci n + fibonacci (n + 1) = fib n + fib (n + 1)
    rw [HI1]
    -- ⊢ fib n + fibonacci (n + 1) = fib n + fib (n + 1)
    rw [HI2]

-- 2ª demostración
-- ===============

example : fibonacci = fib :=
by
  ext n
  -- n : Nat
  -- ⊢ fibonacci n = fib n
  induction n using fibonacci.induct with
  | case1 =>
    -- ⊢ fibonacci 0 = fib 0
    rfl
  | case2 =>
    -- ⊢ fibonacci 1 = fib 1
    rfl
  | case3 n HI1 HI2 =>
    -- n : Nat
    -- HI1 : fibonacci n = fib n
    -- HI2 : fibonacci (n + 1) = fib (n + 1)
    -- ⊢ fibonacci (succ (succ n)) = fib (succ (succ n))
    calc fibonacci (succ (succ n))
         = fibonacci n + fibonacci (n + 1) := by rw [fibonacci]
       _ = fib n + fib (n + 1)             := by rw [HI1, HI2]
       _ = fib (succ (succ n))             := by rw [fib_suma]

-- 3ª demostración
-- ===============

example : fibonacci = fib :=
by
  ext n
  -- n : Nat
  -- ⊢ fibonacci n = fib n
  induction n using fibonacci.induct with
  | case1 =>
    -- ⊢ fibonacci 0 = fib 0
    rfl
  | case2 =>
    -- ⊢ fibonacci 1 = fib 1
    rfl
  | case3 n HI1 HI2 =>
    -- n : Nat
    -- HI1 : fibonacci n = fib n
    -- HI2 : fibonacci (n + 1) = fib (n + 1)
    -- ⊢ fibonacci (succ (succ n)) = fib (succ (succ n))
    simp [HI1, HI2, fibonacci, fib_suma]
</pre>

Se puede interactuar con las demostraciones anteriores en [Lean 4 Web](https://live.lean-lang.org/#url=https://raw.githubusercontent.com/jaalonso/Calculemus2_es/main/src/Fibonacci.lean).

<h2>3. Demostraciones con Isabelle/HOL</h2>

<pre lang="isar">
theory Fibonacci
imports Main
begin

fun fibonacci :: "nat ⇒ nat"
  where
    "fibonacci 0 = 0"
  | "fibonacci (Suc 0) = 1"
  | "fibonacci (Suc (Suc n)) = fibonacci n + fibonacci (Suc n)"

fun fibAux :: "nat => nat × nat"
  where
     "fibAux 0 = (0, 1)"
   | "fibAux (Suc n) = (let (a, b) = fibAux n in (b, a + b))"

definition fib :: "nat ⇒ nat" where
  "fib n = fst (fibAux n)"

lemma fib_suma :
  "fib (Suc (Suc n)) = fib n + fib (Suc n)"
proof (induct n)
  show "fib (Suc (Suc 0)) = fib 0 + fib (Suc 0)"
    by (simp add: fib_def)
next
  fix n
  assume HI : "fib (Suc (Suc n)) = fib n + fib (Suc n)"
  have "fib (Suc (Suc (Suc n))) = fst (fibAux (Suc (Suc (Suc n))))"
    by (simp add: fib_def)
  also have "… = snd (fibAux (Suc (Suc n)))"
    by (simp add: prod.case_eq_if)
  also have "… = fst (fibAux (Suc n)) + snd (fibAux (Suc n))"
    by (metis fibAux.simps(2) snd_conv split_def)
  also have "… = fib (Suc n) + snd (fibAux (Suc n))"
    using fib_def by auto
  also have "… = fib (Suc n) + fib (Suc (Suc n))"
    by (simp add: fib_def prod.case_eq_if)
  finally show "fib (Suc (Suc (Suc n))) = fib (Suc n) + fib (Suc (Suc n))"
    by this
qed

lemma "fibonacci n = fib n"
proof (induct n rule: fibonacci.induct)
  show "fibonacci 0 = fib 0"
    by (simp add: fib_def)
next
  show "fibonacci (Suc 0) = fib (Suc 0)"
    by (simp add: fib_def)
next
  fix n
  assume HI1 : "fibonacci n = fib n"
  assume HI2 : "fibonacci (Suc n) = fib (Suc n)"
  have "fibonacci (Suc (Suc n)) = fibonacci n + fibonacci (Suc n)"
    by simp
  also have "… = fib n + fib (Suc n)"
    by (simp add: HI1 HI2)
  also have "… = fib (Suc (Suc n))"
    by (simp add: fib_suma)
  finally show "fibonacci (Suc (Suc n)) = fib (Suc (Suc n))"
    by this
qed

end
</pre>