l3lab/ntp-mathlib huggingface dataset:
/-- `n.descFactorial k = n! / (n - k)!` but without ℕ-division. See `Nat.descFactorial_eq_div`
for the version using ℕ-division. -/
theorem factorial_mul_descFactorial : ∀ {n k : ℕ}, k ≤ n → (n - k)! * n.descFactorial k = n !
  | n, 0 => fun _ => by rw [descFactorial_zero, mul_one, tsub_zero]
  | 0, succ k => fun h => by
    exfalso
    exact not_succ_le_zero k h
  | succ n, succ k => fun h => by
    

Proof state:
n k : ℕ
h : succ k ≤ succ n
⊢ (succ n - succ k)! * descFactorial (succ n) (succ k) = (succ n)!

Next tactic:
rw [succ_descFactorial_succ, succ_sub_succ, ← mul_assoc, mul_comm (n - k)!, mul_assoc,
      factorial_mul_descFactorial (Nat.succ_le_succ_iff.1 h), factorial_succ]
/-- Avoid in favor of `Nat.factorial_mul_descFactorial` if you can. ℕ-division isn't worth it. -/
theorem descFactorial_eq_div {n k : ℕ} (h : k ≤ n) : n.descFactorial k = n ! / (n - k)! := by
  

Proof state:
n k : ℕ
h : k ≤ n
⊢ descFactorial n k = n ! / (n - k)!

Next tactic:
apply mul_left_cancel₀ (factorial_ne_zero (n - k))
/-- Avoid in favor of `Nat.factorial_mul_descFactorial` if you can. ℕ-division isn't worth it. -/
theorem descFactorial_eq_div {n k : ℕ} (h : k ≤ n) : n.descFactorial k = n ! / (n - k)! := by
  apply mul_left_cancel₀ (factorial_ne_zero (n - k))
  

Proof state:
n k : ℕ
h : k ≤ n
⊢ (n - k)! * descFactorial n k = (n - k)! * (n ! / (n - k)!)

Next tactic:
rw [factorial_mul_descFactorial h]
/-- Avoid in favor of `Nat.factorial_mul_descFactorial` if you can. ℕ-division isn't worth it. -/
theorem descFactorial_eq_div {n k : ℕ} (h : k ≤ n) : n.descFactorial k = n ! / (n - k)! := by
  apply mul_left_cancel₀ (factorial_ne_zero (n - k))
  rw [factorial_mul_descFactorial h]
  

Proof state:
n k : ℕ
h : k ≤ n
⊢ n ! = (n - k)! * (n ! / (n - k)!)

Next tactic:
exact (Nat.mul_div_cancel' <| factorial_dvd_factorial <| Nat.sub_le n k).symm
theorem pow_sub_le_descFactorial (n : ℕ) : ∀ k : ℕ, (n + 1 - k) ^ k ≤ n.descFactorial k
  | 0 => by 

Proof state:
n : ℕ
⊢ (n + 1 - 0) ^ 0 ≤ descFactorial n 0

Next tactic:
rw [descFactorial_zero, pow_zero]
theorem pow_sub_le_descFactorial (n : ℕ) : ∀ k : ℕ, (n + 1 - k) ^ k ≤ n.descFactorial k
  | 0 => by rw [descFactorial_zero, pow_zero]
  | k + 1 => by
    

Proof state:
n k : ℕ
⊢ (n + 1 - (k + 1)) ^ (k + 1) ≤ descFactorial n (k + 1)

Next tactic:
rw [descFactorial_succ, pow_succ, succ_sub_succ, mul_comm]
theorem pow_sub_le_descFactorial (n : ℕ) : ∀ k : ℕ, (n + 1 - k) ^ k ≤ n.descFactorial k
  | 0 => by rw [descFactorial_zero, pow_zero]
  | k + 1 => by
    rw [descFactorial_succ, pow_succ, succ_sub_succ, mul_comm]
    

Proof state:
n k : ℕ
⊢ (n - k) * (n - k) ^ k ≤ (n - k) * descFactorial n k

Next tactic:
apply Nat.mul_le_mul_of_nonneg_left
theorem pow_sub_le_descFactorial (n : ℕ) : ∀ k : ℕ, (n + 1 - k) ^ k ≤ n.descFactorial k
  | 0 => by rw [descFactorial_zero, pow_zero]
  | k + 1 => by
    rw [descFactorial_succ, pow_succ, succ_sub_succ, mul_comm]
    apply Nat.mul_le_mul_of_nonneg_left
    

Proof state:
case h₁
n k : ℕ
⊢ (n - k) ^ k ≤ descFactorial n k

Next tactic:
exact   (le_trans (Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ _) _) k)
          (pow_sub_le_descFactorial n k))
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    

Proof state:
n : ℕ
h : 0 + 2 ≤ n
⊢ (n - (0 + 1)) ^ (0 + 2) < descFactorial n (0 + 2)

Next tactic:
rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    

Proof state:
n : ℕ
h : 0 + 2 ≤ n
⊢ (n - (0 + 1)) * (n - (0 + 1)) < (n - 1) * n

Next tactic:
exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
  | k + 1 => fun h => by
    

Proof state:
n k : ℕ
h : k + 1 + 2 ≤ n
⊢ (n - (k + 1 + 1)) ^ (k + 1 + 2) < descFactorial n (k + 1 + 2)

Next tactic:
rw [descFactorial_succ, pow_succ, mul_comm]
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
  | k + 1 => fun h => by
    rw [descFactorial_succ, pow_succ, mul_comm]
    

Proof state:
n k : ℕ
h : k + 1 + 2 ≤ n
⊢ (n - (k + 1 + 1)) * (n - (k + 1 + 1)) ^ (k + 2) < (n - (k + 2)) * descFactorial n (k + 2)

Next tactic:
apply Nat.mul_lt_mul_of_pos_left
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
  | k + 1 => fun h => by
    rw [descFactorial_succ, pow_succ, mul_comm]
    apply Nat.mul_lt_mul_of_pos_left
    · 

Proof state:
case h
n k : ℕ
h : k + 1 + 2 ≤ n
⊢ (n - (k + 1 + 1)) ^ (k + 2) < descFactorial n (k + 2)

Next tactic:
refine' ((Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ n) _) _).trans_lt _)
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
  | k + 1 => fun h => by
    rw [descFactorial_succ, pow_succ, mul_comm]
    apply Nat.mul_lt_mul_of_pos_left
    · refine' ((Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ n) _) _).trans_lt _)
      

Proof state:
case h
n k : ℕ
h : k + 1 + 2 ≤ n
⊢ (succ n - (k + 1 + 1)) ^ (k + 2) < descFactorial n (k + 2)

Next tactic:
rw [succ_sub_succ]
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
  | k + 1 => fun h => by
    rw [descFactorial_succ, pow_succ, mul_comm]
    apply Nat.mul_lt_mul_of_pos_left
    · refine' ((Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ n) _) _).trans_lt _)
      rw [succ_sub_succ]
      

Proof state:
case h
n k : ℕ
h : k + 1 + 2 ≤ n
⊢ (n - (k + 1)) ^ (k + 2) < descFactorial n (k + 2)

Next tactic:
exact pow_sub_lt_descFactorial' ((le_succ _).trans h)
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
  | k + 1 => fun h => by
    rw [descFactorial_succ, pow_succ, mul_comm]
    apply Nat.mul_lt_mul_of_pos_left
    · refine' ((Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ n) _) _).trans_lt _)
      rw [succ_sub_succ]
      exact pow_sub_lt_descFactorial' ((le_succ _).trans h)
    · 

Proof state:
case hk
n k : ℕ
h : k + 1 + 2 ≤ n
⊢ n - (k + 1 + 1) > 0

Next tactic:
apply tsub_pos_of_lt
theorem pow_sub_lt_descFactorial' {n : ℕ} :
    ∀ {k : ℕ}, k + 2 ≤ n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
  | 0 => fun h => by
    rw [descFactorial_succ, pow_succ, pow_one, descFactorial_one]
    exact
      Nat.mul_lt_mul_of_pos_left (tsub_lt_self (lt_of_lt_of_le zero_lt_two h) zero_lt_one)
        (tsub_pos_of_lt h)
  | k + 1 => fun h => by
    rw [descFactorial_succ, pow_succ, mul_comm]
    apply Nat.mul_lt_mul_of_pos_left
    · refine' ((Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ n) _) _).trans_lt _)
      rw [succ_sub_succ]
      exact pow_sub_lt_descFactorial' ((le_succ _).trans h)
    · apply tsub_pos_of_lt; 

Proof state:
case hk.h
n k : ℕ
h : k + 1 + 2 ≤ n
⊢ k + 1 + 1 < n

Next tactic:
apply h
theorem pow_sub_lt_descFactorial {n : ℕ} :
    ∀ {k : ℕ}, 2 ≤ k → k ≤ n → (n + 1 - k) ^ k < n.descFactorial k
  | 0 => by 

Proof state:
n : ℕ
⊢ 2 ≤ 0 → 0 ≤ n → (n + 1 - 0) ^ 0 < descFactorial n 0

Next tactic:
rintro ⟨⟩
theorem pow_sub_lt_descFactorial {n : ℕ} :
    ∀ {k : ℕ}, 2 ≤ k → k ≤ n → (n + 1 - k) ^ k < n.descFactorial k
  | 0 => by rintro ⟨⟩
  | 1 => by 

Proof state:
n : ℕ
⊢ 2 ≤ 1 → 1 ≤ n → (n + 1 - 1) ^ 1 < descFactorial n 1

Next tactic:
intro
theorem pow_sub_lt_descFactorial {n : ℕ} :
    ∀ {k : ℕ}, 2 ≤ k → k ≤ n → (n + 1 - k) ^ k < n.descFactorial k
  | 0 => by rintro ⟨⟩
  | 1 => by intro; 

Proof state:
n : ℕ
a✝ : 2 ≤ 1
⊢ 1 ≤ n → (n + 1 - 1) ^ 1 < descFactorial n 1

Next tactic:
contradiction
theorem pow_sub_lt_descFactorial {n : ℕ} :
    ∀ {k : ℕ}, 2 ≤ k → k ≤ n → (n + 1 - k) ^ k < n.descFactorial k
  | 0 => by rintro ⟨⟩
  | 1 => by intro; contradiction
  | k + 2 => fun _ h => by
    

Proof state:
n k : ℕ
x✝ : 2 ≤ k + 2
h : k + 2 ≤ n
⊢ (n + 1 - (k + 2)) ^ (k + 2) < descFactorial n (k + 2)

Next tactic:
rw [succ_sub_succ]
theorem pow_sub_lt_descFactorial {n : ℕ} :
    ∀ {k : ℕ}, 2 ≤ k → k ≤ n → (n + 1 - k) ^ k < n.descFactorial k
  | 0 => by rintro ⟨⟩
  | 1 => by intro; contradiction
  | k + 2 => fun _ h => by
    rw [succ_sub_succ]
    

Proof state:
n k : ℕ
x✝ : 2 ≤ k + 2
h : k + 2 ≤ n
⊢ (n - (k + 1)) ^ (k + 2) < descFactorial n (k + 2)

Next tactic:
exact pow_sub_lt_descFactorial' h
theorem descFactorial_le_pow (n : ℕ) : ∀ k : ℕ, n.descFactorial k ≤ n ^ k
  | 0 => by 

Proof state:
n : ℕ
⊢ descFactorial n 0 ≤ n ^ 0

Next tactic:
rw [descFactorial_zero, pow_zero]
theorem descFactorial_le_pow (n : ℕ) : ∀ k : ℕ, n.descFactorial k ≤ n ^ k
  | 0 => by rw [descFactorial_zero, pow_zero]
  | k + 1 => by
    

Proof state:
n k : ℕ
⊢ descFactorial n (k + 1) ≤ n ^ (k + 1)

Next tactic:
rw [descFactorial_succ, pow_succ, mul_comm _ n]
theorem descFactorial_le_pow (n : ℕ) : ∀ k : ℕ, n.descFactorial k ≤ n ^ k
  | 0 => by rw [descFactorial_zero, pow_zero]
  | k + 1 => by
    rw [descFactorial_succ, pow_succ, mul_comm _ n]
    

Proof state:
n k : ℕ
⊢ (n - k) * descFactorial n k ≤ n * n ^ k

Next tactic:
exact Nat.mul_le_mul (Nat.sub_le _ _) (descFactorial_le_pow _ k)
theorem descFactorial_lt_pow {n : ℕ} (hn : 1 ≤ n) : ∀ {k : ℕ}, 2 ≤ k → n.descFactorial k < n ^ k
  | 0 => by 

Proof state:
n : ℕ
hn : 1 ≤ n
⊢ 2 ≤ 0 → descFactorial n 0 < n ^ 0

Next tactic:
rintro ⟨⟩
theorem descFactorial_lt_pow {n : ℕ} (hn : 1 ≤ n) : ∀ {k : ℕ}, 2 ≤ k → n.descFactorial k < n ^ k
  | 0 => by rintro ⟨⟩
  | 1 => by 

Proof state:
n : ℕ
hn : 1 ≤ n
⊢ 2 ≤ 1 → descFactorial n 1 < n ^ 1

Next tactic:
intro
theorem descFactorial_lt_pow {n : ℕ} (hn : 1 ≤ n) : ∀ {k : ℕ}, 2 ≤ k → n.descFactorial k < n ^ k
  | 0 => by rintro ⟨⟩
  | 1 => by intro; 

Proof state:
n : ℕ
hn : 1 ≤ n
a✝ : 2 ≤ 1
⊢ descFactorial n 1 < n ^ 1

Next tactic:
contradiction
theorem descFactorial_lt_pow {n : ℕ} (hn : 1 ≤ n) : ∀ {k : ℕ}, 2 ≤ k → n.descFactorial k < n ^ k
  | 0 => by rintro ⟨⟩
  | 1 => by intro; contradiction
  | k + 2 => fun _ => by
    

Proof state:
n : ℕ
hn : 1 ≤ n
k : ℕ
x✝ : 2 ≤ k + 2
⊢ descFactorial n (k + 2) < n ^ (k + 2)

Next tactic:
rw [descFactorial_succ, pow_succ', mul_comm, mul_comm n]
theorem descFactorial_lt_pow {n : ℕ} (hn : 1 ≤ n) : ∀ {k : ℕ}, 2 ≤ k → n.descFactorial k < n ^ k
  | 0 => by rintro ⟨⟩
  | 1 => by intro; contradiction
  | k + 2 => fun _ => by
    rw [descFactorial_succ, pow_succ', mul_comm, mul_comm n]
    

Proof state:
n : ℕ
hn : 1 ≤ n
k : ℕ
x✝ : 2 ≤ k + 2
⊢ descFactorial n (k + 1) * (n - (k + 1)) < n ^ (k + 1) * n

Next tactic:
exact Nat.mul_lt_mul' (descFactorial_le_pow _ _) (tsub_lt_self hn k.zero_lt_succ)
      (pow_pos (Nat.lt_of_succ_le hn) _)
@[simp]
theorem evenOddRec_even (n : ℕ) (P : ℕ → Sort*) (h0 : P 0) (h_even : ∀ i, P i → P (2 * i))
    (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) :
    @evenOddRec _ h0 h_even h_odd (2 * n) = h_even n (evenOddRec h0 h_even h_odd n) :=
  have : ∀ a, bit false n = a →
      HEq (@evenOddRec _ h0 h_even h_odd a) (h_even n (evenOddRec h0 h_even h_odd n))
    | _, rfl => by 

Proof state:
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ HEq (evenOddRec h0 h_even h_odd (bit false n)) (h_even n (evenOddRec h0 h_even h_odd n))

Next tactic:
rw [evenOddRec, binaryRec_eq]
@[simp]
theorem evenOddRec_even (n : ℕ) (P : ℕ → Sort*) (h0 : P 0) (h_even : ∀ i, P i → P (2 * i))
    (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) :
    @evenOddRec _ h0 h_even h_odd (2 * n) = h_even n (evenOddRec h0 h_even h_odd n) :=
  have : ∀ a, bit false n = a →
      HEq (@evenOddRec _ h0 h_even h_odd a) (h_even n (evenOddRec h0 h_even h_odd n))
    | _, rfl => by rw [evenOddRec, binaryRec_eq]; 

Proof state:
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ HEq
    (match false, n,
      binaryRec h0
        (fun x x_1 x_2 =>
          match x, x_1, x_2 with
          | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
          | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi)
        n with
    | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
    | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi)
    (h_even n (evenOddRec h0 h_even h_odd n))
case h
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ (match false, 0, h0 with
    | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
    | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi) =
    h0

Next tactic:
apply eq_rec_heq
@[simp]
theorem evenOddRec_even (n : ℕ) (P : ℕ → Sort*) (h0 : P 0) (h_even : ∀ i, P i → P (2 * i))
    (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) :
    @evenOddRec _ h0 h_even h_odd (2 * n) = h_even n (evenOddRec h0 h_even h_odd n) :=
  have : ∀ a, bit false n = a →
      HEq (@evenOddRec _ h0 h_even h_odd a) (h_even n (evenOddRec h0 h_even h_odd n))
    | _, rfl => by rw [evenOddRec, binaryRec_eq]; apply eq_rec_heq; 

Proof state:
case h
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ (match false, 0, h0 with
    | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
    | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi) =
    h0

Next tactic:
exact H
@[simp]
theorem evenOddRec_odd (n : ℕ) (P : ℕ → Sort*) (h0 : P 0) (h_even : ∀ i, P i → P (2 * i))
    (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) :
    @evenOddRec _ h0 h_even h_odd (2 * n + 1) = h_odd n (evenOddRec h0 h_even h_odd n) :=
  have : ∀ a, bit true n = a →
      HEq (@evenOddRec _ h0 h_even h_odd a) (h_odd n (evenOddRec h0 h_even h_odd n))
    | _, rfl => by 

Proof state:
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ HEq (evenOddRec h0 h_even h_odd (bit true n)) (h_odd n (evenOddRec h0 h_even h_odd n))

Next tactic:
rw [evenOddRec, binaryRec_eq]
@[simp]
theorem evenOddRec_odd (n : ℕ) (P : ℕ → Sort*) (h0 : P 0) (h_even : ∀ i, P i → P (2 * i))
    (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) :
    @evenOddRec _ h0 h_even h_odd (2 * n + 1) = h_odd n (evenOddRec h0 h_even h_odd n) :=
  have : ∀ a, bit true n = a →
      HEq (@evenOddRec _ h0 h_even h_odd a) (h_odd n (evenOddRec h0 h_even h_odd n))
    | _, rfl => by rw [evenOddRec, binaryRec_eq]; 

Proof state:
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ HEq
    (match true, n,
      binaryRec h0
        (fun x x_1 x_2 =>
          match x, x_1, x_2 with
          | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
          | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi)
        n with
    | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
    | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi)
    (h_odd n (evenOddRec h0 h_even h_odd n))
case h
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ (match false, 0, h0 with
    | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
    | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi) =
    h0

Next tactic:
apply eq_rec_heq
@[simp]
theorem evenOddRec_odd (n : ℕ) (P : ℕ → Sort*) (h0 : P 0) (h_even : ∀ i, P i → P (2 * i))
    (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) :
    @evenOddRec _ h0 h_even h_odd (2 * n + 1) = h_odd n (evenOddRec h0 h_even h_odd n) :=
  have : ∀ a, bit true n = a →
      HEq (@evenOddRec _ h0 h_even h_odd a) (h_odd n (evenOddRec h0 h_even h_odd n))
    | _, rfl => by rw [evenOddRec, binaryRec_eq]; apply eq_rec_heq; 

Proof state:
case h
n : ℕ
P : ℕ → Sort u_1
h0 : P 0
h_even : (i : ℕ) → P i → P (2 * i)
h_odd : (i : ℕ) → P i → P (2 * i + 1)
H : h_even 0 h0 = h0
⊢ (match false, 0, h0 with
    | false, i, hi => (_ : 2 * i = bit0 i) ▸ h_even i hi
    | true, i, hi => (_ : 2 * i + 1 = bit1 i) ▸ h_odd i hi) =
    h0

Next tactic:
exact H
/-- The sections of a multiset of multisets `s` consists of all those multisets
which can be put in bijection with `s`, so each element is a member of the corresponding multiset.
-/

def Sections (s : Multiset (Multiset α)) : Multiset (Multiset α) :=
  Multiset.recOn s {0} (fun s _ c => s.bind fun a => c.map (Multiset.cons a)) fun a₀ a₁ _ pi => by
    

Proof state:
α : Type u_1
s : Multiset (Multiset α)
a₀ a₁ : Multiset α
x✝ pi : Multiset (Multiset α)
⊢ HEq (bind a₀ fun a => map (cons a) (bind a₁ fun a => map (cons a) pi))
    (bind a₁ fun a => map (cons a) (bind a₀ fun a => map (cons a) pi))

Next tactic:
simp [map_bind, bind_bind a₀ a₁, cons_swap]
theorem coe_sections :
    ∀ l : List (List α),
      Sections (l.map fun l : List α => (l : Multiset α) : Multiset (Multiset α)) =
        (l.sections.map fun l : List α => (l : Multiset α) : Multiset (Multiset α))
  | [] => rfl
  | a :: l => by
    

Proof state:
α : Type u_1
a : List α
l : List (List α)
⊢ Sections ↑(List.map (fun l => ↑l) (a :: l)) = ↑(List.map (fun l => ↑l) (List.sections (a :: l)))

Next tactic:
simp only [List.map_cons, List.sections]
theorem coe_sections :
    ∀ l : List (List α),
      Sections (l.map fun l : List α => (l : Multiset α) : Multiset (Multiset α)) =
        (l.sections.map fun l : List α => (l : Multiset α) : Multiset (Multiset α))
  | [] => rfl
  | a :: l => by
    simp only [List.map_cons, List.sections]
    

Proof state:
α : Type u_1
a : List α
l : List (List α)
⊢ Sections ↑(↑a :: List.map (fun l => ↑l) l) =
    ↑(List.map (fun l => ↑l) (List.bind (List.sections l) fun s => List.map (fun a => a :: s) a))

Next tactic:
rw [← cons_coe, sections_cons, bind_map_comm, coe_sections l]
theorem coe_sections :
    ∀ l : List (List α),
      Sections (l.map fun l : List α => (l : Multiset α) : Multiset (Multiset α)) =
        (l.sections.map fun l : List α => (l : Multiset α) : Multiset (Multiset α))
  | [] => rfl
  | a :: l => by
    simp only [List.map_cons, List.sections]
    rw [← cons_coe, sections_cons, bind_map_comm, coe_sections l]
    

Proof state:
α : Type u_1
a : List α
l : List (List α)
⊢ (bind ↑(List.map (fun l => ↑l) (List.sections l)) fun b => map (fun a => a ::ₘ b) ↑a) =
    ↑(List.map (fun l => ↑l) (List.bind (List.sections l) fun s => List.map (fun a => a :: s) a))

Next tactic:
simp [List.sections, (· ∘ ·), List.bind]
@[simp]
theorem sections_add (s t : Multiset (Multiset α)) :
    Sections (s + t) = (Sections s).bind fun m => (Sections t).map (m + ·) :=
  Multiset.induction_on s (by 

Proof state:
α : Type u_1
s t : Multiset (Multiset α)
⊢ Sections (0 + t) = bind (Sections 0) fun m => map (fun x => m + x) (Sections t)

Next tactic:
simp
@[simp]
theorem sections_add (s t : Multiset (Multiset α)) :
    Sections (s + t) = (Sections s).bind fun m => (Sections t).map (m + ·) :=
  Multiset.induction_on s (by simp) fun a s ih => by
    

Proof state:
α : Type u_1
s✝ t : Multiset (Multiset α)
a : Multiset α
s : Multiset (Multiset α)
ih : Sections (s + t) = bind (Sections s) fun m => map (fun x => m + x) (Sections t)
⊢ Sections (a ::ₘ s + t) = bind (Sections (a ::ₘ s)) fun m => map (fun x => m + x) (Sections t)

Next tactic:
simp [ih, bind_assoc, map_bind, bind_map]
theorem mem_sections {s : Multiset (Multiset α)} :
    ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by
  

Proof state:
α : Type u_1
s : Multiset (Multiset α)
⊢ ∀ {a : Multiset α}, a ∈ Sections s ↔ Rel (fun s a => a ∈ s) s a

Next tactic:
induction s using Multiset.induction_on
theorem mem_sections {s : Multiset (Multiset α)} :
    ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by
  induction s using Multiset.induction_on
  

Proof state:
case empty
α : Type u_1
⊢ ∀ {a : Multiset α}, a ∈ Sections 0 ↔ Rel (fun s a => a ∈ s) 0 a
case cons
α : Type u_1
a✝¹ : Multiset α
s✝ : Multiset (Multiset α)
a✝ : ∀ {a : Multiset α}, a ∈ Sections s✝ ↔ Rel (fun s a => a ∈ s) s✝ a
⊢ ∀ {a : Multiset α}, a ∈ Sections (a✝¹ ::ₘ s✝) ↔ Rel (fun s a => a ∈ s) (a✝¹ ::ₘ s✝) a

Next tactic:
case empty => simp
theorem mem_sections {s : Multiset (Multiset α)} :
    ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by
  induction s using Multiset.induction_on
  

Proof state:
α : Type u_1
⊢ ∀ {a : Multiset α}, a ∈ Sections 0 ↔ Rel (fun s a => a ∈ s) 0 a

Next tactic:
case empty => simp
theorem mem_sections {s : Multiset (Multiset α)} :
    ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by
  induction s using Multiset.induction_on
  case empty => 

Proof state:
α : Type u_1
⊢ ∀ {a : Multiset α}, a ∈ Sections 0 ↔ Rel (fun s a => a ∈ s) 0 a

Next tactic:
simp
theorem mem_sections {s : Multiset (Multiset α)} :
    ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by
  induction s using Multiset.induction_on
  case empty => simp
  

Proof state:
case cons
α : Type u_1
a✝¹ : Multiset α
s✝ : Multiset (Multiset α)
a✝ : ∀ {a : Multiset α}, a ∈ Sections s✝ ↔ Rel (fun s a => a ∈ s) s✝ a
⊢ ∀ {a : Multiset α}, a ∈ Sections (a✝¹ ::ₘ s✝) ↔ Rel (fun s a => a ∈ s) (a✝¹ ::ₘ s✝) a

Next tactic:
case cons a a' ih => simp [ih, rel_cons_left, eq_comm]
theorem mem_sections {s : Multiset (Multiset α)} :
    ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by
  induction s using Multiset.induction_on
  case empty => simp
  

Proof state:
α : Type u_1
a : Multiset α
a' : Multiset (Multiset α)
ih : ∀ {a : Multiset α}, a ∈ Sections a' ↔ Rel (fun s a => a ∈ s) a' a
⊢ ∀ {a_1 : Multiset α}, a_1 ∈ Sections (a ::ₘ a') ↔ Rel (fun s a => a ∈ s) (a ::ₘ a') a_1

Next tactic:
case cons a a' ih => simp [ih, rel_cons_left, eq_comm]
theorem mem_sections {s : Multiset (Multiset α)} :
    ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by
  induction s using Multiset.induction_on
  case empty => simp
  case cons a a' ih => 

Proof state:
α : Type u_1
a : Multiset α
a' : Multiset (Multiset α)
ih : ∀ {a : Multiset α}, a ∈ Sections a' ↔ Rel (fun s a => a ∈ s) a' a
⊢ ∀ {a_1 : Multiset α}, a_1 ∈ Sections (a ::ₘ a') ↔ Rel (fun s a => a ∈ s) (a ::ₘ a') a_1

Next tactic:
simp [ih, rel_cons_left, eq_comm]
theorem card_sections {s : Multiset (Multiset α)} : card (Sections s) = prod (s.map card) :=
  Multiset.induction_on s (by 

Proof state:
α : Type u_1
s : Multiset (Multiset α)
⊢ card (Sections 0) = prod (map (⇑card) 0)

Next tactic:
simp
theorem card_sections {s : Multiset (Multiset α)} : card (Sections s) = prod (s.map card) :=
  Multiset.induction_on s (by simp) (by 

Proof state:
α : Type u_1
s : Multiset (Multiset α)
⊢ ∀ ⦃a : Multiset α⦄ {s : Multiset (Multiset α)},
    card (Sections s) = prod (map (⇑card) s) → card (Sections (a ::ₘ s)) = prod (map (⇑card) (a ::ₘ s))

Next tactic:
simp (config := { contextual := true })