l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem pow_eq_zero_iff [NoZeroDivisors M] {a : M} {n : ℕ} (hn : 0 < n) : a ^ n = 0 ↔ a = 0 := by
  refine' ⟨pow_eq_zero, _⟩
  rintro rfl
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : NoZeroDivisors M
n : ℕ
hn : 0 < n
⊢ 0 ^ n = 0

Next tactic:
exact zero_pow hn
@[simp]
theorem pow_eq_zero_iff' [NoZeroDivisors M] [Nontrivial M] {a : M} {n : ℕ} :
    a ^ n = 0 ↔ a = 0 ∧ n ≠ 0 := by 

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝² : MonoidWithZero M
inst✝¹ : NoZeroDivisors M
inst✝ : Nontrivial M
a : M
n : ℕ
⊢ a ^ n = 0 ↔ a = 0 ∧ n ≠ 0

Next tactic:
cases (zero_le n).eq_or_gt
@[simp]
theorem pow_eq_zero_iff' [NoZeroDivisors M] [Nontrivial M] {a : M} {n : ℕ} :
    a ^ n = 0 ↔ a = 0 ∧ n ≠ 0 := by cases (zero_le n).eq_or_gt <;> 

Proof state:
case inl
R : Type u_1
S : Type u_2
M : Type u_3
inst✝² : MonoidWithZero M
inst✝¹ : NoZeroDivisors M
inst✝ : Nontrivial M
a : M
n : ℕ
h✝ : n = 0
⊢ a ^ n = 0 ↔ a = 0 ∧ n ≠ 0

Next tactic:
simp [*, ne_of_gt]
@[simp]
theorem pow_eq_zero_iff' [NoZeroDivisors M] [Nontrivial M] {a : M} {n : ℕ} :
    a ^ n = 0 ↔ a = 0 ∧ n ≠ 0 := by cases (zero_le n).eq_or_gt <;> 

Proof state:
case inr
R : Type u_1
S : Type u_2
M : Type u_3
inst✝² : MonoidWithZero M
inst✝¹ : NoZeroDivisors M
inst✝ : Nontrivial M
a : M
n : ℕ
h✝ : 0 < n
⊢ a ^ n = 0 ↔ a = 0 ∧ n ≠ 0

Next tactic:
simp [*, ne_of_gt]
theorem ne_zero_pow {a : M} {n : ℕ} (hn : n ≠ 0) : a ^ n ≠ 0 → a ≠ 0 := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : MonoidWithZero M
a : M
n : ℕ
hn : n ≠ 0
⊢ a ^ n ≠ 0 → a ≠ 0

Next tactic:
contrapose!
theorem ne_zero_pow {a : M} {n : ℕ} (hn : n ≠ 0) : a ^ n ≠ 0 → a ≠ 0 := by
  contrapose!
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : MonoidWithZero M
a : M
n : ℕ
hn : n ≠ 0
⊢ a = 0 → a ^ n = 0

Next tactic:
rintro rfl
theorem ne_zero_pow {a : M} {n : ℕ} (hn : n ≠ 0) : a ^ n ≠ 0 → a ≠ 0 := by
  contrapose!
  rintro rfl
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : MonoidWithZero M
n : ℕ
hn : n ≠ 0
⊢ 0 ^ n = 0

Next tactic:
exact zero_pow' n hn
@[simp]
theorem zero_pow_eq_zero [Nontrivial M] {n : ℕ} : (0 : M) ^ n = 0 ↔ 0 < n := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : Nontrivial M
n : ℕ
⊢ 0 ^ n = 0 ↔ 0 < n

Next tactic:
constructor
@[simp]
theorem zero_pow_eq_zero [Nontrivial M] {n : ℕ} : (0 : M) ^ n = 0 ↔ 0 < n := by
  constructor <;> 

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : Nontrivial M
n : ℕ
⊢ 0 ^ n = 0 → 0 < n

Next tactic:
intro h
@[simp]
theorem zero_pow_eq_zero [Nontrivial M] {n : ℕ} : (0 : M) ^ n = 0 ↔ 0 < n := by
  constructor <;> 

Proof state:
case mpr
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : Nontrivial M
n : ℕ
⊢ 0 < n → 0 ^ n = 0

Next tactic:
intro h
@[simp]
theorem zero_pow_eq_zero [Nontrivial M] {n : ℕ} : (0 : M) ^ n = 0 ↔ 0 < n := by
  constructor <;> intro h
  · 

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : Nontrivial M
n : ℕ
h : 0 ^ n = 0
⊢ 0 < n

Next tactic:
rw [pos_iff_ne_zero]
@[simp]
theorem zero_pow_eq_zero [Nontrivial M] {n : ℕ} : (0 : M) ^ n = 0 ↔ 0 < n := by
  constructor <;> intro h
  · rw [pos_iff_ne_zero]
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : Nontrivial M
n : ℕ
h : 0 ^ n = 0
⊢ n ≠ 0

Next tactic:
rintro rfl
@[simp]
theorem zero_pow_eq_zero [Nontrivial M] {n : ℕ} : (0 : M) ^ n = 0 ↔ 0 < n := by
  constructor <;> intro h
  · rw [pos_iff_ne_zero]
    rintro rfl
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : Nontrivial M
h : 0 ^ 0 = 0
⊢ False

Next tactic:
simp at h
@[simp]
theorem zero_pow_eq_zero [Nontrivial M] {n : ℕ} : (0 : M) ^ n = 0 ↔ 0 < n := by
  constructor <;> intro h
  · rw [pos_iff_ne_zero]
    rintro rfl
    simp at h
  · 

Proof state:
case mpr
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : MonoidWithZero M
inst✝ : Nontrivial M
n : ℕ
h : 0 < n
⊢ 0 ^ n = 0

Next tactic:
exact zero_pow' n h.ne.symm
theorem Ring.inverse_pow (r : M) : ∀ n : ℕ, Ring.inverse r ^ n = Ring.inverse (r ^ n)
  | 0 => by 

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : MonoidWithZero M
r : M
⊢ inverse r ^ 0 = inverse (r ^ 0)

Next tactic:
rw [pow_zero, pow_zero, Ring.inverse_one]
theorem Ring.inverse_pow (r : M) : ∀ n : ℕ, Ring.inverse r ^ n = Ring.inverse (r ^ n)
  | 0 => by rw [pow_zero, pow_zero, Ring.inverse_one]
  | n + 1 => by
    

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : MonoidWithZero M
r : M
n : ℕ
⊢ inverse r ^ (n + 1) = inverse (r ^ (n + 1))

Next tactic:
rw [pow_succ, pow_succ', Ring.mul_inverse_rev' ((Commute.refl r).pow_left n),
      Ring.inverse_pow r n]
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
⊢ x ^ n ∣ x ^ m ↔ n ≤ m

Next tactic:
constructor
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · 

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
⊢ x ^ n ∣ x ^ m → n ≤ m

Next tactic:
intro h
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
⊢ n ≤ m

Next tactic:
rw [← not_lt]
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
⊢ ¬m < n

Next tactic:
intro hmn
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    intro hmn
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
hmn : m < n
⊢ False

Next tactic:
apply h1
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    intro hmn
    apply h1
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
hmn : m < n
⊢ IsUnit x

Next tactic:
have : x ^ m * x ∣ x ^ m * 1 := by
      rw [← pow_succ', mul_one]
      exact (pow_dvd_pow _ (Nat.succ_le_of_lt hmn)).trans h
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    intro hmn
    apply h1
    have : x ^ m * x ∣ x ^ m * 1 := by
      

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
hmn : m < n
⊢ x ^ m * x ∣ x ^ m * 1

Next tactic:
rw [← pow_succ', mul_one]
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    intro hmn
    apply h1
    have : x ^ m * x ∣ x ^ m * 1 := by
      rw [← pow_succ', mul_one]
      

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
hmn : m < n
⊢ x ^ (m + 1) ∣ x ^ m

Next tactic:
exact (pow_dvd_pow _ (Nat.succ_le_of_lt hmn)).trans h
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    intro hmn
    apply h1
    have : x ^ m * x ∣ x ^ m * 1 := by
      rw [← pow_succ', mul_one]
      exact (pow_dvd_pow _ (Nat.succ_le_of_lt hmn)).trans h
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
hmn : m < n
this : x ^ m * x ∣ x ^ m * 1
⊢ IsUnit x

Next tactic:
rwa [mul_dvd_mul_iff_left, ← isUnit_iff_dvd_one] at this
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    intro hmn
    apply h1
    have : x ^ m * x ∣ x ^ m * 1 := by
      rw [← pow_succ', mul_one]
      exact (pow_dvd_pow _ (Nat.succ_le_of_lt hmn)).trans h
    rwa [mul_dvd_mul_iff_left, ← isUnit_iff_dvd_one] at this
    

Proof state:
case mp
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
h : x ^ n ∣ x ^ m
hmn : m < n
this : x ^ m * x ∣ x ^ m * 1
⊢ x ^ m ≠ 0

Next tactic:
apply pow_ne_zero m h0
theorem pow_dvd_pow_iff [CancelCommMonoidWithZero R] {x : R} {n m : ℕ} (h0 : x ≠ 0)
    (h1 : ¬IsUnit x) : x ^ n ∣ x ^ m ↔ n ≤ m := by
  constructor
  · intro h
    rw [← not_lt]
    intro hmn
    apply h1
    have : x ^ m * x ∣ x ^ m * 1 := by
      rw [← pow_succ', mul_one]
      exact (pow_dvd_pow _ (Nat.succ_le_of_lt hmn)).trans h
    rwa [mul_dvd_mul_iff_left, ← isUnit_iff_dvd_one] at this
    apply pow_ne_zero m h0
  · 

Proof state:
case mpr
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CancelCommMonoidWithZero R
x : R
n m : ℕ
h0 : x ≠ 0
h1 : ¬IsUnit x
⊢ n ≤ m → x ^ n ∣ x ^ m

Next tactic:
apply pow_dvd_pow
theorem min_pow_dvd_add {n m : ℕ} {a b c : R} (ha : c ^ n ∣ a) (hb : c ^ m ∣ b) :
    c ^ min n m ∣ a + b := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Semiring R
inst✝ : Semiring S
n m : ℕ
a b c : R
ha : c ^ n ∣ a
hb : c ^ m ∣ b
⊢ c ^ min n m ∣ a + b

Next tactic:
replace ha := (pow_dvd_pow c (min_le_left n m)).trans ha
theorem min_pow_dvd_add {n m : ℕ} {a b c : R} (ha : c ^ n ∣ a) (hb : c ^ m ∣ b) :
    c ^ min n m ∣ a + b := by
  replace ha := (pow_dvd_pow c (min_le_left n m)).trans ha
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Semiring R
inst✝ : Semiring S
n m : ℕ
a b c : R
hb : c ^ m ∣ b
ha : c ^ min n m ∣ a
⊢ c ^ min n m ∣ a + b

Next tactic:
replace hb := (pow_dvd_pow c (min_le_right n m)).trans hb
theorem min_pow_dvd_add {n m : ℕ} {a b c : R} (ha : c ^ n ∣ a) (hb : c ^ m ∣ b) :
    c ^ min n m ∣ a + b := by
  replace ha := (pow_dvd_pow c (min_le_left n m)).trans ha
  replace hb := (pow_dvd_pow c (min_le_right n m)).trans hb
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Semiring R
inst✝ : Semiring S
n m : ℕ
a b c : R
ha : c ^ min n m ∣ a
hb : c ^ min n m ∣ b
⊢ c ^ min n m ∣ a + b

Next tactic:
exact dvd_add ha hb
theorem add_sq (a b : R) : (a + b) ^ 2 = a ^ 2 + 2 * a * b + b ^ 2 := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CommSemiring R
a b : R
⊢ (a + b) ^ 2 = a ^ 2 + 2 * a * b + b ^ 2

Next tactic:
simp only [sq, add_mul_self_eq]
theorem add_sq' (a b : R) : (a + b) ^ 2 = a ^ 2 + b ^ 2 + 2 * a * b := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CommSemiring R
a b : R
⊢ (a + b) ^ 2 = a ^ 2 + b ^ 2 + 2 * a * b

Next tactic:
rw [add_sq, add_assoc, add_comm _ (b ^ 2), add_assoc]
theorem neg_one_pow_eq_or : ∀ n : ℕ, (-1 : R) ^ n = 1 ∨ (-1 : R) ^ n = -1
  | 0 => Or.inl (pow_zero _)
  | n + 1 => (neg_one_pow_eq_or n).symm.imp
    (fun h ↦ by 

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Monoid R
inst✝ : HasDistribNeg R
n : ℕ
h : (-1) ^ n = -1
⊢ (-1) ^ (n + 1) = 1

Next tactic:
rw [pow_succ, h, neg_one_mul, neg_neg]
theorem neg_one_pow_eq_or : ∀ n : ℕ, (-1 : R) ^ n = 1 ∨ (-1 : R) ^ n = -1
  | 0 => Or.inl (pow_zero _)
  | n + 1 => (neg_one_pow_eq_or n).symm.imp
    (fun h ↦ by rw [pow_succ, h, neg_one_mul, neg_neg])
    (fun h ↦ by 

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Monoid R
inst✝ : HasDistribNeg R
n : ℕ
h : (-1) ^ n = 1
⊢ (-1) ^ (n + 1) = -1

Next tactic:
rw [pow_succ, h, mul_one]
theorem neg_pow_bit0 (a : R) (n : ℕ) : (-a) ^ bit0 n = a ^ bit0 n := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Monoid R
inst✝ : HasDistribNeg R
a : R
n : ℕ
⊢ (-a) ^ bit0 n = a ^ bit0 n

Next tactic:
rw [pow_bit0', neg_mul_neg, pow_bit0']
@[simp]
theorem neg_pow_bit1 (a : R) (n : ℕ) : (-a) ^ bit1 n = -a ^ bit1 n := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Monoid R
inst✝ : HasDistribNeg R
a : R
n : ℕ
⊢ (-a) ^ bit1 n = -a ^ bit1 n

Next tactic:
simp only [bit1, pow_succ, neg_pow_bit0, neg_mul_eq_neg_mul]
theorem neg_sq (a : R) : (-a) ^ 2 = a ^ 2 := by 

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Monoid R
inst✝ : HasDistribNeg R
a : R
⊢ (-a) ^ 2 = a ^ 2

Next tactic:
simp [sq]
theorem neg_one_sq : (-1 : R) ^ 2 = 1 := by 

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Monoid R
inst✝ : HasDistribNeg R
⊢ (-1) ^ 2 = 1

Next tactic:
simp [neg_sq, one_pow]
protected theorem Commute.sq_sub_sq (h : Commute a b) : a ^ 2 - b ^ 2 = (a + b) * (a - b) := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : Ring R
a b : R
h : Commute a b
⊢ a ^ 2 - b ^ 2 = (a + b) * (a - b)

Next tactic:
rw [sq, sq, h.mul_self_sub_mul_self_eq]
@[simp]
theorem neg_one_pow_mul_eq_zero_iff {n : ℕ} {r : R} : (-1) ^ n * r = 0 ↔ r = 0 := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : Ring R
a b : R
n : ℕ
r : R
⊢ (-1) ^ n * r = 0 ↔ r = 0

Next tactic:
rcases neg_one_pow_eq_or R n with h | h
@[simp]
theorem neg_one_pow_mul_eq_zero_iff {n : ℕ} {r : R} : (-1) ^ n * r = 0 ↔ r = 0 := by
  rcases neg_one_pow_eq_or R n with h | h <;> 

Proof state:
case inl
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : Ring R
a b : R
n : ℕ
r : R
h : (-1) ^ n = 1
⊢ (-1) ^ n * r = 0 ↔ r = 0

Next tactic:
simp [h]
@[simp]
theorem neg_one_pow_mul_eq_zero_iff {n : ℕ} {r : R} : (-1) ^ n * r = 0 ↔ r = 0 := by
  rcases neg_one_pow_eq_or R n with h | h <;> 

Proof state:
case inr
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : Ring R
a b : R
n : ℕ
r : R
h : (-1) ^ n = -1
⊢ (-1) ^ n * r = 0 ↔ r = 0

Next tactic:
simp [h]
@[simp]
theorem mul_neg_one_pow_eq_zero_iff {n : ℕ} {r : R} : r * (-1) ^ n = 0 ↔ r = 0 := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : Ring R
a b : R
n : ℕ
r : R
⊢ r * (-1) ^ n = 0 ↔ r = 0

Next tactic:
rcases neg_one_pow_eq_or R n with h | h
@[simp]
theorem mul_neg_one_pow_eq_zero_iff {n : ℕ} {r : R} : r * (-1) ^ n = 0 ↔ r = 0 := by
  rcases neg_one_pow_eq_or R n with h | h <;> 

Proof state:
case inl
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : Ring R
a b : R
n : ℕ
r : R
h : (-1) ^ n = 1
⊢ r * (-1) ^ n = 0 ↔ r = 0

Next tactic:
simp [h]
@[simp]
theorem mul_neg_one_pow_eq_zero_iff {n : ℕ} {r : R} : r * (-1) ^ n = 0 ↔ r = 0 := by
  rcases neg_one_pow_eq_or R n with h | h <;> 

Proof state:
case inr
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : Ring R
a b : R
n : ℕ
r : R
h : (-1) ^ n = -1
⊢ r * (-1) ^ n = 0 ↔ r = 0

Next tactic:
simp [h]
protected theorem Commute.sq_eq_sq_iff_eq_or_eq_neg (h : Commute a b) :
    a ^ 2 = b ^ 2 ↔ a = b ∨ a = -b := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Ring R
a b : R
inst✝ : NoZeroDivisors R
h : Commute a b
⊢ a ^ 2 = b ^ 2 ↔ a = b ∨ a = -b

Next tactic:
rw [← sub_eq_zero, h.sq_sub_sq, mul_eq_zero, add_eq_zero_iff_eq_neg, sub_eq_zero, or_comm]
@[simp]
theorem sq_eq_one_iff : a ^ 2 = 1 ↔ a = 1 ∨ a = -1 := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : Ring R
a b : R
inst✝ : NoZeroDivisors R
⊢ a ^ 2 = 1 ↔ a = 1 ∨ a = -1

Next tactic:
rw [← (Commute.one_right a).sq_eq_sq_iff_eq_or_eq_neg, one_pow]
theorem sub_sq (a b : R) : (a - b) ^ 2 = a ^ 2 - 2 * a * b + b ^ 2 := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CommRing R
a b : R
⊢ (a - b) ^ 2 = a ^ 2 - 2 * a * b + b ^ 2

Next tactic:
rw [sub_eq_add_neg, add_sq, neg_sq, mul_neg, ← sub_eq_add_neg]
theorem sub_sq' (a b : R) : (a - b) ^ 2 = a ^ 2 + b ^ 2 - 2 * a * b := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝ : CommRing R
a b : R
⊢ (a - b) ^ 2 = a ^ 2 + b ^ 2 - 2 * a * b

Next tactic:
rw [sub_eq_add_neg, add_sq', neg_sq, mul_neg, ← sub_eq_add_neg]
protected theorem sq_eq_sq_iff_eq_or_eq_neg {a b : Rˣ} : a ^ 2 = b ^ 2 ↔ a = b ∨ a = -b := by
  

Proof state:
R : Type u_1
S : Type u_2
M : Type u_3
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
a✝ b✝ : R
a b : Rˣ
⊢ a ^ 2 = b ^ 2 ↔ a = b ∨ a = -b

Next tactic:
simp_rw [ext_iff, val_pow_eq_pow_val, sq_eq_sq_iff_eq_or_eq_neg, Units.val_neg]
/-- `think c` is the computation that delays for one "tick" and then performs
  computation `c`. -/
def think (c : Computation α) : Computation α :=
  ⟨Stream'.cons none c.1, fun n a h => by
    

Proof state:
α : Type u
β : Type v
γ : Type w
c : Computation α
n : ℕ
a : α
h : Stream'.cons none (↑c) n = some a
⊢ Stream'.cons none (↑c) (n + 1) = some a

Next tactic:
cases' n with n
/-- `think c` is the computation that delays for one "tick" and then performs
  computation `c`. -/
def think (c : Computation α) : Computation α :=
  ⟨Stream'.cons none c.1, fun n a h => by
    cases' n with n
    · 

Proof state:
case zero
α : Type u
β : Type v
γ : Type w
c : Computation α
a : α
h : Stream'.cons none (↑c) Nat.zero = some a
⊢ Stream'.cons none (↑c) (Nat.zero + 1) = some a

Next tactic:
contradiction
/-- `think c` is the computation that delays for one "tick" and then performs
  computation `c`. -/
def think (c : Computation α) : Computation α :=
  ⟨Stream'.cons none c.1, fun n a h => by
    cases' n with n
    · contradiction
    · 

Proof state:
case succ
α : Type u
β : Type v
γ : Type w
c : Computation α
a : α
n : ℕ
h : Stream'.cons none (↑c) (Nat.succ n) = some a
⊢ Stream'.cons none (↑c) (Nat.succ n + 1) = some a

Next tactic:
exact c.2 h
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
s : Computation α
a : α
⊢ destruct s = Sum.inl a → s = pure a

Next tactic:
dsimp [destruct]
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  

Proof state:
α : Type u
β : Type v
γ : Type w
s : Computation α
a : α
⊢ (match ↑s 0 with
      | none => Sum.inr (tail s)
      | some a => Sum.inl a) =
      Sum.inl a →
    s = pure a

Next tactic:
induction' f0 : s.1 0 with _
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> 

Proof state:
case none
α : Type u
β : Type v
γ : Type w
s : Computation α
a : α
f0 : ↑s 0 = none
⊢ (match none with
      | none => Sum.inr (tail s)
      | some a => Sum.inl a) =
      Sum.inl a →
    s = pure a

Next tactic:
intro h
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> 

Proof state:
case some
α : Type u
β : Type v
γ : Type w
s : Computation α
a val✝ : α
f0 : ↑s 0 = some val✝
⊢ (match some val✝ with
      | none => Sum.inr (tail s)
      | some a => Sum.inl a) =
      Sum.inl a →
    s = pure a

Next tactic:
intro h
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> intro h
  · 

Proof state:
case none
α : Type u
β : Type v
γ : Type w
s : Computation α
a : α
f0 : ↑s 0 = none
h :
  (match none with
    | none => Sum.inr (tail s)
    | some a => Sum.inl a) =
    Sum.inl a
⊢ s = pure a

Next tactic:
contradiction
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> intro h
  · contradiction
  · 

Proof state:
case some
α : Type u
β : Type v
γ : Type w
s : Computation α
a val✝ : α
f0 : ↑s 0 = some val✝
h :
  (match some val✝ with
    | none => Sum.inr (tail s)
    | some a => Sum.inl a) =
    Sum.inl a
⊢ s = pure a

Next tactic:
apply Subtype.eq
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> intro h
  · contradiction
  · apply Subtype.eq
    

Proof state:
case some.a
α : Type u
β : Type v
γ : Type w
s : Computation α
a val✝ : α
f0 : ↑s 0 = some val✝
h :
  (match some val✝ with
    | none => Sum.inr (tail s)
    | some a => Sum.inl a) =
    Sum.inl a
⊢ ↑s = ↑(pure a)

Next tactic:
funext n
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> intro h
  · contradiction
  · apply Subtype.eq
    funext n
    

Proof state:
case some.a.h
α : Type u
β : Type v
γ : Type w
s : Computation α
a val✝ : α
f0 : ↑s 0 = some val✝
h :
  (match some val✝ with
    | none => Sum.inr (tail s)
    | some a => Sum.inl a) =
    Sum.inl a
n : ℕ
⊢ ↑s n = ↑(pure a) n

Next tactic:
induction' n with n IH
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> intro h
  · contradiction
  · apply Subtype.eq
    funext n
    induction' n with n IH
    · 

Proof state:
case some.a.h.zero
α : Type u
β : Type v
γ : Type w
s : Computation α
a val✝ : α
f0 : ↑s 0 = some val✝
h :
  (match some val✝ with
    | none => Sum.inr (tail s)
    | some a => Sum.inl a) =
    Sum.inl a
⊢ ↑s Nat.zero = ↑(pure a) Nat.zero

Next tactic:
injection h with h'
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> intro h
  · contradiction
  · apply Subtype.eq
    funext n
    induction' n with n IH
    · injection h with h'
      

Proof state:
case some.a.h.zero
α : Type u
β : Type v
γ : Type w
s : Computation α
a val✝ : α
f0 : ↑s 0 = some val✝
h' : val✝ = a
⊢ ↑s Nat.zero = ↑(pure a) Nat.zero

Next tactic:
rwa [h'] at f0
theorem destruct_eq_pure {s : Computation α} {a : α} : destruct s = Sum.inl a → s = pure a := by
  dsimp [destruct]
  induction' f0 : s.1 0 with _ <;> intro h
  · contradiction
  · apply Subtype.eq
    funext n
    induction' n with n IH
    · injection h with h'
      rwa [h'] at f0
    · 

Proof state:
case some.a.h.succ
α : Type u
β : Type v
γ : Type w
s : Computation α
a val✝ : α
f0 : ↑s 0 = some val✝
h :
  (match some val✝ with
    | none => Sum.inr (tail s)
    | some a => Sum.inl a) =
    Sum.inl a
n : ℕ
IH : ↑s n = ↑(pure a) n
⊢ ↑s (Nat.succ n) = ↑(pure a) (Nat.succ n)

Next tactic:
exact s.2 IH
theorem destruct_eq_think {s : Computation α} {s'} : destruct s = Sum.inr s' → s = think s' := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
s s' : Computation α
⊢ destruct s = Sum.inr s' → s = think s'

Next tactic:
dsimp [destruct]
theorem destruct_eq_think {s : Computation α} {s'} : destruct s = Sum.inr s' → s = think s' := by
  dsimp [destruct]
  

Proof state:
α : Type u
β : Type v
γ : Type w
s s' : Computation α
⊢ (match ↑s 0 with
      | none => Sum.inr (tail s)
      | some a => Sum.inl a) =
      Sum.inr s' →
    s = think s'

Next tactic:
induction' f0 : s.1 0 with a'
theorem destruct_eq_think {s : Computation α} {s'} : destruct s = Sum.inr s' → s = think s' := by
  dsimp [destruct]
  induction' f0 : s.1 0 with a' <;> 

Proof state:
case none
α : Type u
β : Type v
γ : Type w
s s' : Computation α
f0 : ↑s 0 = none
⊢ (match none with
      | none => Sum.inr (tail s)
      | some a => Sum.inl a) =
      Sum.inr s' →
    s = think s'

Next tactic:
intro h
theorem destruct_eq_think {s : Computation α} {s'} : destruct s = Sum.inr s' → s = think s' := by
  dsimp [destruct]
  induction' f0 : s.1 0 with a' <;> 

Proof state:
case some
α : Type u
β : Type v
γ : Type w
s s' : Computation α
a' : α
f0 : ↑s 0 = some a'
⊢ (match some a' with
      | none => Sum.inr (tail s)
      | some a => Sum.inl a) =
      Sum.inr s' →
    s = think s'

Next tactic:
intro h