l3lab/ntp-mathlib huggingface dataset:
theorem lt_of_testBit {n m : ℕ} (i : ℕ) (hn : testBit n i = false) (hm : testBit m i = true)
    (hnm : ∀ j, i < j → testBit n j = testBit m j) : n < m := by
  induction' n using Nat.binaryRec with b n hn' generalizing i m
  · contrapose! hm
    rw [le_zero_iff] at hm
    simp [hm]
  induction' m using Nat.binaryRec with b' m hm' generalizing i
  · exact False.elim (Bool.false_ne_true ((zero_testBit i).symm.trans hm))
  by_cases hi : i = 0
  · subst hi
    simp only [testBit_zero] at hn hm
    have : n = m :=
      eq_of_testBit_eq fun i => by convert hnm (i + 1) (Nat.zero_lt_succ _) using 1
      <;> rw [testBit_succ]
    rw [hn, hm, this, bit_false, bit_true, bit0_val, bit1_val]
    exact lt_add_one _
  · obtain ⟨i', rfl⟩ := exists_eq_succ_of_ne_zero hi
    simp only [testBit_succ] at hn hm
    have :=
      hn' _ hn hm fun j hj => by convert hnm j.succ (succ_lt_succ hj) using 1 <;> rw [testBit_succ]
    have this' : 2 * n < 2 * m := Nat.mul_lt_mul' (le_refl _) this two_pos
    cases b <;> cases b'
    <;> 

Proof state:
case neg.intro.true.true
n : ℕ
hn' :
  ∀ {m : ℕ} (i : ℕ), testBit n i = false → testBit m i = true → (∀ (j : ℕ), i < j → testBit n j = testBit m j) → n < m
m i' : ℕ
hi : ¬succ i' = 0
hn : testBit n i' = false
hm : testBit m i' = true
this : n < m
this' : 2 * n < 2 * m
hm' :
  ∀ (i : ℕ),
    testBit (bit true n) i = false →
      testBit m i = true → (∀ (j : ℕ), i < j → testBit (bit true n) j = testBit m j) → bit true n < m
hnm : ∀ (j : ℕ), succ i' < j → testBit (bit true n) j = testBit (bit true m) j
⊢ bit true n < bit true m

Next tactic:
simp only [bit_false, bit_true, bit0_val n, bit1_val n, bit0_val m, bit1_val m]
theorem lt_of_testBit {n m : ℕ} (i : ℕ) (hn : testBit n i = false) (hm : testBit m i = true)
    (hnm : ∀ j, i < j → testBit n j = testBit m j) : n < m := by
  induction' n using Nat.binaryRec with b n hn' generalizing i m
  · contrapose! hm
    rw [le_zero_iff] at hm
    simp [hm]
  induction' m using Nat.binaryRec with b' m hm' generalizing i
  · exact False.elim (Bool.false_ne_true ((zero_testBit i).symm.trans hm))
  by_cases hi : i = 0
  · subst hi
    simp only [testBit_zero] at hn hm
    have : n = m :=
      eq_of_testBit_eq fun i => by convert hnm (i + 1) (Nat.zero_lt_succ _) using 1
      <;> rw [testBit_succ]
    rw [hn, hm, this, bit_false, bit_true, bit0_val, bit1_val]
    exact lt_add_one _
  · obtain ⟨i', rfl⟩ := exists_eq_succ_of_ne_zero hi
    simp only [testBit_succ] at hn hm
    have :=
      hn' _ hn hm fun j hj => by convert hnm j.succ (succ_lt_succ hj) using 1 <;> rw [testBit_succ]
    have this' : 2 * n < 2 * m := Nat.mul_lt_mul' (le_refl _) this two_pos
    cases b <;> cases b'
    <;> simp only [bit_false, bit_true, bit0_val n, bit1_val n, bit0_val m, bit1_val m]
    · 

Proof state:
case neg.intro.false.false
n : ℕ
hn' :
  ∀ {m : ℕ} (i : ℕ), testBit n i = false → testBit m i = true → (∀ (j : ℕ), i < j → testBit n j = testBit m j) → n < m
m i' : ℕ
hi : ¬succ i' = 0
hn : testBit n i' = false
hm : testBit m i' = true
this : n < m
this' : 2 * n < 2 * m
hm' :
  ∀ (i : ℕ),
    testBit (bit false n) i = false →
      testBit m i = true → (∀ (j : ℕ), i < j → testBit (bit false n) j = testBit m j) → bit false n < m
hnm : ∀ (j : ℕ), succ i' < j → testBit (bit false n) j = testBit (bit false m) j
⊢ 2 * n < 2 * m

Next tactic:
exact this'
theorem lt_of_testBit {n m : ℕ} (i : ℕ) (hn : testBit n i = false) (hm : testBit m i = true)
    (hnm : ∀ j, i < j → testBit n j = testBit m j) : n < m := by
  induction' n using Nat.binaryRec with b n hn' generalizing i m
  · contrapose! hm
    rw [le_zero_iff] at hm
    simp [hm]
  induction' m using Nat.binaryRec with b' m hm' generalizing i
  · exact False.elim (Bool.false_ne_true ((zero_testBit i).symm.trans hm))
  by_cases hi : i = 0
  · subst hi
    simp only [testBit_zero] at hn hm
    have : n = m :=
      eq_of_testBit_eq fun i => by convert hnm (i + 1) (Nat.zero_lt_succ _) using 1
      <;> rw [testBit_succ]
    rw [hn, hm, this, bit_false, bit_true, bit0_val, bit1_val]
    exact lt_add_one _
  · obtain ⟨i', rfl⟩ := exists_eq_succ_of_ne_zero hi
    simp only [testBit_succ] at hn hm
    have :=
      hn' _ hn hm fun j hj => by convert hnm j.succ (succ_lt_succ hj) using 1 <;> rw [testBit_succ]
    have this' : 2 * n < 2 * m := Nat.mul_lt_mul' (le_refl _) this two_pos
    cases b <;> cases b'
    <;> simp only [bit_false, bit_true, bit0_val n, bit1_val n, bit0_val m, bit1_val m]
    · exact this'
    · 

Proof state:
case neg.intro.false.true
n : ℕ
hn' :
  ∀ {m : ℕ} (i : ℕ), testBit n i = false → testBit m i = true → (∀ (j : ℕ), i < j → testBit n j = testBit m j) → n < m
m i' : ℕ
hi : ¬succ i' = 0
hn : testBit n i' = false
hm : testBit m i' = true
this : n < m
this' : 2 * n < 2 * m
hm' :
  ∀ (i : ℕ),
    testBit (bit false n) i = false →
      testBit m i = true → (∀ (j : ℕ), i < j → testBit (bit false n) j = testBit m j) → bit false n < m
hnm : ∀ (j : ℕ), succ i' < j → testBit (bit false n) j = testBit (bit true m) j
⊢ 2 * n < 2 * m + 1

Next tactic:
exact Nat.lt_add_right 1 this'
theorem lt_of_testBit {n m : ℕ} (i : ℕ) (hn : testBit n i = false) (hm : testBit m i = true)
    (hnm : ∀ j, i < j → testBit n j = testBit m j) : n < m := by
  induction' n using Nat.binaryRec with b n hn' generalizing i m
  · contrapose! hm
    rw [le_zero_iff] at hm
    simp [hm]
  induction' m using Nat.binaryRec with b' m hm' generalizing i
  · exact False.elim (Bool.false_ne_true ((zero_testBit i).symm.trans hm))
  by_cases hi : i = 0
  · subst hi
    simp only [testBit_zero] at hn hm
    have : n = m :=
      eq_of_testBit_eq fun i => by convert hnm (i + 1) (Nat.zero_lt_succ _) using 1
      <;> rw [testBit_succ]
    rw [hn, hm, this, bit_false, bit_true, bit0_val, bit1_val]
    exact lt_add_one _
  · obtain ⟨i', rfl⟩ := exists_eq_succ_of_ne_zero hi
    simp only [testBit_succ] at hn hm
    have :=
      hn' _ hn hm fun j hj => by convert hnm j.succ (succ_lt_succ hj) using 1 <;> rw [testBit_succ]
    have this' : 2 * n < 2 * m := Nat.mul_lt_mul' (le_refl _) this two_pos
    cases b <;> cases b'
    <;> simp only [bit_false, bit_true, bit0_val n, bit1_val n, bit0_val m, bit1_val m]
    · exact this'
    · exact Nat.lt_add_right 1 this'
    · 

Proof state:
case neg.intro.true.false
n : ℕ
hn' :
  ∀ {m : ℕ} (i : ℕ), testBit n i = false → testBit m i = true → (∀ (j : ℕ), i < j → testBit n j = testBit m j) → n < m
m i' : ℕ
hi : ¬succ i' = 0
hn : testBit n i' = false
hm : testBit m i' = true
this : n < m
this' : 2 * n < 2 * m
hm' :
  ∀ (i : ℕ),
    testBit (bit true n) i = false →
      testBit m i = true → (∀ (j : ℕ), i < j → testBit (bit true n) j = testBit m j) → bit true n < m
hnm : ∀ (j : ℕ), succ i' < j → testBit (bit true n) j = testBit (bit false m) j
⊢ 2 * n + 1 < 2 * m

Next tactic:
calc
        2 * n + 1 < 2 * n + 2 := lt.base _
        _ ≤ 2 * m := mul_le_mul_left 2 this
theorem lt_of_testBit {n m : ℕ} (i : ℕ) (hn : testBit n i = false) (hm : testBit m i = true)
    (hnm : ∀ j, i < j → testBit n j = testBit m j) : n < m := by
  induction' n using Nat.binaryRec with b n hn' generalizing i m
  · contrapose! hm
    rw [le_zero_iff] at hm
    simp [hm]
  induction' m using Nat.binaryRec with b' m hm' generalizing i
  · exact False.elim (Bool.false_ne_true ((zero_testBit i).symm.trans hm))
  by_cases hi : i = 0
  · subst hi
    simp only [testBit_zero] at hn hm
    have : n = m :=
      eq_of_testBit_eq fun i => by convert hnm (i + 1) (Nat.zero_lt_succ _) using 1
      <;> rw [testBit_succ]
    rw [hn, hm, this, bit_false, bit_true, bit0_val, bit1_val]
    exact lt_add_one _
  · obtain ⟨i', rfl⟩ := exists_eq_succ_of_ne_zero hi
    simp only [testBit_succ] at hn hm
    have :=
      hn' _ hn hm fun j hj => by convert hnm j.succ (succ_lt_succ hj) using 1 <;> rw [testBit_succ]
    have this' : 2 * n < 2 * m := Nat.mul_lt_mul' (le_refl _) this two_pos
    cases b <;> cases b'
    <;> simp only [bit_false, bit_true, bit0_val n, bit1_val n, bit0_val m, bit1_val m]
    · exact this'
    · exact Nat.lt_add_right 1 this'
    · calc
        2 * n + 1 < 2 * n + 2 := lt.base _
        _ ≤ 2 * m := mul_le_mul_left 2 this
    · 

Proof state:
case neg.intro.true.true
n : ℕ
hn' :
  ∀ {m : ℕ} (i : ℕ), testBit n i = false → testBit m i = true → (∀ (j : ℕ), i < j → testBit n j = testBit m j) → n < m
m i' : ℕ
hi : ¬succ i' = 0
hn : testBit n i' = false
hm : testBit m i' = true
this : n < m
this' : 2 * n < 2 * m
hm' :
  ∀ (i : ℕ),
    testBit (bit true n) i = false →
      testBit m i = true → (∀ (j : ℕ), i < j → testBit (bit true n) j = testBit m j) → bit true n < m
hnm : ∀ (j : ℕ), succ i' < j → testBit (bit true n) j = testBit (bit true m) j
⊢ 2 * n + 1 < 2 * m + 1

Next tactic:
exact Nat.succ_lt_succ this'
@[simp]
theorem testBit_two_pow_self (n : ℕ) : testBit (2 ^ n) n = true := by
  

Proof state:
n : ℕ
⊢ testBit (2 ^ n) n = true

Next tactic:
rw [testBit, shiftRight_eq_div_pow, Nat.div_self (pow_pos (α := ℕ) zero_lt_two n)]
@[simp]
theorem testBit_two_pow_self (n : ℕ) : testBit (2 ^ n) n = true := by
  rw [testBit, shiftRight_eq_div_pow, Nat.div_self (pow_pos (α := ℕ) zero_lt_two n)]
  

Proof state:
n : ℕ
⊢ (1 &&& 1 != 0) = true

Next tactic:
simp
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  

Proof state:
n m : ℕ
hm : n ≠ m
⊢ testBit (2 ^ n) m = false

Next tactic:
rw [testBit, shiftRight_eq_div_pow]
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  rw [testBit, shiftRight_eq_div_pow]
  

Proof state:
n m : ℕ
hm : n ≠ m
⊢ (2 ^ n / 2 ^ m &&& 1 != 0) = false

Next tactic:
cases' hm.lt_or_lt with hm hm
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  rw [testBit, shiftRight_eq_div_pow]
  cases' hm.lt_or_lt with hm hm
  · 

Proof state:
case inl
n m : ℕ
hm✝ : n ≠ m
hm : n < m
⊢ (2 ^ n / 2 ^ m &&& 1 != 0) = false

Next tactic:
rw [Nat.div_eq_of_lt]
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  rw [testBit, shiftRight_eq_div_pow]
  cases' hm.lt_or_lt with hm hm
  · rw [Nat.div_eq_of_lt]
    · 

Proof state:
case inl
n m : ℕ
hm✝ : n ≠ m
hm : n < m
⊢ (0 &&& 1 != 0) = false

Next tactic:
simp
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  rw [testBit, shiftRight_eq_div_pow]
  cases' hm.lt_or_lt with hm hm
  · rw [Nat.div_eq_of_lt]
    · simp
    · 

Proof state:
case inl
n m : ℕ
hm✝ : n ≠ m
hm : n < m
⊢ 2 ^ n < 2 ^ m

Next tactic:
exact pow_lt_pow_right one_lt_two hm
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  rw [testBit, shiftRight_eq_div_pow]
  cases' hm.lt_or_lt with hm hm
  · rw [Nat.div_eq_of_lt]
    · simp
    · exact pow_lt_pow_right one_lt_two hm
  · 

Proof state:
case inr
n m : ℕ
hm✝ : n ≠ m
hm : m < n
⊢ (2 ^ n / 2 ^ m &&& 1 != 0) = false

Next tactic:
rw [pow_div hm.le zero_lt_two, ← tsub_add_cancel_of_le (succ_le_of_lt <| tsub_pos_of_lt hm)]
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  rw [testBit, shiftRight_eq_div_pow]
  cases' hm.lt_or_lt with hm hm
  · rw [Nat.div_eq_of_lt]
    · simp
    · exact pow_lt_pow_right one_lt_two hm
  · rw [pow_div hm.le zero_lt_two, ← tsub_add_cancel_of_le (succ_le_of_lt <| tsub_pos_of_lt hm)]
    -- Porting note: XXX why does this make it work?
    

Proof state:
case inr
n m : ℕ
hm✝ : n ≠ m
hm : m < n
⊢ (2 ^ (n - m - succ 0 + succ 0) &&& 1 != 0) = false

Next tactic:
rw [(rfl : succ 0 = 1)]
theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by
  rw [testBit, shiftRight_eq_div_pow]
  cases' hm.lt_or_lt with hm hm
  · rw [Nat.div_eq_of_lt]
    · simp
    · exact pow_lt_pow_right one_lt_two hm
  · rw [pow_div hm.le zero_lt_two, ← tsub_add_cancel_of_le (succ_le_of_lt <| tsub_pos_of_lt hm)]
    -- Porting note: XXX why does this make it work?
    rw [(rfl : succ 0 = 1)]
    

Proof state:
case inr
n m : ℕ
hm✝ : n ≠ m
hm : m < n
⊢ (2 ^ (n - m - succ 0 + succ 0) &&& 1 != 0) = false

Next tactic:
simp [pow_succ, and_one_is_mod, mul_mod_left]
theorem testBit_two_pow (n m : ℕ) : testBit (2 ^ n) m = (n = m) := by
  

Proof state:
n m : ℕ
⊢ (testBit (2 ^ n) m = true) = (n = m)

Next tactic:
by_cases h : n = m
theorem testBit_two_pow (n m : ℕ) : testBit (2 ^ n) m = (n = m) := by
  by_cases h : n = m
  · 

Proof state:
case pos
n m : ℕ
h : n = m
⊢ (testBit (2 ^ n) m = true) = (n = m)

Next tactic:
cases h
theorem testBit_two_pow (n m : ℕ) : testBit (2 ^ n) m = (n = m) := by
  by_cases h : n = m
  · cases h
    

Proof state:
case pos.refl
n : ℕ
⊢ (testBit (2 ^ n) n = true) = (n = n)

Next tactic:
simp
theorem testBit_two_pow (n m : ℕ) : testBit (2 ^ n) m = (n = m) := by
  by_cases h : n = m
  · cases h
    simp
  · 

Proof state:
case neg
n m : ℕ
h : ¬n = m
⊢ (testBit (2 ^ n) m = true) = (n = m)

Next tactic:
rw [testBit_two_pow_of_ne h]
theorem testBit_two_pow (n m : ℕ) : testBit (2 ^ n) m = (n = m) := by
  by_cases h : n = m
  · cases h
    simp
  · rw [testBit_two_pow_of_ne h]
    

Proof state:
case neg
n m : ℕ
h : ¬n = m
⊢ (false = true) = (n = m)

Next tactic:
simp [h]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  

Proof state:
f : Bool → Bool → Bool
⊢ bitwise (swap f) = swap (bitwise f)

Next tactic:
funext m n
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  

Proof state:
case h.h
f : Bool → Bool → Bool
m n : ℕ
⊢ bitwise (swap f) m n = swap (bitwise f) m n

Next tactic:
simp only [Function.swap]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  

Proof state:
case h.h
f : Bool → Bool → Bool
m n : ℕ
⊢ bitwise (swap f) m n = bitwise f n m

Next tactic:
induction' m using Nat.strongInductionOn with m ih generalizing n
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  

Proof state:
case h.h.ind
f : Bool → Bool → Bool
m : ℕ
ih : ∀ m_1 < m, ∀ (n : ℕ), bitwise (swap f) m_1 n = bitwise f n m_1
n : ℕ
⊢ bitwise (swap f) m n = bitwise f n m

Next tactic:
cases' m with m
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> 

Proof state:
case h.h.ind.zero
f : Bool → Bool → Bool
n : ℕ
ih : ∀ m < zero, ∀ (n : ℕ), bitwise (swap f) m n = bitwise f n m
⊢ bitwise (swap f) zero n = bitwise f n zero

Next tactic:
cases' n with n
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> 

Proof state:
case h.h.ind.succ
f : Bool → Bool → Bool
n m : ℕ
ih : ∀ m_1 < succ m, ∀ (n : ℕ), bitwise (swap f) m_1 n = bitwise f n m_1
⊢ bitwise (swap f) (succ m) n = bitwise f n (succ m)

Next tactic:
cases' n with n
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> 

Proof state:
case h.h.ind.zero.zero
f : Bool → Bool → Bool
ih : ∀ m < zero, ∀ (n : ℕ), bitwise (swap f) m n = bitwise f n m
⊢ bitwise (swap f) zero zero = bitwise f zero zero

Next tactic:
try rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> try 

Proof state:
case h.h.ind.zero.zero
f : Bool → Bool → Bool
ih : ∀ m < zero, ∀ (n : ℕ), bitwise (swap f) m n = bitwise f n m
⊢ bitwise (swap f) zero zero = bitwise f zero zero

Next tactic:
rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> 

Proof state:
case h.h.ind.zero.succ
f : Bool → Bool → Bool
ih : ∀ m < zero, ∀ (n : ℕ), bitwise (swap f) m n = bitwise f n m
n : ℕ
⊢ bitwise (swap f) zero (succ n) = bitwise f (succ n) zero

Next tactic:
try rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> try 

Proof state:
case h.h.ind.zero.succ
f : Bool → Bool → Bool
ih : ∀ m < zero, ∀ (n : ℕ), bitwise (swap f) m n = bitwise f n m
n : ℕ
⊢ bitwise (swap f) zero (succ n) = bitwise f (succ n) zero

Next tactic:
rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> 

Proof state:
case h.h.ind.succ.zero
f : Bool → Bool → Bool
m : ℕ
ih : ∀ m_1 < succ m, ∀ (n : ℕ), bitwise (swap f) m_1 n = bitwise f n m_1
⊢ bitwise (swap f) (succ m) zero = bitwise f zero (succ m)

Next tactic:
try rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> try 

Proof state:
case h.h.ind.succ.zero
f : Bool → Bool → Bool
m : ℕ
ih : ∀ m_1 < succ m, ∀ (n : ℕ), bitwise (swap f) m_1 n = bitwise f n m_1
⊢ bitwise (swap f) (succ m) zero = bitwise f zero (succ m)

Next tactic:
rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> 

Proof state:
case h.h.ind.succ.succ
f : Bool → Bool → Bool
m : ℕ
ih : ∀ m_1 < succ m, ∀ (n : ℕ), bitwise (swap f) m_1 n = bitwise f n m_1
n : ℕ
⊢ bitwise (swap f) (succ m) (succ n) = bitwise f (succ n) (succ m)

Next tactic:
try rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> try 

Proof state:
case h.h.ind.succ.succ
f : Bool → Bool → Bool
m : ℕ
ih : ∀ m_1 < succ m, ∀ (n : ℕ), bitwise (swap f) m_1 n = bitwise f n m_1
n : ℕ
⊢ bitwise (swap f) (succ m) (succ n) = bitwise f (succ n) (succ m)

Next tactic:
rw [bitwise_zero_left, bitwise_zero_right]
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> try rw [bitwise_zero_left, bitwise_zero_right]
  · 

Proof state:
case h.h.ind.succ.succ
f : Bool → Bool → Bool
m : ℕ
ih : ∀ m_1 < succ m, ∀ (n : ℕ), bitwise (swap f) m_1 n = bitwise f n m_1
n : ℕ
⊢ bitwise (swap f) (succ m) (succ n) = bitwise f (succ n) (succ m)

Next tactic:
specialize ih ((m+1) / 2) (div_lt_self' ..)
theorem bitwise_swap {f : Bool → Bool → Bool} :
    bitwise (Function.swap f) = Function.swap (bitwise f) := by
  funext m n
  simp only [Function.swap]
  induction' m using Nat.strongInductionOn with m ih generalizing n
  cases' m with m
  <;> cases' n with n
  <;> try rw [bitwise_zero_left, bitwise_zero_right]
  · specialize ih ((m+1) / 2) (div_lt_self' ..)
    

Proof state:
case h.h.ind.succ.succ
f : Bool → Bool → Bool
m n : ℕ
ih : ∀ (n : ℕ), bitwise (swap f) ((m + 1) / 2) n = bitwise f n ((m + 1) / 2)
⊢ bitwise (swap f) (succ m) (succ n) = bitwise f (succ n) (succ m)

Next tactic:
simp [bitwise_of_ne_zero, ih]
/-- If `f` is a commutative operation on bools such that `f false false = false`, then `bitwise f`
    is also commutative. -/
theorem bitwise_comm {f : Bool → Bool → Bool} (hf : ∀ b b', f b b' = f b' b) (n m : ℕ) :
    bitwise f n m = bitwise f m n :=
  suffices bitwise f = swap (bitwise f) by 

Proof state:
f : Bool → Bool → Bool
hf : ∀ (b b' : Bool), f b b' = f b' b
n m : ℕ
this : bitwise f = swap (bitwise f)
⊢ bitwise f n m = bitwise f m n

Next tactic:
conv_lhs => rw [this]
/-- If `f` is a commutative operation on bools such that `f false false = false`, then `bitwise f`
    is also commutative. -/
theorem bitwise_comm {f : Bool → Bool → Bool} (hf : ∀ b b', f b b' = f b' b) (n m : ℕ) :
    bitwise f n m = bitwise f m n :=
  suffices bitwise f = swap (bitwise f) by conv_lhs => 

Proof state:
f : Bool → Bool → Bool
hf : ∀ (b b' : Bool), f b b' = f b' b
n m : ℕ
this : bitwise f = swap (bitwise f)
| bitwise f n m

Next tactic:
rw [this]
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  

Proof state:
n i : ℕ
⊢ n &&& 2 ^ i = Bool.toNat (testBit n i) * 2 ^ i

Next tactic:
refine eq_of_testBit_eq fun j => ?_
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  refine eq_of_testBit_eq fun j => ?_
  

Proof state:
n i j : ℕ
⊢ testBit (n &&& 2 ^ i) j = testBit (Bool.toNat (testBit n i) * 2 ^ i) j

Next tactic:
obtain rfl | hij := Decidable.eq_or_ne i j
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  refine eq_of_testBit_eq fun j => ?_
  obtain rfl | hij := Decidable.eq_or_ne i j <;> 

Proof state:
case inl
n i : ℕ
⊢ testBit (n &&& 2 ^ i) i = testBit (Bool.toNat (testBit n i) * 2 ^ i) i

Next tactic:
cases' h : n.testBit i
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  refine eq_of_testBit_eq fun j => ?_
  obtain rfl | hij := Decidable.eq_or_ne i j <;> 

Proof state:
case inr
n i j : ℕ
hij : i ≠ j
⊢ testBit (n &&& 2 ^ i) j = testBit (Bool.toNat (testBit n i) * 2 ^ i) j

Next tactic:
cases' h : n.testBit i
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  refine eq_of_testBit_eq fun j => ?_
  obtain rfl | hij := Decidable.eq_or_ne i j <;> cases' h : n.testBit i
  · 

Proof state:
case inl.false
n i : ℕ
h : testBit n i = false
⊢ testBit (n &&& 2 ^ i) i = testBit (Bool.toNat false * 2 ^ i) i

Next tactic:
simp [h]
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  refine eq_of_testBit_eq fun j => ?_
  obtain rfl | hij := Decidable.eq_or_ne i j <;> cases' h : n.testBit i
  · simp [h]
  · 

Proof state:
case inl.true
n i : ℕ
h : testBit n i = true
⊢ testBit (n &&& 2 ^ i) i = testBit (Bool.toNat true * 2 ^ i) i

Next tactic:
simp [h]
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  refine eq_of_testBit_eq fun j => ?_
  obtain rfl | hij := Decidable.eq_or_ne i j <;> cases' h : n.testBit i
  · simp [h]
  · simp [h]
  · 

Proof state:
case inr.false
n i j : ℕ
hij : i ≠ j
h : testBit n i = false
⊢ testBit (n &&& 2 ^ i) j = testBit (Bool.toNat false * 2 ^ i) j

Next tactic:
simp [h, testBit_two_pow_of_ne hij]
lemma and_two_pow (n i : ℕ) : n &&& 2 ^ i = (n.testBit i).toNat * 2 ^ i := by
  refine eq_of_testBit_eq fun j => ?_
  obtain rfl | hij := Decidable.eq_or_ne i j <;> cases' h : n.testBit i
  · simp [h]
  · simp [h]
  · simp [h, testBit_two_pow_of_ne hij]
  · 

Proof state:
case inr.true
n i j : ℕ
hij : i ≠ j
h : testBit n i = true
⊢ testBit (n &&& 2 ^ i) j = testBit (Bool.toNat true * 2 ^ i) j

Next tactic:
simp [h, testBit_two_pow_of_ne hij]
lemma two_pow_and (n i : ℕ) : 2 ^ i &&& n = 2 ^ i * (n.testBit i).toNat := by
  

Proof state:
n i : ℕ
⊢ 2 ^ i &&& n = 2 ^ i * Bool.toNat (testBit n i)

Next tactic:
rw [mul_comm, land_comm, and_two_pow]