l3lab/ntp-mathlib huggingface dataset:
/-- The `PNat` version of `Nat.findX` -/
protected def findX : { n // p n ∧ ∀ m : ℕ+, m < n → ¬p m } := by
  have : ∃ (n' : ℕ) (n : ℕ+) (_ : n' = n), p n := Exists.elim h fun n hn => ⟨n, n, rfl, hn⟩
  have n := Nat.findX this
  refine' ⟨⟨n, _⟩, _, fun m hm pm => _⟩
  · obtain ⟨n', hn', -⟩ := n.prop.1
    rw [hn']
    exact n'.prop
  · obtain ⟨n', hn', pn'⟩ := n.prop.1
    

Proof state:
case refine'_2.intro.intro
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
this : ∃ n' n, ∃ (_ : n' = ↑n), p n
n : { n // (∃ n_1, ∃ (_ : n = ↑n_1), p n_1) ∧ ∀ m < n, ¬∃ n, ∃ (_ : m = ↑n), p n }
n' : ℕ+
hn' : ↑n = ↑n'
pn' : p n'
⊢ p { val := ↑n, property := (_ : 0 < ↑n) }

Next tactic:
simpa [hn', Subtype.coe_eta] using pn'
/-- The `PNat` version of `Nat.findX` -/
protected def findX : { n // p n ∧ ∀ m : ℕ+, m < n → ¬p m } := by
  have : ∃ (n' : ℕ) (n : ℕ+) (_ : n' = n), p n := Exists.elim h fun n hn => ⟨n, n, rfl, hn⟩
  have n := Nat.findX this
  refine' ⟨⟨n, _⟩, _, fun m hm pm => _⟩
  · obtain ⟨n', hn', -⟩ := n.prop.1
    rw [hn']
    exact n'.prop
  · obtain ⟨n', hn', pn'⟩ := n.prop.1
    simpa [hn', Subtype.coe_eta] using pn'
  · 

Proof state:
case refine'_3
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
this : ∃ n' n, ∃ (_ : n' = ↑n), p n
n : { n // (∃ n_1, ∃ (_ : n = ↑n_1), p n_1) ∧ ∀ m < n, ¬∃ n, ∃ (_ : m = ↑n), p n }
m : ℕ+
hm : m < { val := ↑n, property := (_ : 0 < ↑n) }
pm : p m
⊢ False

Next tactic:
exact n.prop.2 m hm ⟨m, rfl, pm⟩
theorem find_eq_iff : PNat.find h = m ↔ p m ∧ ∀ n < m, ¬p n := by
  

Proof state:
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n m : ℕ+
⊢ PNat.find h = m ↔ p m ∧ ∀ n < m, ¬p n

Next tactic:
constructor
theorem find_eq_iff : PNat.find h = m ↔ p m ∧ ∀ n < m, ¬p n := by
  constructor
  · 

Proof state:
case mp
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n m : ℕ+
⊢ PNat.find h = m → p m ∧ ∀ n < m, ¬p n

Next tactic:
rintro rfl
theorem find_eq_iff : PNat.find h = m ↔ p m ∧ ∀ n < m, ¬p n := by
  constructor
  · rintro rfl
    

Proof state:
case mp
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n : ℕ+
⊢ p (PNat.find h) ∧ ∀ n < PNat.find h, ¬p n

Next tactic:
exact ⟨PNat.find_spec h, fun _ => PNat.find_min h⟩
theorem find_eq_iff : PNat.find h = m ↔ p m ∧ ∀ n < m, ¬p n := by
  constructor
  · rintro rfl
    exact ⟨PNat.find_spec h, fun _ => PNat.find_min h⟩
  · 

Proof state:
case mpr
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n m : ℕ+
⊢ (p m ∧ ∀ n < m, ¬p n) → PNat.find h = m

Next tactic:
rintro ⟨hm, hlt⟩
theorem find_eq_iff : PNat.find h = m ↔ p m ∧ ∀ n < m, ¬p n := by
  constructor
  · rintro rfl
    exact ⟨PNat.find_spec h, fun _ => PNat.find_min h⟩
  · rintro ⟨hm, hlt⟩
    

Proof state:
case mpr.intro
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n m : ℕ+
hm : p m
hlt : ∀ n < m, ¬p n
⊢ PNat.find h = m

Next tactic:
exact le_antisymm (PNat.find_min' h hm) (not_lt.1 <| imp_not_comm.1 (hlt _) <| PNat.find_spec h)
@[simp]
theorem find_le_iff (n : ℕ+) : PNat.find h ≤ n ↔ ∃ m ≤ n, p m := by
  

Proof state:
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n✝ m n : ℕ+
⊢ PNat.find h ≤ n ↔ ∃ m ≤ n, p m

Next tactic:
simp only [exists_prop, ← lt_add_one_iff, find_lt_iff]
@[simp]
theorem le_find_iff (n : ℕ+) : n ≤ PNat.find h ↔ ∀ m < n, ¬p m := by
  

Proof state:
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n✝ m n : ℕ+
⊢ n ≤ PNat.find h ↔ ∀ m < n, ¬p m

Next tactic:
simp only [← not_lt, find_lt_iff, not_exists, not_and]
@[simp]
theorem lt_find_iff (n : ℕ+) : n < PNat.find h ↔ ∀ m ≤ n, ¬p m := by
  

Proof state:
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n✝ m n : ℕ+
⊢ n < PNat.find h ↔ ∀ m ≤ n, ¬p m

Next tactic:
simp only [← add_one_le_iff, le_find_iff, add_le_add_iff_right]
@[simp]
theorem find_eq_one : PNat.find h = 1 ↔ p 1 := by 

Proof state:
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n m : ℕ+
⊢ PNat.find h = 1 ↔ p 1

Next tactic:
simp [find_eq_iff]
theorem one_le_find : 1 < PNat.find h ↔ ¬p 1 :=
  not_iff_not.mp <| by 

Proof state:
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h : ∃ n, p n
n m : ℕ+
⊢ ¬1 < PNat.find h ↔ ¬¬p 1

Next tactic:
simp
theorem find_comp_succ (h : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h1 : ¬p 1) :
    PNat.find h = PNat.find h₂ + 1 := by
  

Proof state:
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h✝ : ∃ n, p n
n m : ℕ+
h : ∃ n, p n
h₂ : ∃ n, p (n + 1)
h1 : ¬p 1
⊢ PNat.find h = PNat.find h₂ + 1

Next tactic:
refine' (find_eq_iff _).2 ⟨PNat.find_spec h₂, fun n => PNat.recOn n _ _⟩
theorem find_comp_succ (h : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h1 : ¬p 1) :
    PNat.find h = PNat.find h₂ + 1 := by
  refine' (find_eq_iff _).2 ⟨PNat.find_spec h₂, fun n => PNat.recOn n _ _⟩
  · 

Proof state:
case refine'_1
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h✝ : ∃ n, p n
n✝ m : ℕ+
h : ∃ n, p n
h₂ : ∃ n, p (n + 1)
h1 : ¬p 1
n : ℕ+
⊢ 1 < PNat.find h₂ + 1 → ¬p 1

Next tactic:
simp [h1]
theorem find_comp_succ (h : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h1 : ¬p 1) :
    PNat.find h = PNat.find h₂ + 1 := by
  refine' (find_eq_iff _).2 ⟨PNat.find_spec h₂, fun n => PNat.recOn n _ _⟩
  · simp [h1]
  

Proof state:
case refine'_2
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h✝ : ∃ n, p n
n✝ m : ℕ+
h : ∃ n, p n
h₂ : ∃ n, p (n + 1)
h1 : ¬p 1
n : ℕ+
⊢ ∀ (n : ℕ+), (n < PNat.find h₂ + 1 → ¬p n) → n + 1 < PNat.find h₂ + 1 → ¬p (n + 1)

Next tactic:
intro m _ hm
theorem find_comp_succ (h : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h1 : ¬p 1) :
    PNat.find h = PNat.find h₂ + 1 := by
  refine' (find_eq_iff _).2 ⟨PNat.find_spec h₂, fun n => PNat.recOn n _ _⟩
  · simp [h1]
  intro m _ hm
  

Proof state:
case refine'_2
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h✝ : ∃ n, p n
n✝ m✝ : ℕ+
h : ∃ n, p n
h₂ : ∃ n, p (n + 1)
h1 : ¬p 1
n m : ℕ+
a✝ : m < PNat.find h₂ + 1 → ¬p m
hm : m + 1 < PNat.find h₂ + 1
⊢ ¬p (m + 1)

Next tactic:
simp only [add_lt_add_iff_right, lt_find_iff] at hm
theorem find_comp_succ (h : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h1 : ¬p 1) :
    PNat.find h = PNat.find h₂ + 1 := by
  refine' (find_eq_iff _).2 ⟨PNat.find_spec h₂, fun n => PNat.recOn n _ _⟩
  · simp [h1]
  intro m _ hm
  simp only [add_lt_add_iff_right, lt_find_iff] at hm
  

Proof state:
case refine'_2
p q : ℕ+ → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
h✝ : ∃ n, p n
n✝ m✝ : ℕ+
h : ∃ n, p n
h₂ : ∃ n, p (n + 1)
h1 : ¬p 1
n m : ℕ+
a✝ : m < PNat.find h₂ + 1 → ¬p m
hm : ∀ m_1 ≤ m, ¬p (m_1 + 1)
⊢ ¬p (m + 1)

Next tactic:
exact hm _ le_rfl
theorem circulant_injective [AddGroup n] : Injective (circulant : (n → α) → Matrix n n α) := by
  

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : AddGroup n
⊢ Injective circulant

Next tactic:
intro v w h
theorem circulant_injective [AddGroup n] : Injective (circulant : (n → α) → Matrix n n α) := by
  intro v w h
  

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : AddGroup n
v w : n → α
h : circulant v = circulant w
⊢ v = w

Next tactic:
ext k
theorem circulant_injective [AddGroup n] : Injective (circulant : (n → α) → Matrix n n α) := by
  intro v w h
  ext k
  

Proof state:
case h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : AddGroup n
v w : n → α
h : circulant v = circulant w
k : n
⊢ v k = w k

Next tactic:
rw [← circulant_col_zero_eq v, ← circulant_col_zero_eq w, h]
theorem Fin.circulant_injective : ∀ n, Injective fun v : Fin n → α => circulant v
  | 0 => by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
⊢ Injective fun v => circulant v

Next tactic:
simp [Injective]
theorem transpose_circulant [AddGroup n] (v : n → α) :
    (circulant v)ᵀ = circulant fun i => v (-i) := by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : AddGroup n
v : n → α
⊢ (circulant v)ᵀ = circulant fun i => v (-i)

Next tactic:
ext
theorem transpose_circulant [AddGroup n] (v : n → α) :
    (circulant v)ᵀ = circulant fun i => v (-i) := by ext; 

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : AddGroup n
v : n → α
i✝ x✝ : n
⊢ (circulant v)ᵀ i✝ x✝ = circulant (fun i => v (-i)) i✝ x✝

Next tactic:
simp
theorem conjTranspose_circulant [Star α] [AddGroup n] (v : n → α) :
    (circulant v)ᴴ = circulant (star fun i => v (-i)) := by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝¹ : Star α
inst✝ : AddGroup n
v : n → α
⊢ (circulant v)ᴴ = circulant (star fun i => v (-i))

Next tactic:
ext
theorem conjTranspose_circulant [Star α] [AddGroup n] (v : n → α) :
    (circulant v)ᴴ = circulant (star fun i => v (-i)) := by ext; 

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝¹ : Star α
inst✝ : AddGroup n
v : n → α
i✝ x✝ : n
⊢ (circulant v)ᴴ i✝ x✝ = circulant (star fun i => v (-i)) i✝ x✝

Next tactic:
simp
theorem Fin.transpose_circulant : ∀ {n} (v : Fin n → α), (circulant v)ᵀ = circulant fun i => v (-i)
  | 0 => by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
⊢ ∀ (v : Fin 0 → α), (circulant v)ᵀ = circulant fun i => v (-i)

Next tactic:
simp [Injective, eq_iff_true_of_subsingleton]
theorem Fin.conjTranspose_circulant [Star α] :
    ∀ {n} (v : Fin n → α), (circulant v)ᴴ = circulant (star fun i => v (-i))
  | 0 => by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : Star α
⊢ ∀ (v : Fin 0 → α), (circulant v)ᴴ = circulant (star fun i => v (-i))

Next tactic:
simp [Injective, eq_iff_true_of_subsingleton]
/-- The product of two circulant matrices `circulant v` and `circulant w` is
    the circulant matrix generated by `mulVec (circulant v) w`. -/
theorem circulant_mul [Semiring α] [Fintype n] [AddGroup n] (v w : n → α) :
    circulant v * circulant w = circulant (mulVec (circulant v) w) := by
  

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝² : Semiring α
inst✝¹ : Fintype n
inst✝ : AddGroup n
v w : n → α
⊢ circulant v * circulant w = circulant (mulVec (circulant v) w)

Next tactic:
ext i j
/-- The product of two circulant matrices `circulant v` and `circulant w` is
    the circulant matrix generated by `mulVec (circulant v) w`. -/
theorem circulant_mul [Semiring α] [Fintype n] [AddGroup n] (v w : n → α) :
    circulant v * circulant w = circulant (mulVec (circulant v) w) := by
  ext i j
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝² : Semiring α
inst✝¹ : Fintype n
inst✝ : AddGroup n
v w : n → α
i j : n
⊢ (circulant v * circulant w) i j = circulant (mulVec (circulant v) w) i j

Next tactic:
simp only [mul_apply, mulVec, circulant_apply, dotProduct]
/-- The product of two circulant matrices `circulant v` and `circulant w` is
    the circulant matrix generated by `mulVec (circulant v) w`. -/
theorem circulant_mul [Semiring α] [Fintype n] [AddGroup n] (v w : n → α) :
    circulant v * circulant w = circulant (mulVec (circulant v) w) := by
  ext i j
  simp only [mul_apply, mulVec, circulant_apply, dotProduct]
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝² : Semiring α
inst✝¹ : Fintype n
inst✝ : AddGroup n
v w : n → α
i j : n
⊢ ∑ x : n, v (i - x) * w (x - j) = ∑ x : n, v (i - j - x) * w x

Next tactic:
refine' Fintype.sum_equiv (Equiv.subRight j) _ _ _
/-- The product of two circulant matrices `circulant v` and `circulant w` is
    the circulant matrix generated by `mulVec (circulant v) w`. -/
theorem circulant_mul [Semiring α] [Fintype n] [AddGroup n] (v w : n → α) :
    circulant v * circulant w = circulant (mulVec (circulant v) w) := by
  ext i j
  simp only [mul_apply, mulVec, circulant_apply, dotProduct]
  refine' Fintype.sum_equiv (Equiv.subRight j) _ _ _
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝² : Semiring α
inst✝¹ : Fintype n
inst✝ : AddGroup n
v w : n → α
i j : n
⊢ ∀ (x : n), v (i - x) * w (x - j) = v (i - j - (Equiv.subRight j) x) * w ((Equiv.subRight j) x)

Next tactic:
intro x
/-- The product of two circulant matrices `circulant v` and `circulant w` is
    the circulant matrix generated by `mulVec (circulant v) w`. -/
theorem circulant_mul [Semiring α] [Fintype n] [AddGroup n] (v w : n → α) :
    circulant v * circulant w = circulant (mulVec (circulant v) w) := by
  ext i j
  simp only [mul_apply, mulVec, circulant_apply, dotProduct]
  refine' Fintype.sum_equiv (Equiv.subRight j) _ _ _
  intro x
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝² : Semiring α
inst✝¹ : Fintype n
inst✝ : AddGroup n
v w : n → α
i j x : n
⊢ v (i - x) * w (x - j) = v (i - j - (Equiv.subRight j) x) * w ((Equiv.subRight j) x)

Next tactic:
simp only [Equiv.subRight_apply, sub_sub_sub_cancel_right]
theorem Fin.circulant_mul [Semiring α] :
    ∀ {n} (v w : Fin n → α), circulant v * circulant w = circulant (mulVec (circulant v) w)
  | 0 => by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : Semiring α
⊢ ∀ (v w : Fin 0 → α), circulant v * circulant w = circulant (mulVec (circulant v) w)

Next tactic:
simp [Injective, eq_iff_true_of_subsingleton]
/-- Multiplication of circulant matrices commutes when the elements do. -/
theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n]
    (v w : n → α) : circulant v * circulant w = circulant w * circulant v := by
  

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝³ : CommSemigroup α
inst✝² : AddCommMonoid α
inst✝¹ : Fintype n
inst✝ : AddCommGroup n
v w : n → α
⊢ circulant v * circulant w = circulant w * circulant v

Next tactic:
ext i j
/-- Multiplication of circulant matrices commutes when the elements do. -/
theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n]
    (v w : n → α) : circulant v * circulant w = circulant w * circulant v := by
  ext i j
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝³ : CommSemigroup α
inst✝² : AddCommMonoid α
inst✝¹ : Fintype n
inst✝ : AddCommGroup n
v w : n → α
i j : n
⊢ (circulant v * circulant w) i j = (circulant w * circulant v) i j

Next tactic:
simp only [mul_apply, circulant_apply, mul_comm]
/-- Multiplication of circulant matrices commutes when the elements do. -/
theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n]
    (v w : n → α) : circulant v * circulant w = circulant w * circulant v := by
  ext i j
  simp only [mul_apply, circulant_apply, mul_comm]
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝³ : CommSemigroup α
inst✝² : AddCommMonoid α
inst✝¹ : Fintype n
inst✝ : AddCommGroup n
v w : n → α
i j : n
⊢ ∑ x : n, v (i - x) * w (x - j) = ∑ x : n, w (i - x) * v (x - j)

Next tactic:
refine' Fintype.sum_equiv ((Equiv.subLeft i).trans (Equiv.addRight j)) _ _ _
/-- Multiplication of circulant matrices commutes when the elements do. -/
theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n]
    (v w : n → α) : circulant v * circulant w = circulant w * circulant v := by
  ext i j
  simp only [mul_apply, circulant_apply, mul_comm]
  refine' Fintype.sum_equiv ((Equiv.subLeft i).trans (Equiv.addRight j)) _ _ _
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝³ : CommSemigroup α
inst✝² : AddCommMonoid α
inst✝¹ : Fintype n
inst✝ : AddCommGroup n
v w : n → α
i j : n
⊢ ∀ (x : n),
    v (i - x) * w (x - j) =
      w (i - ((Equiv.subLeft i).trans (Equiv.addRight j)) x) * v (((Equiv.subLeft i).trans (Equiv.addRight j)) x - j)

Next tactic:
intro x
/-- Multiplication of circulant matrices commutes when the elements do. -/
theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n]
    (v w : n → α) : circulant v * circulant w = circulant w * circulant v := by
  ext i j
  simp only [mul_apply, circulant_apply, mul_comm]
  refine' Fintype.sum_equiv ((Equiv.subLeft i).trans (Equiv.addRight j)) _ _ _
  intro x
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝³ : CommSemigroup α
inst✝² : AddCommMonoid α
inst✝¹ : Fintype n
inst✝ : AddCommGroup n
v w : n → α
i j x : n
⊢ v (i - x) * w (x - j) =
    w (i - ((Equiv.subLeft i).trans (Equiv.addRight j)) x) * v (((Equiv.subLeft i).trans (Equiv.addRight j)) x - j)

Next tactic:
simp only [Equiv.trans_apply, Equiv.subLeft_apply, Equiv.coe_addRight, add_sub_cancel, mul_comm]
/-- Multiplication of circulant matrices commutes when the elements do. -/
theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n]
    (v w : n → α) : circulant v * circulant w = circulant w * circulant v := by
  ext i j
  simp only [mul_apply, circulant_apply, mul_comm]
  refine' Fintype.sum_equiv ((Equiv.subLeft i).trans (Equiv.addRight j)) _ _ _
  intro x
  simp only [Equiv.trans_apply, Equiv.subLeft_apply, Equiv.coe_addRight, add_sub_cancel, mul_comm]
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝³ : CommSemigroup α
inst✝² : AddCommMonoid α
inst✝¹ : Fintype n
inst✝ : AddCommGroup n
v w : n → α
i j x : n
⊢ v (i - x) * w (x - j) = v (i - x) * w (i - (i - x + j))

Next tactic:
congr 2
/-- Multiplication of circulant matrices commutes when the elements do. -/
theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n]
    (v w : n → α) : circulant v * circulant w = circulant w * circulant v := by
  ext i j
  simp only [mul_apply, circulant_apply, mul_comm]
  refine' Fintype.sum_equiv ((Equiv.subLeft i).trans (Equiv.addRight j)) _ _ _
  intro x
  simp only [Equiv.trans_apply, Equiv.subLeft_apply, Equiv.coe_addRight, add_sub_cancel, mul_comm]
  congr 2
  

Proof state:
case a.h.e_a.e_a
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝³ : CommSemigroup α
inst✝² : AddCommMonoid α
inst✝¹ : Fintype n
inst✝ : AddCommGroup n
v w : n → α
i j x : n
⊢ x - j = i - (i - x + j)

Next tactic:
abel
theorem Fin.circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] :
    ∀ {n} (v w : Fin n → α), circulant v * circulant w = circulant w * circulant v
  | 0 => by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝¹ : CommSemigroup α
inst✝ : AddCommMonoid α
⊢ ∀ (v w : Fin 0 → α), circulant v * circulant w = circulant w * circulant v

Next tactic:
simp [Injective]
@[simp]
theorem circulant_single_one (α n) [Zero α] [One α] [DecidableEq n] [AddGroup n] :
    circulant (Pi.single 0 1 : n → α) = (1 : Matrix n n α) := by
  

Proof state:
α✝ : Type u_1
β : Type u_2
m : Type u_3
n✝ : Type u_4
R : Type u_5
α : Type u_6
n : Type u_7
inst✝³ : Zero α
inst✝² : One α
inst✝¹ : DecidableEq n
inst✝ : AddGroup n
⊢ circulant (Pi.single 0 1) = 1

Next tactic:
ext i j
@[simp]
theorem circulant_single_one (α n) [Zero α] [One α] [DecidableEq n] [AddGroup n] :
    circulant (Pi.single 0 1 : n → α) = (1 : Matrix n n α) := by
  ext i j
  

Proof state:
case a.h
α✝ : Type u_1
β : Type u_2
m : Type u_3
n✝ : Type u_4
R : Type u_5
α : Type u_6
n : Type u_7
inst✝³ : Zero α
inst✝² : One α
inst✝¹ : DecidableEq n
inst✝ : AddGroup n
i j : n
⊢ circulant (Pi.single 0 1) i j = OfNat.ofNat 1 i j

Next tactic:
simp [one_apply, Pi.single_apply, sub_eq_zero]
@[simp]
theorem circulant_single (n) [Semiring α] [DecidableEq n] [AddGroup n] [Fintype n] (a : α) :
    circulant (Pi.single 0 a : n → α) = scalar n a := by
  

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n✝ : Type u_4
R : Type u_5
n : Type u_6
inst✝³ : Semiring α
inst✝² : DecidableEq n
inst✝¹ : AddGroup n
inst✝ : Fintype n
a : α
⊢ circulant (Pi.single 0 a) = (scalar n) a

Next tactic:
ext i j
@[simp]
theorem circulant_single (n) [Semiring α] [DecidableEq n] [AddGroup n] [Fintype n] (a : α) :
    circulant (Pi.single 0 a : n → α) = scalar n a := by
  ext i j
  

Proof state:
case a.h
α : Type u_1
β : Type u_2
m : Type u_3
n✝ : Type u_4
R : Type u_5
n : Type u_6
inst✝³ : Semiring α
inst✝² : DecidableEq n
inst✝¹ : AddGroup n
inst✝ : Fintype n
a : α
i j : n
⊢ circulant (Pi.single 0 a) i j = (scalar n) a i j

Next tactic:
simp [Pi.single_apply, diagonal_apply, sub_eq_zero]
/-- Note we use `↑i = 0` instead of `i = 0` as `Fin 0` has no `0`.
This means that we cannot state this with `Pi.single` as we did with `Matrix.circulant_single`. -/
theorem Fin.circulant_ite (α) [Zero α] [One α] :
    ∀ n, circulant (fun i => ite (i.1 = 0) 1 0 : Fin n → α) = 1
  | 0 => by 

Proof state:
α✝ : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
α : Type u_6
inst✝¹ : Zero α
inst✝ : One α
⊢ (circulant fun i => if ↑i = 0 then 1 else 0) = 1

Next tactic:
simp [Injective, eq_iff_true_of_subsingleton]
/-- Note we use `↑i = 0` instead of `i = 0` as `Fin 0` has no `0`.
This means that we cannot state this with `Pi.single` as we did with `Matrix.circulant_single`. -/
theorem Fin.circulant_ite (α) [Zero α] [One α] :
    ∀ n, circulant (fun i => ite (i.1 = 0) 1 0 : Fin n → α) = 1
  | 0 => by simp [Injective, eq_iff_true_of_subsingleton]
  | n + 1 => by
    

Proof state:
α✝ : Type u_1
β : Type u_2
m : Type u_3
n✝ : Type u_4
R : Type u_5
α : Type u_6
inst✝¹ : Zero α
inst✝ : One α
n : ℕ
⊢ (circulant fun i => if ↑i = 0 then 1 else 0) = 1

Next tactic:
rw [← circulant_single_one]
/-- Note we use `↑i = 0` instead of `i = 0` as `Fin 0` has no `0`.
This means that we cannot state this with `Pi.single` as we did with `Matrix.circulant_single`. -/
theorem Fin.circulant_ite (α) [Zero α] [One α] :
    ∀ n, circulant (fun i => ite (i.1 = 0) 1 0 : Fin n → α) = 1
  | 0 => by simp [Injective, eq_iff_true_of_subsingleton]
  | n + 1 => by
    rw [← circulant_single_one]
    

Proof state:
α✝ : Type u_1
β : Type u_2
m : Type u_3
n✝ : Type u_4
R : Type u_5
α : Type u_6
inst✝¹ : Zero α
inst✝ : One α
n : ℕ
⊢ (circulant fun i => if ↑i = 0 then 1 else 0) = circulant (Pi.single 0 1)

Next tactic:
congr with j
/-- Note we use `↑i = 0` instead of `i = 0` as `Fin 0` has no `0`.
This means that we cannot state this with `Pi.single` as we did with `Matrix.circulant_single`. -/
theorem Fin.circulant_ite (α) [Zero α] [One α] :
    ∀ n, circulant (fun i => ite (i.1 = 0) 1 0 : Fin n → α) = 1
  | 0 => by simp [Injective, eq_iff_true_of_subsingleton]
  | n + 1 => by
    rw [← circulant_single_one]
    congr with j
    

Proof state:
case a.h
α✝ : Type u_1
β : Type u_2
m : Type u_3
n✝ : Type u_4
R : Type u_5
α : Type u_6
inst✝¹ : Zero α
inst✝ : One α
n : ℕ
j x✝ : Fin (n + 1)
⊢ circulant (fun i => if ↑i = 0 then 1 else 0) j x✝ = circulant (Pi.single 0 1) j x✝

Next tactic:
simp [Pi.single_apply, Fin.ext_iff]
/-- A circulant of `v` is symmetric iff `v` equals its reverse. -/
theorem circulant_isSymm_iff [AddGroup n] {v : n → α} :
    (circulant v).IsSymm ↔ ∀ i, v (-i) = v i := by
  

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
inst✝ : AddGroup n
v : n → α
⊢ IsSymm (circulant v) ↔ ∀ (i : n), v (-i) = v i

Next tactic:
rw [IsSymm, transpose_circulant, circulant_inj, funext_iff]
theorem Fin.circulant_isSymm_iff : ∀ {n} {v : Fin n → α}, (circulant v).IsSymm ↔ ∀ i, v (-i) = v i
  | 0 => by 

Proof state:
α : Type u_1
β : Type u_2
m : Type u_3
n : Type u_4
R : Type u_5
v✝ : Fin 0 → α
⊢ IsSymm (circulant v✝) ↔ ∀ (i : Fin 0), v✝ (-i) = v✝ i

Next tactic:
simp [IsSymm.ext_iff, IsEmpty.forall_iff]