l3lab/ntp-mathlib huggingface dataset:
/-- `charpoly f` is the characteristic polynomial of the matrix of `f` in any basis. -/
@[simp]
theorem charpoly_toMatrix {ι : Type w} [DecidableEq ι] [Fintype ι] (b : Basis ι R M) :
    (toMatrix b b f).charpoly = f.charpoly := by
  let A := toMatrix b b f
  let b' := chooseBasis R M
  let ι' := ChooseBasisIndex R M
  let A' := toMatrix b' b' f
  let e := Basis.indexEquiv b b'
  let φ := reindexLinearEquiv R R e e
  let φ₁ := reindexLinearEquiv R R e (Equiv.refl ι')
  let φ₂ := reindexLinearEquiv R R (Equiv.refl ι') (Equiv.refl ι')
  let φ₃ := reindexLinearEquiv R R (Equiv.refl ι') e
  let P := b.toMatrix b'
  let Q := b'.toMatrix b
  have hPQ : C.mapMatrix (φ₁ P) * C.mapMatrix (φ₃ Q) = 1 := by
    rw [RingHom.mapMatrix_apply, RingHom.mapMatrix_apply, ← Matrix.map_mul,
      reindexLinearEquiv_mul R R, Basis.toMatrix_mul_toMatrix_flip,
      reindexLinearEquiv_one, ← RingHom.mapMatrix_apply, RingHom.map_one]
  calc
    A.charpoly = (reindex e e A).charpoly := (charpoly_reindex _ _).symm
    _ = det (scalar ι' X - C.mapMatrix (φ A)) := rfl
    _ = det (scalar ι' X - C.mapMatrix (φ (P * A' * Q))) := by
      rw [basis_toMatrix_mul_linearMap_toMatrix_mul_basis_toMatrix]
    _ = det (scalar ι' X - C.mapMatrix (φ₁ P * φ₂ A' * φ₃ Q)) := by
      rw [reindexLinearEquiv_mul, reindexLinearEquiv_mul]
    _ = det (scalar ι' X - C.mapMatrix (φ₁ P) * C.mapMatrix A' * C.mapMatrix (φ₃ Q)) := by 

Proof state:
R : Type u
M : Type v
inst✝⁷ : CommRing R
inst✝⁶ : Nontrivial R
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
inst✝³ : Module.Free R M
inst✝² : Module.Finite R M
f : M →ₗ[R] M
ι : Type w
inst✝¹ : DecidableEq ι
inst✝ : Fintype ι
b : Basis ι R M
A : Matrix ι ι R := (toMatrix b b) f
b' : Basis (ChooseBasisIndex R M) R M := chooseBasis R M
ι' : Type v := ChooseBasisIndex R M
A' : Matrix (ChooseBasisIndex R M) (ChooseBasisIndex R M) R := (toMatrix b' b') f
e : ι ≃ ChooseBasisIndex R M := Basis.indexEquiv b b'
φ : Matrix ι ι R ≃ₗ[R] Matrix (ChooseBasisIndex R M) (ChooseBasisIndex R M) R := reindexLinearEquiv R R e e
φ₁ : Matrix ι ι' R ≃ₗ[R] Matrix (ChooseBasisIndex R M) ι' R := reindexLinearEquiv R R e (Equiv.refl ι')
φ₂ : Matrix ι' ι' R ≃ₗ[R] Matrix ι' ι' R := reindexLinearEquiv R R (Equiv.refl ι') (Equiv.refl ι')
φ₃ : Matrix ι' ι R ≃ₗ[R] Matrix ι' (ChooseBasisIndex R M) R := reindexLinearEquiv R R (Equiv.refl ι') e
P : Matrix ι (ChooseBasisIndex R M) R := Basis.toMatrix b ⇑b'
Q : Matrix (ChooseBasisIndex R M) ι R := Basis.toMatrix b' ⇑b
hPQ : (RingHom.mapMatrix C) (φ₁ P) * (RingHom.mapMatrix C) (φ₃ Q) = 1
⊢ det ((scalar ι') X - (RingHom.mapMatrix C) (φ₁ P * φ₂ A' * φ₃ Q)) =
    det ((scalar ι') X - (RingHom.mapMatrix C) (φ₁ P) * (RingHom.mapMatrix C) A' * (RingHom.mapMatrix C) (φ₃ Q))

Next tactic:
simp
/-- `charpoly f` is the characteristic polynomial of the matrix of `f` in any basis. -/
@[simp]
theorem charpoly_toMatrix {ι : Type w} [DecidableEq ι] [Fintype ι] (b : Basis ι R M) :
    (toMatrix b b f).charpoly = f.charpoly := by
  let A := toMatrix b b f
  let b' := chooseBasis R M
  let ι' := ChooseBasisIndex R M
  let A' := toMatrix b' b' f
  let e := Basis.indexEquiv b b'
  let φ := reindexLinearEquiv R R e e
  let φ₁ := reindexLinearEquiv R R e (Equiv.refl ι')
  let φ₂ := reindexLinearEquiv R R (Equiv.refl ι') (Equiv.refl ι')
  let φ₃ := reindexLinearEquiv R R (Equiv.refl ι') e
  let P := b.toMatrix b'
  let Q := b'.toMatrix b
  have hPQ : C.mapMatrix (φ₁ P) * C.mapMatrix (φ₃ Q) = 1 := by
    rw [RingHom.mapMatrix_apply, RingHom.mapMatrix_apply, ← Matrix.map_mul,
      reindexLinearEquiv_mul R R, Basis.toMatrix_mul_toMatrix_flip,
      reindexLinearEquiv_one, ← RingHom.mapMatrix_apply, RingHom.map_one]
  calc
    A.charpoly = (reindex e e A).charpoly := (charpoly_reindex _ _).symm
    _ = det (scalar ι' X - C.mapMatrix (φ A)) := rfl
    _ = det (scalar ι' X - C.mapMatrix (φ (P * A' * Q))) := by
      rw [basis_toMatrix_mul_linearMap_toMatrix_mul_basis_toMatrix]
    _ = det (scalar ι' X - C.mapMatrix (φ₁ P * φ₂ A' * φ₃ Q)) := by
      rw [reindexLinearEquiv_mul, reindexLinearEquiv_mul]
    _ = det (scalar ι' X - C.mapMatrix (φ₁ P) * C.mapMatrix A' * C.mapMatrix (φ₃ Q)) := by simp
    _ = det (scalar ι' X * C.mapMatrix (φ₁ P) * C.mapMatrix (φ₃ Q) -
          C.mapMatrix (φ₁ P) * C.mapMatrix A' * C.mapMatrix (φ₃ Q)) := by
      

Proof state:
R : Type u
M : Type v
inst✝⁷ : CommRing R
inst✝⁶ : Nontrivial R
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
inst✝³ : Module.Free R M
inst✝² : Module.Finite R M
f : M →ₗ[R] M
ι : Type w
inst✝¹ : DecidableEq ι
inst✝ : Fintype ι
b : Basis ι R M
A : Matrix ι ι R := (toMatrix b b) f
b' : Basis (ChooseBasisIndex R M) R M := chooseBasis R M
ι' : Type v := ChooseBasisIndex R M
A' : Matrix (ChooseBasisIndex R M) (ChooseBasisIndex R M) R := (toMatrix b' b') f
e : ι ≃ ChooseBasisIndex R M := Basis.indexEquiv b b'
φ : Matrix ι ι R ≃ₗ[R] Matrix (ChooseBasisIndex R M) (ChooseBasisIndex R M) R := reindexLinearEquiv R R e e
φ₁ : Matrix ι ι' R ≃ₗ[R] Matrix (ChooseBasisIndex R M) ι' R := reindexLinearEquiv R R e (Equiv.refl ι')
φ₂ : Matrix ι' ι' R ≃ₗ[R] Matrix ι' ι' R := reindexLinearEquiv R R (Equiv.refl ι') (Equiv.refl ι')
φ₃ : Matrix ι' ι R ≃ₗ[R] Matrix ι' (ChooseBasisIndex R M) R := reindexLinearEquiv R R (Equiv.refl ι') e
P : Matrix ι (ChooseBasisIndex R M) R := Basis.toMatrix b ⇑b'
Q : Matrix (ChooseBasisIndex R M) ι R := Basis.toMatrix b' ⇑b
hPQ : (RingHom.mapMatrix C) (φ₁ P) * (RingHom.mapMatrix C) (φ₃ Q) = 1
⊢ det ((scalar ι') X - (RingHom.mapMatrix C) (φ₁ P) * (RingHom.mapMatrix C) A' * (RingHom.mapMatrix C) (φ₃ Q)) =
    det
      ((scalar ι') X * (RingHom.mapMatrix C) (φ₁ P) * (RingHom.mapMatrix C) (φ₃ Q) -
        (RingHom.mapMatrix C) (φ₁ P) * (RingHom.mapMatrix C) A' * (RingHom.mapMatrix C) (φ₃ Q))

Next tactic:
rw [Matrix.mul_assoc ((scalar ι') X), hPQ, Matrix.mul_one]
@[to_additive]
theorem smul_pi_subset [∀ i, SMul K (R i)] (r : K) (s : Set ι) (t : ∀ i, Set (R i)) :
    r • pi s t ⊆ pi s (r • t) := by
  

Proof state:
K : Type u_1
ι : Type u_2
R : ι → Type u_3
inst✝ : (i : ι) → SMul K (R i)
r : K
s : Set ι
t : (i : ι) → Set (R i)
⊢ r • pi s t ⊆ pi s (r • t)

Next tactic:
rintro x ⟨y, h, rfl⟩ i hi
@[to_additive]
theorem smul_pi_subset [∀ i, SMul K (R i)] (r : K) (s : Set ι) (t : ∀ i, Set (R i)) :
    r • pi s t ⊆ pi s (r • t) := by
  rintro x ⟨y, h, rfl⟩ i hi
  

Proof state:
case intro.intro
K : Type u_1
ι : Type u_2
R : ι → Type u_3
inst✝ : (i : ι) → SMul K (R i)
r : K
s : Set ι
t : (i : ι) → Set (R i)
y : (i : ι) → R i
h : y ∈ pi s t
i : ι
hi : i ∈ s
⊢ (fun x => r • x) y i ∈ (r • t) i

Next tactic:
exact smul_mem_smul_set (h i hi)
@[to_additive]
theorem smul_univ_pi [∀ i, SMul K (R i)] (r : K) (t : ∀ i, Set (R i)) :
    r • pi (univ : Set ι) t = pi (univ : Set ι) (r • t) :=
  (Subset.antisymm (smul_pi_subset _ _ _)) fun x h ↦ by
    

Proof state:
K : Type u_1
ι : Type u_2
R : ι → Type u_3
inst✝ : (i : ι) → SMul K (R i)
r : K
t : (i : ι) → Set (R i)
x : (i : ι) → R i
h : x ∈ pi univ (r • t)
⊢ x ∈ r • pi univ t

Next tactic:
refine' ⟨fun i ↦ Classical.choose (h i <| Set.mem_univ _), fun i _ ↦ _, funext fun i ↦ _⟩
@[to_additive]
theorem smul_univ_pi [∀ i, SMul K (R i)] (r : K) (t : ∀ i, Set (R i)) :
    r • pi (univ : Set ι) t = pi (univ : Set ι) (r • t) :=
  (Subset.antisymm (smul_pi_subset _ _ _)) fun x h ↦ by
    refine' ⟨fun i ↦ Classical.choose (h i <| Set.mem_univ _), fun i _ ↦ _, funext fun i ↦ _⟩
    · 

Proof state:
case refine'_1
K : Type u_1
ι : Type u_2
R : ι → Type u_3
inst✝ : (i : ι) → SMul K (R i)
r : K
t : (i : ι) → Set (R i)
x : (i : ι) → R i
h : x ∈ pi univ (r • t)
i : ι
x✝ : i ∈ univ
⊢ (fun i => Classical.choose (_ : x i ∈ (r • t) i)) i ∈ t i

Next tactic:
exact (Classical.choose_spec (h i <| Set.mem_univ i)).left
@[to_additive]
theorem smul_univ_pi [∀ i, SMul K (R i)] (r : K) (t : ∀ i, Set (R i)) :
    r • pi (univ : Set ι) t = pi (univ : Set ι) (r • t) :=
  (Subset.antisymm (smul_pi_subset _ _ _)) fun x h ↦ by
    refine' ⟨fun i ↦ Classical.choose (h i <| Set.mem_univ _), fun i _ ↦ _, funext fun i ↦ _⟩
    · exact (Classical.choose_spec (h i <| Set.mem_univ i)).left
    · 

Proof state:
case refine'_2
K : Type u_1
ι : Type u_2
R : ι → Type u_3
inst✝ : (i : ι) → SMul K (R i)
r : K
t : (i : ι) → Set (R i)
x : (i : ι) → R i
h : x ∈ pi univ (r • t)
i : ι
⊢ (fun x => r • x) (fun i => Classical.choose (_ : x i ∈ (r • t) i)) i = x i

Next tactic:
exact (Classical.choose_spec (h i <| Set.mem_univ i)).right
@[simp]
theorem εClosure_empty : M.εClosure ∅ = ∅ :=
  eq_empty_of_forall_not_mem fun s hs ↦ by 

Proof state:
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x : List α
s✝ : σ
a : α
s : σ
hs : s ∈ εClosure M ∅
⊢ False

Next tactic:
induction hs
@[simp]
theorem εClosure_empty : M.εClosure ∅ = ∅ :=
  eq_empty_of_forall_not_mem fun s hs ↦ by induction hs <;> 

Proof state:
case base
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x : List α
s✝¹ : σ
a : α
s s✝ : σ
a✝ : s✝ ∈ ∅
⊢ False

Next tactic:
assumption
@[simp]
theorem εClosure_empty : M.εClosure ∅ = ∅ :=
  eq_empty_of_forall_not_mem fun s hs ↦ by induction hs <;> 

Proof state:
case step
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x : List α
s✝¹ : σ
a : α
s s✝ t✝ : σ
a✝¹ : t✝ ∈ step M s✝ none
a✝ : εClosure M ∅ s✝
a_ih✝ : False
⊢ False

Next tactic:
assumption
@[simp]
theorem mem_stepSet_iff : s ∈ M.stepSet S a ↔ ∃ t ∈ S, s ∈ M.εClosure (M.step t a) := by
  

Proof state:
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
⊢ s ∈ stepSet M S a ↔ ∃ t ∈ S, s ∈ εClosure M (step M t (some a))

Next tactic:
simp_rw [stepSet, mem_iUnion₂, exists_prop]
@[simp]
theorem stepSet_empty (a : α) : M.stepSet ∅ a = ∅ := by
  

Proof state:
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x : List α
s : σ
a✝ a : α
⊢ stepSet M ∅ a = ∅

Next tactic:
simp_rw [stepSet, mem_empty_iff_false, iUnion_false, iUnion_empty]
@[simp]
theorem evalFrom_append_singleton (S : Set σ) (x : List α) (a : α) :
    M.evalFrom S (x ++ [a]) = M.stepSet (M.evalFrom S x) a := by
  

Proof state:
α : Type u
σ σ' : Type v
M : εNFA α σ
S✝ : Set σ
x✝ : List α
s : σ
a✝ : α
S : Set σ
x : List α
a : α
⊢ evalFrom M S (x ++ [a]) = stepSet M (evalFrom M S x) a

Next tactic:
rw [evalFrom, List.foldl_append, List.foldl_cons, List.foldl_nil]
@[simp]
theorem evalFrom_empty (x : List α) : M.evalFrom ∅ x = ∅ := by
  

Proof state:
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x✝ : List α
s : σ
a : α
x : List α
⊢ evalFrom M ∅ x = ∅

Next tactic:
induction' x using List.reverseRecOn with x a ih
@[simp]
theorem evalFrom_empty (x : List α) : M.evalFrom ∅ x = ∅ := by
  induction' x using List.reverseRecOn with x a ih
  · 

Proof state:
case H0
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
⊢ evalFrom M ∅ [] = ∅

Next tactic:
rw [evalFrom_nil, εClosure_empty]
@[simp]
theorem evalFrom_empty (x : List α) : M.evalFrom ∅ x = ∅ := by
  induction' x using List.reverseRecOn with x a ih
  · rw [evalFrom_nil, εClosure_empty]
  · 

Proof state:
case H1
α : Type u
σ σ' : Type v
M : εNFA α σ
S : Set σ
x✝ : List α
s : σ
a✝ : α
x : List α
a : α
ih : evalFrom M ∅ x = ∅
⊢ evalFrom M ∅ (x ++ [a]) = ∅

Next tactic:
rw [evalFrom_append_singleton, ih, stepSet_empty]
@[simp]
theorem toεNFA_εClosure (M : NFA α σ) (S : Set σ) : M.toεNFA.εClosure S = S := by
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s : σ
a : α
M : NFA α σ
S : Set σ
⊢ εNFA.εClosure (toεNFA M) S = S

Next tactic:
ext a
@[simp]
theorem toεNFA_εClosure (M : NFA α σ) (S : Set σ) : M.toεNFA.εClosure S = S := by
  ext a
  

Proof state:
case h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s : σ
a✝ : α
M : NFA α σ
S : Set σ
a : σ
⊢ a ∈ εNFA.εClosure (toεNFA M) S ↔ a ∈ S

Next tactic:
refine' ⟨_, εNFA.εClosure.base _⟩
@[simp]
theorem toεNFA_εClosure (M : NFA α σ) (S : Set σ) : M.toεNFA.εClosure S = S := by
  ext a
  refine' ⟨_, εNFA.εClosure.base _⟩
  

Proof state:
case h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s : σ
a✝ : α
M : NFA α σ
S : Set σ
a : σ
⊢ a ∈ εNFA.εClosure (toεNFA M) S → a ∈ S

Next tactic:
rintro (⟨_, h⟩ | ⟨_, _, h, _⟩)
@[simp]
theorem toεNFA_εClosure (M : NFA α σ) (S : Set σ) : M.toεNFA.εClosure S = S := by
  ext a
  refine' ⟨_, εNFA.εClosure.base _⟩
  rintro (⟨_, h⟩ | ⟨_, _, h, _⟩)
  · 

Proof state:
case h.base
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s : σ
a✝ : α
M : NFA α σ
S : Set σ
a : σ
h : a ∈ S
⊢ a ∈ S

Next tactic:
exact h
@[simp]
theorem toεNFA_εClosure (M : NFA α σ) (S : Set σ) : M.toεNFA.εClosure S = S := by
  ext a
  refine' ⟨_, εNFA.εClosure.base _⟩
  rintro (⟨_, h⟩ | ⟨_, _, h, _⟩)
  · exact h
  · 

Proof state:
case h.step
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s : σ
a✝¹ : α
M : NFA α σ
S : Set σ
a s✝ : σ
a✝ : εNFA.εClosure (toεNFA M) S s✝
h : a ∈ εNFA.step (toεNFA M) s✝ none
⊢ a ∈ S

Next tactic:
cases h
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
M : NFA α σ
start : Set σ
⊢ εNFA.evalFrom (toεNFA M) start = evalFrom M start

Next tactic:
rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
M : NFA α σ
start : Set σ
⊢ List.foldl (εNFA.stepSet (toεNFA M)) start = List.foldl (stepSet M) start

Next tactic:
suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by 

Proof state:
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
M : NFA α σ
start : Set σ
this : εNFA.stepSet (toεNFA M) = stepSet M
⊢ List.foldl (εNFA.stepSet (toεNFA M)) start = List.foldl (stepSet M) start

Next tactic:
rw [this]
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
M : NFA α σ
start : Set σ
⊢ εNFA.stepSet (toεNFA M) = stepSet M

Next tactic:
ext S s
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
  ext S s
  

Proof state:
case h.h.h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s✝ : σ
a : α
M : NFA α σ
start S : Set σ
s : α
x✝ : σ
⊢ x✝ ∈ εNFA.stepSet (toεNFA M) S s ↔ x✝ ∈ stepSet M S s

Next tactic:
simp only [stepSet, εNFA.stepSet, exists_prop, Set.mem_iUnion]
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
  ext S s
  simp only [stepSet, εNFA.stepSet, exists_prop, Set.mem_iUnion]
  

Proof state:
case h.h.h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s✝ : σ
a : α
M : NFA α σ
start S : Set σ
s : α
x✝ : σ
⊢ (∃ i ∈ S, x✝ ∈ εNFA.εClosure (toεNFA M) (εNFA.step (toεNFA M) i (some s))) ↔ ∃ i ∈ S, x✝ ∈ step M i s

Next tactic:
apply exists_congr
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
  ext S s
  simp only [stepSet, εNFA.stepSet, exists_prop, Set.mem_iUnion]
  apply exists_congr
  

Proof state:
case h.h.h.h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s✝ : σ
a : α
M : NFA α σ
start S : Set σ
s : α
x✝ : σ
⊢ ∀ (a : σ), a ∈ S ∧ x✝ ∈ εNFA.εClosure (toεNFA M) (εNFA.step (toεNFA M) a (some s)) ↔ a ∈ S ∧ x✝ ∈ step M a s

Next tactic:
simp only [and_congr_right_iff]
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
  ext S s
  simp only [stepSet, εNFA.stepSet, exists_prop, Set.mem_iUnion]
  apply exists_congr
  simp only [and_congr_right_iff]
  

Proof state:
case h.h.h.h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s✝ : σ
a : α
M : NFA α σ
start S : Set σ
s : α
x✝ : σ
⊢ ∀ a ∈ S, x✝ ∈ εNFA.εClosure (toεNFA M) (εNFA.step (toεNFA M) a (some s)) ↔ x✝ ∈ step M a s

Next tactic:
intro _ _
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
  ext S s
  simp only [stepSet, εNFA.stepSet, exists_prop, Set.mem_iUnion]
  apply exists_congr
  simp only [and_congr_right_iff]
  intro _ _
  

Proof state:
case h.h.h.h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s✝ : σ
a : α
M : NFA α σ
start S : Set σ
s : α
x✝ a✝¹ : σ
a✝ : a✝¹ ∈ S
⊢ x✝ ∈ εNFA.εClosure (toεNFA M) (εNFA.step (toεNFA M) a✝¹ (some s)) ↔ x✝ ∈ step M a✝¹ s

Next tactic:
rw [M.toεNFA_εClosure]
@[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start := by
  rw [evalFrom, εNFA.evalFrom, toεNFA_εClosure]
  suffices εNFA.stepSet (toεNFA M) = stepSet M by rw [this]
  ext S s
  simp only [stepSet, εNFA.stepSet, exists_prop, Set.mem_iUnion]
  apply exists_congr
  simp only [and_congr_right_iff]
  intro _ _
  rw [M.toεNFA_εClosure]
  

Proof state:
case h.h.h.h
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S✝ : Set σ
x : List α
s✝ : σ
a : α
M : NFA α σ
start S : Set σ
s : α
x✝ a✝¹ : σ
a✝ : a✝¹ ∈ S
⊢ x✝ ∈ εNFA.step (toεNFA M) a✝¹ (some s) ↔ x✝ ∈ step M a✝¹ s

Next tactic:
rfl
@[simp]
theorem toεNFA_correct (M : NFA α σ) : M.toεNFA.accepts = M.accepts := by
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
M : NFA α σ
⊢ εNFA.accepts (toεNFA M) = accepts M

Next tactic:
rw [εNFA.accepts, εNFA.eval, toεNFA_evalFrom_match]
@[simp]
theorem toεNFA_correct (M : NFA α σ) : M.toεNFA.accepts = M.accepts := by
  rw [εNFA.accepts, εNFA.eval, toεNFA_evalFrom_match]
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : εNFA α σ
S : Set σ
x : List α
s : σ
a : α
M : NFA α σ
⊢ {x | ∃ S ∈ (toεNFA M).accept, S ∈ evalFrom M (toεNFA M).start x} = accepts M

Next tactic:
rfl
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
⊢ (fun S' => functorPullback (Over.forget X) S') ((fun S => functorPushforward (Over.forget X) S) S) = S

Next tactic:
ext Z g
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    ext Z g
    

Proof state:
case h
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
Z : Over X
g : Z ⟶ Y
⊢ ((fun S' => functorPullback (Over.forget X) S') ((fun S => functorPushforward (Over.forget X) S) S)).arrows g ↔
    S.arrows g

Next tactic:
dsimp [Presieve.functorPullback, Presieve.functorPushforward]
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    ext Z g
    dsimp [Presieve.functorPullback, Presieve.functorPushforward]
    

Proof state:
case h
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
Z : Over X
g : Z ⟶ Y
⊢ (∃ Z_1 g_1 h, S.arrows g_1 ∧ g.left = h ≫ g_1.left) ↔ S.arrows g

Next tactic:
constructor
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    ext Z g
    dsimp [Presieve.functorPullback, Presieve.functorPushforward]
    constructor
    · 

Proof state:
case h.mp
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
Z : Over X
g : Z ⟶ Y
⊢ (∃ Z_1 g_1 h, S.arrows g_1 ∧ g.left = h ≫ g_1.left) → S.arrows g

Next tactic:
rintro ⟨W, a, b, h, w⟩
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    ext Z g
    dsimp [Presieve.functorPullback, Presieve.functorPushforward]
    constructor
    · rintro ⟨W, a, b, h, w⟩
      

Proof state:
case h.mp.intro.intro.intro.intro
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
Z : Over X
g : Z ⟶ Y
W : Over X
a : W ⟶ Y
b : Z.left ⟶ W.left
h : S.arrows a
w : g.left = b ≫ a.left
⊢ S.arrows g

Next tactic:
let c : Z ⟶ W := Over.homMk b
        (by rw [← Over.w g, w, assoc, Over.w a])
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    ext Z g
    dsimp [Presieve.functorPullback, Presieve.functorPushforward]
    constructor
    · rintro ⟨W, a, b, h, w⟩
      let c : Z ⟶ W := Over.homMk b
        (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
Z : Over X
g : Z ⟶ Y
W : Over X
a : W ⟶ Y
b : Z.left ⟶ W.left
h : S.arrows a
w : g.left = b ≫ a.left
⊢ b ≫ W.hom = Z.hom

Next tactic:
rw [← Over.w g, w, assoc, Over.w a]
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    ext Z g
    dsimp [Presieve.functorPullback, Presieve.functorPushforward]
    constructor
    · rintro ⟨W, a, b, h, w⟩
      let c : Z ⟶ W := Over.homMk b
        (by rw [← Over.w g, w, assoc, Over.w a])
      

Proof state:
case h.mp.intro.intro.intro.intro
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
Z : Over X
g : Z ⟶ Y
W : Over X
a : W ⟶ Y
b : Z.left ⟶ W.left
h : S.arrows a
w : g.left = b ≫ a.left
c : Z ⟶ W := Over.homMk b
⊢ S.arrows g

Next tactic:
rw [show g = c ≫ a by ext; exact w]
/-- The equivalence `Sieve Y ≃ Sieve Y.left` for all `Y : Over X`. -/
def overEquiv {X : C} (Y : Over X) :
    Sieve Y ≃ Sieve Y.left where
  toFun S := Sieve.functorPushforward (Over.forget X) S
  invFun S' := Sieve.functorPullback (Over.forget X) S'
  left_inv S := by
    ext Z g
    dsimp [Presieve.functorPullback, Presieve.functorPushforward]
    constructor
    · rintro ⟨W, a, b, h, w⟩
      let c : Z ⟶ W := Over.homMk b
        (by rw [← Over.w g, w, assoc, Over.w a])
      rw [show g = c ≫ a by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
Y : Over X
S : Sieve Y
Z : Over X
g : Z ⟶ Y
W : Over X
a : W ⟶ Y
b : Z.left ⟶ W.left
h : S.arrows a
w : g.left = b ≫ a.left
c : Z ⟶ W := Over.homMk b
⊢ g = c ≫ a

Next tactic:
ext