l3lab/ntp-mathlib huggingface dataset:
theorem fib_lt_fib_succ {n : ℕ} (hn : 2 ≤ n) : fib n < fib (n + 1) := by
  

Proof state:
n : ℕ
hn : 2 ≤ n
⊢ fib n < fib (n + 1)

Next tactic:
rcases exists_add_of_le hn with ⟨n, rfl⟩
theorem fib_lt_fib_succ {n : ℕ} (hn : 2 ≤ n) : fib n < fib (n + 1) := by
  rcases exists_add_of_le hn with ⟨n, rfl⟩
  

Proof state:
case intro
n : ℕ
hn : 2 ≤ 2 + n
⊢ fib (2 + n) < fib (2 + n + 1)

Next tactic:
rw [← tsub_pos_iff_lt, add_comm 2, fib_add_two_sub_fib_add_one, fib_pos]
theorem fib_lt_fib_succ {n : ℕ} (hn : 2 ≤ n) : fib n < fib (n + 1) := by
  rcases exists_add_of_le hn with ⟨n, rfl⟩
  rw [← tsub_pos_iff_lt, add_comm 2, fib_add_two_sub_fib_add_one, fib_pos]
  

Proof state:
case intro
n : ℕ
hn : 2 ≤ 2 + n
⊢ 0 < n + 1

Next tactic:
exact succ_pos n
/-- `fib (n + 2)` is strictly monotone. -/
theorem fib_add_two_strictMono : StrictMono fun n => fib (n + 2) := by
  

Proof state:
⊢ StrictMono fun n => fib (n + 2)

Next tactic:
refine' strictMono_nat_of_lt_succ fun n => _
/-- `fib (n + 2)` is strictly monotone. -/
theorem fib_add_two_strictMono : StrictMono fun n => fib (n + 2) := by
  refine' strictMono_nat_of_lt_succ fun n => _
  

Proof state:
n : ℕ
⊢ fib (n + 2) < fib (n + 1 + 2)

Next tactic:
rw [add_right_comm]
/-- `fib (n + 2)` is strictly monotone. -/
theorem fib_add_two_strictMono : StrictMono fun n => fib (n + 2) := by
  refine' strictMono_nat_of_lt_succ fun n => _
  rw [add_right_comm]
  

Proof state:
n : ℕ
⊢ fib (n + 2) < fib (n + 2 + 1)

Next tactic:
exact fib_lt_fib_succ (self_le_add_left _ _)
lemma fib_lt_fib {m : ℕ} (hm : 2 ≤ m) : ∀ {n}, fib m < fib n ↔ m < n
  | 0 => by 

Proof state:
m : ℕ
hm : 2 ≤ m
⊢ fib m < fib 0 ↔ m < 0

Next tactic:
simp [hm]
lemma fib_lt_fib {m : ℕ} (hm : 2 ≤ m) : ∀ {n}, fib m < fib n ↔ m < n
  | 0 => by simp [hm]
  | 1 => by 

Proof state:
m : ℕ
hm : 2 ≤ m
⊢ fib m < fib 1 ↔ m < 1

Next tactic:
simp [hm]
lemma fib_lt_fib {m : ℕ} (hm : 2 ≤ m) : ∀ {n}, fib m < fib n ↔ m < n
  | 0 => by simp [hm]
  | 1 => by simp [hm]
  | n + 2 => fib_strictMonoOn.lt_iff_lt hm $ by 

Proof state:
m : ℕ
hm : 2 ≤ m
n : ℕ
⊢ n + 2 ∈ Set.Ici 2

Next tactic:
simp
theorem le_fib_self {n : ℕ} (five_le_n : 5 ≤ n) : n ≤ fib n := by
  

Proof state:
n : ℕ
five_le_n : 5 ≤ n
⊢ n ≤ fib n

Next tactic:
induction' five_le_n with n five_le_n IH
theorem le_fib_self {n : ℕ} (five_le_n : 5 ≤ n) : n ≤ fib n := by
  induction' five_le_n with n five_le_n IH
  ·-- 5 ≤ fib 5
    

Proof state:
case refl
n : ℕ
⊢ 5 ≤ fib 5

Next tactic:
rfl
theorem le_fib_self {n : ℕ} (five_le_n : 5 ≤ n) : n ≤ fib n := by
  induction' five_le_n with n five_le_n IH
  ·-- 5 ≤ fib 5
    rfl
  · -- n + 1 ≤ fib (n + 1) for 5 ≤ n
    

Proof state:
case step
n✝ n : ℕ
five_le_n : Nat.le 5 n
IH : n ≤ fib n
⊢ succ n ≤ fib (succ n)

Next tactic:
rw [succ_le_iff]
theorem le_fib_self {n : ℕ} (five_le_n : 5 ≤ n) : n ≤ fib n := by
  induction' five_le_n with n five_le_n IH
  ·-- 5 ≤ fib 5
    rfl
  · -- n + 1 ≤ fib (n + 1) for 5 ≤ n
    rw [succ_le_iff]
    

Proof state:
case step
n✝ n : ℕ
five_le_n : Nat.le 5 n
IH : n ≤ fib n
⊢ n < fib (succ n)

Next tactic:
calc
      n ≤ fib n := IH
      _ < fib (n + 1) := fib_lt_fib_succ (le_trans (by decide) five_le_n)
theorem le_fib_self {n : ℕ} (five_le_n : 5 ≤ n) : n ≤ fib n := by
  induction' five_le_n with n five_le_n IH
  ·-- 5 ≤ fib 5
    rfl
  · -- n + 1 ≤ fib (n + 1) for 5 ≤ n
    rw [succ_le_iff]
    calc
      n ≤ fib n := IH
      _ < fib (n + 1) := fib_lt_fib_succ (le_trans (by 

Proof state:
n✝ n : ℕ
five_le_n : Nat.le 5 n
IH : n ≤ fib n
⊢ 2 ≤ 5

Next tactic:
decide
/-- Subsequent Fibonacci numbers are coprime,
  see https://proofwiki.org/wiki/Consecutive_Fibonacci_Numbers_are_Coprime -/
theorem fib_coprime_fib_succ (n : ℕ) : Nat.Coprime (fib n) (fib (n + 1)) := by
  

Proof state:
n : ℕ
⊢ Coprime (fib n) (fib (n + 1))

Next tactic:
induction' n with n ih
/-- Subsequent Fibonacci numbers are coprime,
  see https://proofwiki.org/wiki/Consecutive_Fibonacci_Numbers_are_Coprime -/
theorem fib_coprime_fib_succ (n : ℕ) : Nat.Coprime (fib n) (fib (n + 1)) := by
  induction' n with n ih
  · 

Proof state:
case zero
⊢ Coprime (fib zero) (fib (zero + 1))

Next tactic:
simp
/-- Subsequent Fibonacci numbers are coprime,
  see https://proofwiki.org/wiki/Consecutive_Fibonacci_Numbers_are_Coprime -/
theorem fib_coprime_fib_succ (n : ℕ) : Nat.Coprime (fib n) (fib (n + 1)) := by
  induction' n with n ih
  · simp
  · 

Proof state:
case succ
n : ℕ
ih : Coprime (fib n) (fib (n + 1))
⊢ Coprime (fib (succ n)) (fib (succ n + 1))

Next tactic:
rw [fib_add_two]
/-- Subsequent Fibonacci numbers are coprime,
  see https://proofwiki.org/wiki/Consecutive_Fibonacci_Numbers_are_Coprime -/
theorem fib_coprime_fib_succ (n : ℕ) : Nat.Coprime (fib n) (fib (n + 1)) := by
  induction' n with n ih
  · simp
  · rw [fib_add_two]
    

Proof state:
case succ
n : ℕ
ih : Coprime (fib n) (fib (n + 1))
⊢ Coprime (fib (succ n)) (fib n + fib (n + 1))

Next tactic:
simp only [coprime_add_self_right]
/-- Subsequent Fibonacci numbers are coprime,
  see https://proofwiki.org/wiki/Consecutive_Fibonacci_Numbers_are_Coprime -/
theorem fib_coprime_fib_succ (n : ℕ) : Nat.Coprime (fib n) (fib (n + 1)) := by
  induction' n with n ih
  · simp
  · rw [fib_add_two]
    simp only [coprime_add_self_right]
    

Proof state:
case succ
n : ℕ
ih : Coprime (fib n) (fib (n + 1))
⊢ Coprime (fib (succ n)) (fib n)

Next tactic:
simp [Coprime, ih.symm]
/-- See https://proofwiki.org/wiki/Fibonacci_Number_in_terms_of_Smaller_Fibonacci_Numbers -/
theorem fib_add (m n : ℕ) : fib (m + n + 1) = fib m * fib n + fib (m + 1) * fib (n + 1) := by
  

Proof state:
m n : ℕ
⊢ fib (m + n + 1) = fib m * fib n + fib (m + 1) * fib (n + 1)

Next tactic:
induction' n with n ih generalizing m
/-- See https://proofwiki.org/wiki/Fibonacci_Number_in_terms_of_Smaller_Fibonacci_Numbers -/
theorem fib_add (m n : ℕ) : fib (m + n + 1) = fib m * fib n + fib (m + 1) * fib (n + 1) := by
  induction' n with n ih generalizing m
  · 

Proof state:
case zero
m : ℕ
⊢ fib (m + zero + 1) = fib m * fib zero + fib (m + 1) * fib (zero + 1)

Next tactic:
simp
/-- See https://proofwiki.org/wiki/Fibonacci_Number_in_terms_of_Smaller_Fibonacci_Numbers -/
theorem fib_add (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
  · 

Proof state:
case succ
n : ℕ
ih : ∀ (m : ℕ), fib (m + n + 1) = fib m * fib n + fib (m + 1) * fib (n + 1)
m : ℕ
⊢ fib (m + succ n + 1) = fib m * fib (succ n) + fib (m + 1) * fib (succ n + 1)

Next tactic:
intros
/-- See https://proofwiki.org/wiki/Fibonacci_Number_in_terms_of_Smaller_Fibonacci_Numbers -/
theorem fib_add (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
  · intros
    

Proof state:
case succ
n : ℕ
ih : ∀ (m : ℕ), fib (m + n + 1) = fib m * fib n + fib (m + 1) * fib (n + 1)
m : ℕ
⊢ fib (m + succ n + 1) = fib m * fib (succ n) + fib (m + 1) * fib (succ n + 1)

Next tactic:
specialize ih (m + 1)
/-- See https://proofwiki.org/wiki/Fibonacci_Number_in_terms_of_Smaller_Fibonacci_Numbers -/
theorem fib_add (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
  · intros
    specialize ih (m + 1)
    

Proof state:
case succ
n m : ℕ
ih : fib (m + 1 + n + 1) = fib (m + 1) * fib n + fib (m + 1 + 1) * fib (n + 1)
⊢ fib (m + succ n + 1) = fib m * fib (succ n) + fib (m + 1) * fib (succ n + 1)

Next tactic:
rw [add_assoc m 1 n, add_comm 1 n] at ih
/-- See https://proofwiki.org/wiki/Fibonacci_Number_in_terms_of_Smaller_Fibonacci_Numbers -/
theorem fib_add (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
  · intros
    specialize ih (m + 1)
    rw [add_assoc m 1 n, add_comm 1 n] at ih
    

Proof state:
case succ
n m : ℕ
ih : fib (m + (n + 1) + 1) = fib (m + 1) * fib n + fib (m + 1 + 1) * fib (n + 1)
⊢ fib (m + succ n + 1) = fib m * fib (succ n) + fib (m + 1) * fib (succ n + 1)

Next tactic:
simp only [fib_add_two, ih]
/-- See https://proofwiki.org/wiki/Fibonacci_Number_in_terms_of_Smaller_Fibonacci_Numbers -/
theorem fib_add (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
  · intros
    specialize ih (m + 1)
    rw [add_assoc m 1 n, add_comm 1 n] at ih
    simp only [fib_add_two, ih]
    

Proof state:
case succ
n m : ℕ
ih : fib (m + (n + 1) + 1) = fib (m + 1) * fib n + fib (m + 1 + 1) * fib (n + 1)
⊢ fib (m + 1) * fib n + (fib m + fib (m + 1)) * fib (n + 1) = fib m * fib (succ n) + fib (m + 1) * (fib n + fib (n + 1))

Next tactic:
ring
theorem fib_two_mul (n : ℕ) : fib (2 * n) = fib n * (2 * fib (n + 1) - fib n) := by
  

Proof state:
n : ℕ
⊢ fib (2 * n) = fib n * (2 * fib (n + 1) - fib n)

Next tactic:
cases n
theorem fib_two_mul (n : ℕ) : fib (2 * n) = fib n * (2 * fib (n + 1) - fib n) := by
  cases n
  · 

Proof state:
case zero
⊢ fib (2 * zero) = fib zero * (2 * fib (zero + 1) - fib zero)

Next tactic:
simp
theorem fib_two_mul (n : ℕ) : fib (2 * n) = fib n * (2 * fib (n + 1) - fib n) := by
  cases n
  · simp
  · 

Proof state:
case succ
n✝ : ℕ
⊢ fib (2 * succ n✝) = fib (succ n✝) * (2 * fib (succ n✝ + 1) - fib (succ n✝))

Next tactic:
rw [Nat.succ_eq_add_one, two_mul, ← add_assoc, fib_add, fib_add_two, two_mul]
theorem fib_two_mul (n : ℕ) : fib (2 * n) = fib n * (2 * fib (n + 1) - fib n) := by
  cases n
  · simp
  · rw [Nat.succ_eq_add_one, two_mul, ← add_assoc, fib_add, fib_add_two, two_mul]
    

Proof state:
case succ
n✝ : ℕ
⊢ fib (n✝ + 1) * fib n✝ + (fib n✝ + fib (n✝ + 1)) * fib (n✝ + 1) =
    fib (n✝ + 1) * (fib n✝ + fib (n✝ + 1) + (fib n✝ + fib (n✝ + 1)) - fib (n✝ + 1))

Next tactic:
simp only [← add_assoc, add_tsub_cancel_right]
theorem fib_two_mul (n : ℕ) : fib (2 * n) = fib n * (2 * fib (n + 1) - fib n) := by
  cases n
  · simp
  · rw [Nat.succ_eq_add_one, two_mul, ← add_assoc, fib_add, fib_add_two, two_mul]
    simp only [← add_assoc, add_tsub_cancel_right]
    

Proof state:
case succ
n✝ : ℕ
⊢ fib (n✝ + 1) * fib n✝ + (fib n✝ + fib (n✝ + 1)) * fib (n✝ + 1) = fib (n✝ + 1) * (fib n✝ + fib (n✝ + 1) + fib n✝)

Next tactic:
ring
theorem fib_two_mul_add_one (n : ℕ) : fib (2 * n + 1) = fib (n + 1) ^ 2 + fib n ^ 2 := by
  

Proof state:
n : ℕ
⊢ fib (2 * n + 1) = fib (n + 1) ^ 2 + fib n ^ 2

Next tactic:
rw [two_mul, fib_add]
theorem fib_two_mul_add_one (n : ℕ) : fib (2 * n + 1) = fib (n + 1) ^ 2 + fib n ^ 2 := by
  rw [two_mul, fib_add]
  

Proof state:
n : ℕ
⊢ fib n * fib n + fib (n + 1) * fib (n + 1) = fib (n + 1) ^ 2 + fib n ^ 2

Next tactic:
ring
theorem fib_two_mul_add_two (n : ℕ) :
    fib (2 * n + 2) = fib (n + 1) * (2 * fib n + fib (n + 1)) := by
  

Proof state:
n : ℕ
⊢ fib (2 * n + 2) = fib (n + 1) * (2 * fib n + fib (n + 1))

Next tactic:
rw [fib_add_two, fib_two_mul, fib_two_mul_add_one]
theorem fib_two_mul_add_two (n : ℕ) :
    fib (2 * n + 2) = fib (n + 1) * (2 * fib n + fib (n + 1)) := by
  rw [fib_add_two, fib_two_mul, fib_two_mul_add_one]
  -- porting note: A bunch of issues similar to [this zulip thread](https://github.com/leanprover-community/mathlib4/pull/1576) with `zify`
  

Proof state:
n : ℕ
⊢ fib n * (2 * fib (n + 1) - fib n) + (fib (n + 1) ^ 2 + fib n ^ 2) = fib (n + 1) * (2 * fib n + fib (n + 1))

Next tactic:
have : fib n ≤ 2 * fib (n + 1) :=
    le_trans (fib_le_fib_succ) (mul_comm 2 _ ▸ le_mul_of_pos_right two_pos)
theorem fib_two_mul_add_two (n : ℕ) :
    fib (2 * n + 2) = fib (n + 1) * (2 * fib n + fib (n + 1)) := by
  rw [fib_add_two, fib_two_mul, fib_two_mul_add_one]
  -- porting note: A bunch of issues similar to [this zulip thread](https://github.com/leanprover-community/mathlib4/pull/1576) with `zify`
  have : fib n ≤ 2 * fib (n + 1) :=
    le_trans (fib_le_fib_succ) (mul_comm 2 _ ▸ le_mul_of_pos_right two_pos)
  

Proof state:
n : ℕ
this : fib n ≤ 2 * fib (n + 1)
⊢ fib n * (2 * fib (n + 1) - fib n) + (fib (n + 1) ^ 2 + fib n ^ 2) = fib (n + 1) * (2 * fib n + fib (n + 1))

Next tactic:
zify [this]
theorem fib_two_mul_add_two (n : ℕ) :
    fib (2 * n + 2) = fib (n + 1) * (2 * fib n + fib (n + 1)) := by
  rw [fib_add_two, fib_two_mul, fib_two_mul_add_one]
  -- porting note: A bunch of issues similar to [this zulip thread](https://github.com/leanprover-community/mathlib4/pull/1576) with `zify`
  have : fib n ≤ 2 * fib (n + 1) :=
    le_trans (fib_le_fib_succ) (mul_comm 2 _ ▸ le_mul_of_pos_right two_pos)
  zify [this]
  

Proof state:
n : ℕ
this : fib n ≤ 2 * fib (n + 1)
⊢ ↑(fib n) * (2 * ↑(fib (n + 1)) - ↑(fib n)) + (↑(fib (n + 1)) ^ 2 + ↑(fib n) ^ 2) =
    ↑(fib (n + 1)) * (2 * ↑(fib n) + ↑(fib (n + 1)))

Next tactic:
ring
theorem fib_bit0 (n : ℕ) : fib (bit0 n) = fib n * (2 * fib (n + 1) - fib n) := by
  

Proof state:
n : ℕ
⊢ fib (bit0 n) = fib n * (2 * fib (n + 1) - fib n)

Next tactic:
rw [bit0_eq_two_mul, fib_two_mul]
theorem fib_bit1 (n : ℕ) : fib (bit1 n) = fib (n + 1) ^ 2 + fib n ^ 2 := by
  

Proof state:
n : ℕ
⊢ fib (bit1 n) = fib (n + 1) ^ 2 + fib n ^ 2

Next tactic:
rw [Nat.bit1_eq_succ_bit0, bit0_eq_two_mul, fib_two_mul_add_one]
theorem fib_bit1_succ (n : ℕ) : fib (bit1 n + 1) = fib (n + 1) * (2 * fib n + fib (n + 1)) := by
  

Proof state:
n : ℕ
⊢ fib (bit1 n + 1) = fib (n + 1) * (2 * fib n + fib (n + 1))

Next tactic:
rw [Nat.bit1_eq_succ_bit0, bit0_eq_two_mul, fib_two_mul_add_two]
theorem fast_fib_aux_bit_ff (n : ℕ) :
    fastFibAux (bit false n) =
      let p := fastFibAux n
      (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2) := by
  

Proof state:
n : ℕ
⊢ fastFibAux (bit false n) =
    let p := fastFibAux n;
    (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2)

Next tactic:
rw [fastFibAux, binaryRec_eq]
theorem fast_fib_aux_bit_ff (n : ℕ) :
    fastFibAux (bit false n) =
      let p := fastFibAux n
      (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2) := by
  rw [fastFibAux, binaryRec_eq]
  · 

Proof state:
n : ℕ
⊢ (if false = true then
      ((binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).2 ^
            2 +
          (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).1 ^
            2,
        (binaryRec (fib 0, fib 1)
              (fun b x p =>
                if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
              n).2 *
          (2 *
              (binaryRec (fib 0, fib 1)
                  (fun b x p =>
                    if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                    else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                  n).1 +
            (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).2))
    else
      ((binaryRec (fib 0, fib 1)
              (fun b x p =>
                if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
              n).1 *
          (2 *
              (binaryRec (fib 0, fib 1)
                  (fun b x p =>
                    if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                    else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                  n).2 -
            (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).1),
        (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).2 ^
            2 +
          (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).1 ^
            2)) =
    let p :=
      binaryRec (fib 0, fib 1)
        (fun b x p =>
          if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2)) else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
        n;
    (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2)

Next tactic:
rfl
theorem fast_fib_aux_bit_ff (n : ℕ) :
    fastFibAux (bit false n) =
      let p := fastFibAux n
      (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2) := by
  rw [fastFibAux, binaryRec_eq]
  · rfl
  · 

Proof state:
case h
n : ℕ
⊢ (if false = true then
      ((fib 0, fib 1).2 ^ 2 + (fib 0, fib 1).1 ^ 2, (fib 0, fib 1).2 * (2 * (fib 0, fib 1).1 + (fib 0, fib 1).2))
    else ((fib 0, fib 1).1 * (2 * (fib 0, fib 1).2 - (fib 0, fib 1).1), (fib 0, fib 1).2 ^ 2 + (fib 0, fib 1).1 ^ 2)) =
    (fib 0, fib 1)

Next tactic:
simp
theorem fast_fib_aux_bit_tt (n : ℕ) :
    fastFibAux (bit true n) =
      let p := fastFibAux n
      (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2)) := by
  

Proof state:
n : ℕ
⊢ fastFibAux (bit true n) =
    let p := fastFibAux n;
    (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))

Next tactic:
rw [fastFibAux, binaryRec_eq]
theorem fast_fib_aux_bit_tt (n : ℕ) :
    fastFibAux (bit true n) =
      let p := fastFibAux n
      (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2)) := by
  rw [fastFibAux, binaryRec_eq]
  · 

Proof state:
n : ℕ
⊢ (if true = true then
      ((binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).2 ^
            2 +
          (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).1 ^
            2,
        (binaryRec (fib 0, fib 1)
              (fun b x p =>
                if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
              n).2 *
          (2 *
              (binaryRec (fib 0, fib 1)
                  (fun b x p =>
                    if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                    else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                  n).1 +
            (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).2))
    else
      ((binaryRec (fib 0, fib 1)
              (fun b x p =>
                if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
              n).1 *
          (2 *
              (binaryRec (fib 0, fib 1)
                  (fun b x p =>
                    if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                    else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                  n).2 -
            (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).1),
        (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).2 ^
            2 +
          (binaryRec (fib 0, fib 1)
                (fun b x p =>
                  if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))
                  else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
                n).1 ^
            2)) =
    let p :=
      binaryRec (fib 0, fib 1)
        (fun b x p =>
          if b = true then (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2)) else (p.1 * (2 * p.2 - p.1), p.2 ^ 2 + p.1 ^ 2))
        n;
    (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2))

Next tactic:
rfl
theorem fast_fib_aux_bit_tt (n : ℕ) :
    fastFibAux (bit true n) =
      let p := fastFibAux n
      (p.2 ^ 2 + p.1 ^ 2, p.2 * (2 * p.1 + p.2)) := by
  rw [fastFibAux, binaryRec_eq]
  · rfl
  · 

Proof state:
case h
n : ℕ
⊢ (if false = true then
      ((fib 0, fib 1).2 ^ 2 + (fib 0, fib 1).1 ^ 2, (fib 0, fib 1).2 * (2 * (fib 0, fib 1).1 + (fib 0, fib 1).2))
    else ((fib 0, fib 1).1 * (2 * (fib 0, fib 1).2 - (fib 0, fib 1).1), (fib 0, fib 1).2 ^ 2 + (fib 0, fib 1).1 ^ 2)) =
    (fib 0, fib 1)

Next tactic:
simp
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  

Proof state:
n : ℕ
⊢ fastFibAux n = (fib n, fib (n + 1))

Next tactic:
apply Nat.binaryRec _ (fun b n' ih => _) n
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · 

Proof state:
n : ℕ
⊢ fastFibAux 0 = (fib 0, fib (0 + 1))

Next tactic:
simp [fastFibAux]
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · simp [fastFibAux]
  · 

Proof state:
n : ℕ
⊢ ∀ (b : Bool) (n' : ℕ),
    fastFibAux n' = (fib n', fib (n' + 1)) → fastFibAux (bit b n') = (fib (bit b n'), fib (bit b n' + 1))

Next tactic:
intro b
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · simp [fastFibAux]
  · intro b
    

Proof state:
n : ℕ
b : Bool
⊢ ∀ (n' : ℕ), fastFibAux n' = (fib n', fib (n' + 1)) → fastFibAux (bit b n') = (fib (bit b n'), fib (bit b n' + 1))

Next tactic:
intro n'
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · simp [fastFibAux]
  · intro b
    intro n'
    

Proof state:
n : ℕ
b : Bool
n' : ℕ
⊢ fastFibAux n' = (fib n', fib (n' + 1)) → fastFibAux (bit b n') = (fib (bit b n'), fib (bit b n' + 1))

Next tactic:
intro ih
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · simp [fastFibAux]
  · intro b
    intro n'
    intro ih
    

Proof state:
n : ℕ
b : Bool
n' : ℕ
ih : fastFibAux n' = (fib n', fib (n' + 1))
⊢ fastFibAux (bit b n') = (fib (bit b n'), fib (bit b n' + 1))

Next tactic:
cases b
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · simp [fastFibAux]
  · intro b
    intro n'
    intro ih
    cases b <;>
          

Proof state:
case false
n n' : ℕ
ih : fastFibAux n' = (fib n', fib (n' + 1))
⊢ fastFibAux (bit false n') = (fib (bit false n'), fib (bit false n' + 1))

Next tactic:
simp only [fast_fib_aux_bit_ff, fast_fib_aux_bit_tt, congr_arg Prod.fst ih,
            congr_arg Prod.snd ih, Prod.mk.inj_iff]
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · simp [fastFibAux]
  · intro b
    intro n'
    intro ih
    cases b <;>
          

Proof state:
case true
n n' : ℕ
ih : fastFibAux n' = (fib n', fib (n' + 1))
⊢ fastFibAux (bit true n') = (fib (bit true n'), fib (bit true n' + 1))

Next tactic:
simp only [fast_fib_aux_bit_ff, fast_fib_aux_bit_tt, congr_arg Prod.fst ih,
            congr_arg Prod.snd ih, Prod.mk.inj_iff]
theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by
  apply Nat.binaryRec _ (fun b n' ih => _) n
  · simp [fastFibAux]
  · intro b
    intro n'
    intro ih
    cases b <;>
          simp only [fast_fib_aux_bit_ff, fast_fib_aux_bit_tt, congr_arg Prod.fst ih,
            congr_arg Prod.snd ih, Prod.mk.inj_iff] <;>
          

Proof state:
case false
n n' : ℕ
ih : fastFibAux n' = (fib n', fib (n' + 1))
⊢ fib n' * (2 * fib (n' + 1) - fib n') = fib (bit false n') ∧ fib (n' + 1) ^ 2 + fib n' ^ 2 = fib (bit false n' + 1)

Next tactic:
simp [bit, fib_bit0, fib_bit1, fib_bit0_succ, fib_bit1_succ]