l3lab/ntp-mathlib huggingface dataset:
/-- Transport an exact pairing across an isomorphism in the second argument. -/
def exactPairingCongrRight {X Y Y' : C} [ExactPairing X Y'] (i : Y ≅ Y') : ExactPairing X Y where
  evaluation' := (i.hom ⊗ 𝟙 X) ≫ ε_ _ _
  coevaluation' := η_ _ _ ≫ (𝟙 X ⊗ i.inv)
  evaluation_coevaluation' := by
    rw [id_tensor_comp, comp_tensor_id]
    simp only [Iso.inv_hom_id_assoc, associator_conjugation, Category.assoc]
    slice_lhs 3 4 =>
      

Proof state:
case a.a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| (𝟙 X ⊗ i.inv ⊗ 𝟙 X) ≫ (𝟙 X ⊗ i.hom ⊗ 𝟙 X)
case a.a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| 𝟙 X ⊗ ε_ X Y'
case a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| η_ X Y' ⊗ 𝟙 X
case a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| (α_ X Y' X).hom

Next tactic:
rw [← tensor_comp]
      simp
/-- Transport an exact pairing across an isomorphism in the second argument. -/
def exactPairingCongrRight {X Y Y' : C} [ExactPairing X Y'] (i : Y ≅ Y') : ExactPairing X Y where
  evaluation' := (i.hom ⊗ 𝟙 X) ≫ ε_ _ _
  coevaluation' := η_ _ _ ≫ (𝟙 X ⊗ i.inv)
  evaluation_coevaluation' := by
    rw [id_tensor_comp, comp_tensor_id]
    simp only [Iso.inv_hom_id_assoc, associator_conjugation, Category.assoc]
    slice_lhs 3 4 =>
      

Proof state:
case a.a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| (𝟙 X ⊗ i.inv ⊗ 𝟙 X) ≫ (𝟙 X ⊗ i.hom ⊗ 𝟙 X)
case a.a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| 𝟙 X ⊗ ε_ X Y'
case a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| η_ X Y' ⊗ 𝟙 X
case a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| (α_ X Y' X).hom

Next tactic:
rw [← tensor_comp]
/-- Transport an exact pairing across an isomorphism in the second argument. -/
def exactPairingCongrRight {X Y Y' : C} [ExactPairing X Y'] (i : Y ≅ Y') : ExactPairing X Y where
  evaluation' := (i.hom ⊗ 𝟙 X) ≫ ε_ _ _
  coevaluation' := η_ _ _ ≫ (𝟙 X ⊗ i.inv)
  evaluation_coevaluation' := by
    rw [id_tensor_comp, comp_tensor_id]
    simp only [Iso.inv_hom_id_assoc, associator_conjugation, Category.assoc]
    slice_lhs 3 4 =>
      rw [← tensor_comp]
      

Proof state:
case a.a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| 𝟙 X ≫ 𝟙 X ⊗ (i.inv ⊗ 𝟙 X) ≫ (i.hom ⊗ 𝟙 X)
case a.a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| 𝟙 X ⊗ ε_ X Y'
case a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| η_ X Y' ⊗ 𝟙 X
case a.a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
| (α_ X Y' X).hom

Next tactic:
simp
/-- Transport an exact pairing across an isomorphism in the second argument. -/
def exactPairingCongrRight {X Y Y' : C} [ExactPairing X Y'] (i : Y ≅ Y') : ExactPairing X Y where
  evaluation' := (i.hom ⊗ 𝟙 X) ≫ ε_ _ _
  coevaluation' := η_ _ _ ≫ (𝟙 X ⊗ i.inv)
  evaluation_coevaluation' := by
    rw [id_tensor_comp, comp_tensor_id]
    simp only [Iso.inv_hom_id_assoc, associator_conjugation, Category.assoc]
    slice_lhs 3 4 =>
      rw [← tensor_comp]
      simp
    

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
X Y Y' : C
inst✝ : ExactPairing X Y'
i : Y ≅ Y'
⊢ (η_ X Y' ⊗ 𝟙 X) ≫ (α_ X Y' X).hom ≫ 𝟙 (X ⊗ Y' ⊗ X) ≫ (𝟙 X ⊗ ε_ X Y') = (λ_ X).hom ≫ (ρ_ X).inv

Next tactic:
simp
/-- Right duals are isomorphic. -/
def rightDualIso {X Y₁ Y₂ : C} (p₁ : ExactPairing X Y₁) (p₂ : ExactPairing X Y₂) : Y₁ ≅ Y₂ where
  hom := @rightAdjointMate C _ _ X X ⟨Y₂⟩ ⟨Y₁⟩ (𝟙 X)
  inv := @rightAdjointMate C _ _ X X ⟨Y₁⟩ ⟨Y₂⟩ (𝟙 X)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y₁ Y₂ : C
p₁ : ExactPairing X Y₁
p₂ : ExactPairing X Y₂
⊢ 𝟙 Xᘁ ≫ 𝟙 Xᘁ = 𝟙 Y₁

Next tactic:
rw [← @comp_rightAdjointMate C _ _ X X X ⟨Y₁⟩ ⟨Y₂⟩ ⟨Y₁⟩, Category.comp_id,
      @rightAdjointMate_id _ _ _ _ ⟨Y₁⟩]
/-- Right duals are isomorphic. -/
def rightDualIso {X Y₁ Y₂ : C} (p₁ : ExactPairing X Y₁) (p₂ : ExactPairing X Y₂) : Y₁ ≅ Y₂ where
  hom := @rightAdjointMate C _ _ X X ⟨Y₂⟩ ⟨Y₁⟩ (𝟙 X)
  inv := @rightAdjointMate C _ _ X X ⟨Y₁⟩ ⟨Y₂⟩ (𝟙 X)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    rw [← @comp_rightAdjointMate C _ _ X X X ⟨Y₁⟩ ⟨Y₂⟩ ⟨Y₁⟩, Category.comp_id,
      @rightAdjointMate_id _ _ _ _ ⟨Y₁⟩]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y₁ Y₂ : C
p₁ : ExactPairing X Y₁
p₂ : ExactPairing X Y₂
⊢ 𝟙 Xᘁ = 𝟙 Y₁

Next tactic:
rfl
/-- Right duals are isomorphic. -/
def rightDualIso {X Y₁ Y₂ : C} (p₁ : ExactPairing X Y₁) (p₂ : ExactPairing X Y₂) : Y₁ ≅ Y₂ where
  hom := @rightAdjointMate C _ _ X X ⟨Y₂⟩ ⟨Y₁⟩ (𝟙 X)
  inv := @rightAdjointMate C _ _ X X ⟨Y₁⟩ ⟨Y₂⟩ (𝟙 X)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    rw [← @comp_rightAdjointMate C _ _ X X X ⟨Y₁⟩ ⟨Y₂⟩ ⟨Y₁⟩, Category.comp_id,
      @rightAdjointMate_id _ _ _ _ ⟨Y₁⟩]
    rfl
  inv_hom_id := by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y₁ Y₂ : C
p₁ : ExactPairing X Y₁
p₂ : ExactPairing X Y₂
⊢ 𝟙 Xᘁ ≫ 𝟙 Xᘁ = 𝟙 Y₂

Next tactic:
rw [← @comp_rightAdjointMate C _ _ X X X ⟨Y₂⟩ ⟨Y₁⟩ ⟨Y₂⟩, Category.comp_id,
      @rightAdjointMate_id _ _ _ _ ⟨Y₂⟩]
/-- Right duals are isomorphic. -/
def rightDualIso {X Y₁ Y₂ : C} (p₁ : ExactPairing X Y₁) (p₂ : ExactPairing X Y₂) : Y₁ ≅ Y₂ where
  hom := @rightAdjointMate C _ _ X X ⟨Y₂⟩ ⟨Y₁⟩ (𝟙 X)
  inv := @rightAdjointMate C _ _ X X ⟨Y₁⟩ ⟨Y₂⟩ (𝟙 X)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    rw [← @comp_rightAdjointMate C _ _ X X X ⟨Y₁⟩ ⟨Y₂⟩ ⟨Y₁⟩, Category.comp_id,
      @rightAdjointMate_id _ _ _ _ ⟨Y₁⟩]
    rfl
  inv_hom_id := by
    rw [← @comp_rightAdjointMate C _ _ X X X ⟨Y₂⟩ ⟨Y₁⟩ ⟨Y₂⟩, Category.comp_id,
      @rightAdjointMate_id _ _ _ _ ⟨Y₂⟩]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y₁ Y₂ : C
p₁ : ExactPairing X Y₁
p₂ : ExactPairing X Y₂
⊢ 𝟙 Xᘁ = 𝟙 Y₂

Next tactic:
rfl
/-- Left duals are isomorphic. -/
def leftDualIso {X₁ X₂ Y : C} (p₁ : ExactPairing X₁ Y) (p₂ : ExactPairing X₂ Y) : X₁ ≅ X₂ where
  hom := @leftAdjointMate C _ _ Y Y ⟨X₂⟩ ⟨X₁⟩ (𝟙 Y)
  inv := @leftAdjointMate C _ _ Y Y ⟨X₁⟩ ⟨X₂⟩ (𝟙 Y)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X₁ X₂ Y : C
p₁ : ExactPairing X₁ Y
p₂ : ExactPairing X₂ Y
⊢ ((ᘁ𝟙 Y) ≫ ᘁ𝟙 Y) = 𝟙 X₁

Next tactic:
rw [← @comp_leftAdjointMate C _ _ Y Y Y ⟨X₁⟩ ⟨X₂⟩ ⟨X₁⟩, Category.comp_id,
      @leftAdjointMate_id _ _ _ _ ⟨X₁⟩]
/-- Left duals are isomorphic. -/
def leftDualIso {X₁ X₂ Y : C} (p₁ : ExactPairing X₁ Y) (p₂ : ExactPairing X₂ Y) : X₁ ≅ X₂ where
  hom := @leftAdjointMate C _ _ Y Y ⟨X₂⟩ ⟨X₁⟩ (𝟙 Y)
  inv := @leftAdjointMate C _ _ Y Y ⟨X₁⟩ ⟨X₂⟩ (𝟙 Y)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    rw [← @comp_leftAdjointMate C _ _ Y Y Y ⟨X₁⟩ ⟨X₂⟩ ⟨X₁⟩, Category.comp_id,
      @leftAdjointMate_id _ _ _ _ ⟨X₁⟩]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X₁ X₂ Y : C
p₁ : ExactPairing X₁ Y
p₂ : ExactPairing X₂ Y
⊢ 𝟙 ᘁY = 𝟙 X₁

Next tactic:
rfl
/-- Left duals are isomorphic. -/
def leftDualIso {X₁ X₂ Y : C} (p₁ : ExactPairing X₁ Y) (p₂ : ExactPairing X₂ Y) : X₁ ≅ X₂ where
  hom := @leftAdjointMate C _ _ Y Y ⟨X₂⟩ ⟨X₁⟩ (𝟙 Y)
  inv := @leftAdjointMate C _ _ Y Y ⟨X₁⟩ ⟨X₂⟩ (𝟙 Y)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    rw [← @comp_leftAdjointMate C _ _ Y Y Y ⟨X₁⟩ ⟨X₂⟩ ⟨X₁⟩, Category.comp_id,
      @leftAdjointMate_id _ _ _ _ ⟨X₁⟩]
    rfl
  inv_hom_id := by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X₁ X₂ Y : C
p₁ : ExactPairing X₁ Y
p₂ : ExactPairing X₂ Y
⊢ ((ᘁ𝟙 Y) ≫ ᘁ𝟙 Y) = 𝟙 X₂

Next tactic:
rw [← @comp_leftAdjointMate C _ _ Y Y Y ⟨X₂⟩ ⟨X₁⟩ ⟨X₂⟩, Category.comp_id,
      @leftAdjointMate_id _ _ _ _ ⟨X₂⟩]
/-- Left duals are isomorphic. -/
def leftDualIso {X₁ X₂ Y : C} (p₁ : ExactPairing X₁ Y) (p₂ : ExactPairing X₂ Y) : X₁ ≅ X₂ where
  hom := @leftAdjointMate C _ _ Y Y ⟨X₂⟩ ⟨X₁⟩ (𝟙 Y)
  inv := @leftAdjointMate C _ _ Y Y ⟨X₁⟩ ⟨X₂⟩ (𝟙 Y)
  -- Porting note: no implicit arguments were required below:
  hom_inv_id := by
    rw [← @comp_leftAdjointMate C _ _ Y Y Y ⟨X₁⟩ ⟨X₂⟩ ⟨X₁⟩, Category.comp_id,
      @leftAdjointMate_id _ _ _ _ ⟨X₁⟩]
    rfl
  inv_hom_id := by
    rw [← @comp_leftAdjointMate C _ _ Y Y Y ⟨X₂⟩ ⟨X₁⟩ ⟨X₂⟩, Category.comp_id,
      @leftAdjointMate_id _ _ _ _ ⟨X₂⟩]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X₁ X₂ Y : C
p₁ : ExactPairing X₁ Y
p₂ : ExactPairing X₂ Y
⊢ 𝟙 ᘁY = 𝟙 X₂

Next tactic:
rfl
@[simp]
theorem rightDualIso_id {X Y : C} (p : ExactPairing X Y) : rightDualIso p p = Iso.refl Y := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : C
p : ExactPairing X Y
⊢ rightDualIso p p = Iso.refl Y

Next tactic:
ext
@[simp]
theorem rightDualIso_id {X Y : C} (p : ExactPairing X Y) : rightDualIso p p = Iso.refl Y := by
  ext
  

Proof state:
case w
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : C
p : ExactPairing X Y
⊢ (rightDualIso p p).hom = (Iso.refl Y).hom

Next tactic:
simp only [rightDualIso, Iso.refl_hom, @rightAdjointMate_id _ _ _ _ ⟨Y⟩]
@[simp]
theorem leftDualIso_id {X Y : C} (p : ExactPairing X Y) : leftDualIso p p = Iso.refl X := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : C
p : ExactPairing X Y
⊢ leftDualIso p p = Iso.refl X

Next tactic:
ext
@[simp]
theorem leftDualIso_id {X Y : C} (p : ExactPairing X Y) : leftDualIso p p = Iso.refl X := by
  ext
  

Proof state:
case w
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : C
p : ExactPairing X Y
⊢ (leftDualIso p p).hom = (Iso.refl X).hom

Next tactic:
simp only [leftDualIso, Iso.refl_hom, @leftAdjointMate_id _ _ _ _ ⟨X⟩]
theorem mem_stepSet (s : σ) (S : Set σ) (a : α) : s ∈ M.stepSet S a ↔ ∃ t ∈ S, s ∈ M.step t a := by
  

Proof state:
α : Type u
σ σ' : Type v
M : NFA α σ
s : σ
S : Set σ
a : α
⊢ s ∈ stepSet M S a ↔ ∃ t ∈ S, s ∈ step M t a

Next tactic:
simp [stepSet]
@[simp]
theorem stepSet_empty (a : α) : M.stepSet ∅ a = ∅ := by 

Proof state:
α : Type u
σ σ' : Type v
M : NFA α σ
a : α
⊢ stepSet M ∅ a = ∅

Next tactic:
simp [stepSet]
@[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 α
a : α
⊢ evalFrom M S (x ++ [a]) = stepSet M (evalFrom M S x) a

Next tactic:
simp only [evalFrom, List.foldl_append, List.foldl_cons, List.foldl_nil]
theorem mem_accepts : x ∈ M.accepts ↔ ∃ S ∈ M.accept, S ∈ M.evalFrom M.start x := by 

Proof state:
α : Type u
σ σ' : Type v
M : NFA α σ
x : List α
⊢ x ∈ accepts M ↔ ∃ S ∈ M.accept, S ∈ evalFrom M M.start x

Next tactic:
rfl
@[simp]
theorem toDFA_correct : M.toDFA.accepts = M.accepts := by
  

Proof state:
α : Type u
σ σ' : Type v
M : NFA α σ
⊢ DFA.accepts (toDFA M) = accepts M

Next tactic:
ext x
@[simp]
theorem toDFA_correct : M.toDFA.accepts = M.accepts := by
  ext x
  

Proof state:
case h
α : Type u
σ σ' : Type v
M : NFA α σ
x : List α
⊢ x ∈ DFA.accepts (toDFA M) ↔ x ∈ accepts M

Next tactic:
rw [mem_accepts, DFA.mem_accepts]
@[simp]
theorem toDFA_correct : M.toDFA.accepts = M.accepts := by
  ext x
  rw [mem_accepts, DFA.mem_accepts]
  

Proof state:
case h
α : Type u
σ σ' : Type v
M : NFA α σ
x : List α
⊢ DFA.evalFrom (toDFA M) (toDFA M).start x ∈ (toDFA M).accept ↔ ∃ S ∈ M.accept, S ∈ evalFrom M M.start x

Next tactic:
constructor
@[simp]
theorem toDFA_correct : M.toDFA.accepts = M.accepts := by
  ext x
  rw [mem_accepts, DFA.mem_accepts]
  constructor <;> · 

Proof state:
case h.mp
α : Type u
σ σ' : Type v
M : NFA α σ
x : List α
⊢ DFA.evalFrom (toDFA M) (toDFA M).start x ∈ (toDFA M).accept → ∃ S ∈ M.accept, S ∈ evalFrom M M.start x

Next tactic:
exact fun ⟨w, h2, h3⟩ => ⟨w, h3, h2⟩
@[simp]
theorem toDFA_correct : M.toDFA.accepts = M.accepts := by
  ext x
  rw [mem_accepts, DFA.mem_accepts]
  constructor <;> · 

Proof state:
case h.mpr
α : Type u
σ σ' : Type v
M : NFA α σ
x : List α
⊢ (∃ S ∈ M.accept, S ∈ evalFrom M M.start x) → DFA.evalFrom (toDFA M) (toDFA M).start x ∈ (toDFA M).accept

Next tactic:
exact fun ⟨w, h2, h3⟩ => ⟨w, h3, h2⟩
theorem pumping_lemma [Fintype σ] {x : List α} (hx : x ∈ M.accepts)
    (hlen : Fintype.card (Set σ) ≤ List.length x) :
    ∃ a b c,
      x = a ++ b ++ c ∧
        a.length + b.length ≤ Fintype.card (Set σ) ∧ b ≠ [] ∧ {a} * {b}∗ * {c} ≤ M.accepts := by
  

Proof state:
α : Type u
σ σ' : Type v
M : NFA α σ
inst✝ : Fintype σ
x : List α
hx : x ∈ accepts M
hlen : Fintype.card (Set σ) ≤ List.length x
⊢ ∃ a b c,
    x = a ++ b ++ c ∧ List.length a + List.length b ≤ Fintype.card (Set σ) ∧ b ≠ [] ∧ {a} * {b}∗ * {c} ≤ accepts M

Next tactic:
rw [← toDFA_correct] at hx ⊢
theorem pumping_lemma [Fintype σ] {x : List α} (hx : x ∈ M.accepts)
    (hlen : Fintype.card (Set σ) ≤ List.length x) :
    ∃ a b c,
      x = a ++ b ++ c ∧
        a.length + b.length ≤ Fintype.card (Set σ) ∧ b ≠ [] ∧ {a} * {b}∗ * {c} ≤ M.accepts := by
  rw [← toDFA_correct] at hx ⊢
  

Proof state:
α : Type u
σ σ' : Type v
M : NFA α σ
inst✝ : Fintype σ
x : List α
hx : x ∈ DFA.accepts (toDFA M)
hlen : Fintype.card (Set σ) ≤ List.length x
⊢ ∃ a b c,
    x = a ++ b ++ c ∧
      List.length a + List.length b ≤ Fintype.card (Set σ) ∧ b ≠ [] ∧ {a} * {b}∗ * {c} ≤ DFA.accepts (toDFA M)

Next tactic:
exact M.toDFA.pumping_lemma hx hlen
@[simp]
theorem toNFA_evalFrom_match (M : DFA α σ) (start : σ) (s : List α) :
    M.toNFA.evalFrom {start} s = {M.evalFrom start s} := by
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
start : σ
s : List α
⊢ NFA.evalFrom (toNFA M) {start} s = {evalFrom M start s}

Next tactic:
change List.foldl M.toNFA.stepSet {start} s = {List.foldl M.step start s}
@[simp]
theorem toNFA_evalFrom_match (M : DFA α σ) (start : σ) (s : List α) :
    M.toNFA.evalFrom {start} s = {M.evalFrom start s} := by
  change List.foldl M.toNFA.stepSet {start} s = {List.foldl M.step start s}
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
start : σ
s : List α
⊢ List.foldl (NFA.stepSet (toNFA M)) {start} s = {List.foldl M.step start s}

Next tactic:
induction' s with a s ih generalizing start
@[simp]
theorem toNFA_evalFrom_match (M : DFA α σ) (start : σ) (s : List α) :
    M.toNFA.evalFrom {start} s = {M.evalFrom start s} := by
  change List.foldl M.toNFA.stepSet {start} s = {List.foldl M.step start s}
  induction' s with a s ih generalizing start
  · 

Proof state:
case nil
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
start : σ
⊢ List.foldl (NFA.stepSet (toNFA M)) {start} [] = {List.foldl M.step start []}

Next tactic:
tauto
@[simp]
theorem toNFA_evalFrom_match (M : DFA α σ) (start : σ) (s : List α) :
    M.toNFA.evalFrom {start} s = {M.evalFrom start s} := by
  change List.foldl M.toNFA.stepSet {start} s = {List.foldl M.step start s}
  induction' s with a s ih generalizing start
  · tauto
  · 

Proof state:
case cons
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
a : α
s : List α
ih : ∀ (start : σ), List.foldl (NFA.stepSet (toNFA M)) {start} s = {List.foldl M.step start s}
start : σ
⊢ List.foldl (NFA.stepSet (toNFA M)) {start} (a :: s) = {List.foldl M.step start (a :: s)}

Next tactic:
rw [List.foldl, List.foldl,
      show M.toNFA.stepSet {start} a = {M.step start a} by simp [NFA.stepSet] ]
@[simp]
theorem toNFA_evalFrom_match (M : DFA α σ) (start : σ) (s : List α) :
    M.toNFA.evalFrom {start} s = {M.evalFrom start s} := by
  change List.foldl M.toNFA.stepSet {start} s = {List.foldl M.step start s}
  induction' s with a s ih generalizing start
  · tauto
  · rw [List.foldl, List.foldl,
      show M.toNFA.stepSet {start} a = {M.step start a} by 

Proof state:
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
a : α
s : List α
ih : ∀ (start : σ), List.foldl (NFA.stepSet (toNFA M)) {start} s = {List.foldl M.step start s}
start : σ
⊢ NFA.stepSet (toNFA M) {start} a = {step M start a}

Next tactic:
simp [NFA.stepSet]
@[simp]
theorem toNFA_evalFrom_match (M : DFA α σ) (start : σ) (s : List α) :
    M.toNFA.evalFrom {start} s = {M.evalFrom start s} := by
  change List.foldl M.toNFA.stepSet {start} s = {List.foldl M.step start s}
  induction' s with a s ih generalizing start
  · tauto
  · rw [List.foldl, List.foldl,
      show M.toNFA.stepSet {start} a = {M.step start a} by simp [NFA.stepSet] ]
    

Proof state:
case cons
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
a : α
s : List α
ih : ∀ (start : σ), List.foldl (NFA.stepSet (toNFA M)) {start} s = {List.foldl M.step start s}
start : σ
⊢ List.foldl (NFA.stepSet (toNFA M)) {step M start a} s = {List.foldl M.step (step M start a) s}

Next tactic:
tauto
@[simp]
theorem toNFA_correct (M : DFA α σ) : M.toNFA.accepts = M.accepts := by
  

Proof state:
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
⊢ NFA.accepts (toNFA M) = accepts M

Next tactic:
ext x
@[simp]
theorem toNFA_correct (M : DFA α σ) : M.toNFA.accepts = M.accepts := by
  ext x
  

Proof state:
case h
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
x : List α
⊢ x ∈ NFA.accepts (toNFA M) ↔ x ∈ accepts M

Next tactic:
rw [NFA.mem_accepts, toNFA_start, toNFA_evalFrom_match]
@[simp]
theorem toNFA_correct (M : DFA α σ) : M.toNFA.accepts = M.accepts := by
  ext x
  rw [NFA.mem_accepts, toNFA_start, toNFA_evalFrom_match]
  

Proof state:
case h
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
x : List α
⊢ (∃ S ∈ (toNFA M).accept, S ∈ {evalFrom M M.start x}) ↔ x ∈ accepts M

Next tactic:
constructor
@[simp]
theorem toNFA_correct (M : DFA α σ) : M.toNFA.accepts = M.accepts := by
  ext x
  rw [NFA.mem_accepts, toNFA_start, toNFA_evalFrom_match]
  constructor
  · 

Proof state:
case h.mp
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
x : List α
⊢ (∃ S ∈ (toNFA M).accept, S ∈ {evalFrom M M.start x}) → x ∈ accepts M

Next tactic:
rintro ⟨S, hS₁, hS₂⟩
@[simp]
theorem toNFA_correct (M : DFA α σ) : M.toNFA.accepts = M.accepts := by
  ext x
  rw [NFA.mem_accepts, toNFA_start, toNFA_evalFrom_match]
  constructor
  · rintro ⟨S, hS₁, hS₂⟩
    

Proof state:
case h.mp.intro.intro
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
x : List α
S : σ
hS₁ : S ∈ (toNFA M).accept
hS₂ : S ∈ {evalFrom M M.start x}
⊢ x ∈ accepts M

Next tactic:
rwa [Set.mem_singleton_iff.mp hS₂] at hS₁
@[simp]
theorem toNFA_correct (M : DFA α σ) : M.toNFA.accepts = M.accepts := by
  ext x
  rw [NFA.mem_accepts, toNFA_start, toNFA_evalFrom_match]
  constructor
  · rintro ⟨S, hS₁, hS₂⟩
    rwa [Set.mem_singleton_iff.mp hS₂] at hS₁
  · 

Proof state:
case h.mpr
α : Type u
σ σ' : Type v
M✝ : NFA α σ
M : DFA α σ
x : List α
⊢ x ∈ accepts M → ∃ S ∈ (toNFA M).accept, S ∈ {evalFrom M M.start x}

Next tactic:
exact fun h => ⟨M.eval x, h, rfl⟩
theorem isPell_norm : ∀ {b : ℤ√d}, IsPell b ↔ b * star b = 1
  | ⟨x, y⟩ => by 

Proof state:
d x y : ℤ
⊢ IsPell { re := x, im := y } ↔ { re := x, im := y } * star { re := x, im := y } = 1

Next tactic:
simp [Zsqrtd.ext, IsPell, mul_comm]
theorem isPell_norm : ∀ {b : ℤ√d}, IsPell b ↔ b * star b = 1
  | ⟨x, y⟩ => by simp [Zsqrtd.ext, IsPell, mul_comm]; 

Proof state:
d x y : ℤ
⊢ x * x - y * (d * y) = 1 ↔ x * x + -(y * (d * y)) = 1

Next tactic:
ring_nf
theorem isPell_iff_mem_unitary : ∀ {b : ℤ√d}, IsPell b ↔ b ∈ unitary (ℤ√d)
  | ⟨x, y⟩ => by 

Proof state:
d x y : ℤ
⊢ IsPell { re := x, im := y } ↔ { re := x, im := y } ∈ unitary (ℤ√d)

Next tactic:
rw [unitary.mem_iff, isPell_norm, mul_comm (star _), and_self_iff]
theorem isPell_mul {b c : ℤ√d} (hb : IsPell b) (hc : IsPell c) : IsPell (b * c) :=
  isPell_norm.2 (by 

Proof state:
d : ℤ
b c : ℤ√d
hb : IsPell b
hc : IsPell c
⊢ b * c * star (b * c) = 1

Next tactic:
simp [mul_comm, mul_left_comm c, mul_assoc,
    star_mul, isPell_norm.1 hb, isPell_norm.1 hc]
theorem isPell_star : ∀ {b : ℤ√d}, IsPell b ↔ IsPell (star b)
  | ⟨x, y⟩ => by 

Proof state:
d x y : ℤ
⊢ IsPell { re := x, im := y } ↔ IsPell (star { re := x, im := y })

Next tactic:
simp [IsPell, Zsqrtd.star_mk]
@[simp]
theorem d_pos : 0 < d a1 :=
  tsub_pos_of_lt (mul_lt_mul a1 (le_of_lt a1) (by 

Proof state:
a : ℕ
a1 : 1 < a
⊢ 0 < 1

Next tactic:
decide
theorem xn_one : xn a1 1 = a := by 

Proof state:
a : ℕ
a1 : 1 < a
⊢ xn a1 1 = a

Next tactic:
simp
theorem yn_one : yn a1 1 = 1 := by 

Proof state:
a : ℕ
a1 : 1 < a
⊢ yn a1 1 = 1

Next tactic:
simp
theorem asq_pos : 0 < a * a :=
  le_trans (le_of_lt a1)
    (by 

Proof state:
a : ℕ
a1 : 1 < a
⊢ a ≤ a * a

Next tactic:
have := @Nat.mul_le_mul_left 1 a a (le_of_lt a1)
theorem asq_pos : 0 < a * a :=
  le_trans (le_of_lt a1)
    (by have := @Nat.mul_le_mul_left 1 a a (le_of_lt a1); 

Proof state:
a : ℕ
a1 : 1 < a
this : a * 1 ≤ a * a
⊢ a ≤ a * a

Next tactic:
rwa [mul_one] at this
theorem dz_val : ↑(d a1) = az a * az a - 1 :=
  have : 1 ≤ a * a := asq_pos a1
  by 

Proof state:
a : ℕ
a1 : 1 < a
this : 1 ≤ a * a
⊢ ↑(Pell.d a1) = az a * az a - 1

Next tactic:
rw [Pell.d, Int.ofNat_sub this]
theorem dz_val : ↑(d a1) = az a * az a - 1 :=
  have : 1 ≤ a * a := asq_pos a1
  by rw [Pell.d, Int.ofNat_sub this]; 

Proof state:
a : ℕ
a1 : 1 < a
this : 1 ≤ a * a
⊢ ↑(a * a) - ↑1 = az a * az a - 1

Next tactic:
rfl
theorem isPell_nat {x y : ℕ} : IsPell (⟨x, y⟩ : ℤ√(d a1)) ↔ x * x - d a1 * y * y = 1 :=
  ⟨fun h =>
    Nat.cast_inj.1
      (by 

Proof state:
a : ℕ
a1 : 1 < a
x y : ℕ
h : IsPell { re := ↑x, im := ↑y }
⊢ ↑(x * x - Pell.d a1 * y * y) = ↑1

Next tactic:
rw [Int.ofNat_sub (Int.le_of_ofNat_le_ofNat <| Int.le.intro_sub _ h)]
theorem isPell_nat {x y : ℕ} : IsPell (⟨x, y⟩ : ℤ√(d a1)) ↔ x * x - d a1 * y * y = 1 :=
  ⟨fun h =>
    Nat.cast_inj.1
      (by rw [Int.ofNat_sub (Int.le_of_ofNat_le_ofNat <| Int.le.intro_sub _ h)]; 

Proof state:
a : ℕ
a1 : 1 < a
x y : ℕ
h : IsPell { re := ↑x, im := ↑y }
⊢ ↑(x * x) - ↑(Pell.d a1 * y * y) = ↑1

Next tactic:
exact h
theorem isPell_nat {x y : ℕ} : IsPell (⟨x, y⟩ : ℤ√(d a1)) ↔ x * x - d a1 * y * y = 1 :=
  ⟨fun h =>
    Nat.cast_inj.1
      (by rw [Int.ofNat_sub (Int.le_of_ofNat_le_ofNat <| Int.le.intro_sub _ h)]; exact h),
    fun h =>
    show ((x * x : ℕ) - (d a1 * y * y : ℕ) : ℤ) = 1 by
      

Proof state:
a : ℕ
a1 : 1 < a
x y : ℕ
h : x * x - Pell.d a1 * y * y = 1
⊢ ↑(x * x) - ↑(Pell.d a1 * y * y) = 1

Next tactic:
rw [← Int.ofNat_sub <| le_of_lt <| Nat.lt_of_sub_eq_succ h, h]
theorem isPell_nat {x y : ℕ} : IsPell (⟨x, y⟩ : ℤ√(d a1)) ↔ x * x - d a1 * y * y = 1 :=
  ⟨fun h =>
    Nat.cast_inj.1
      (by rw [Int.ofNat_sub (Int.le_of_ofNat_le_ofNat <| Int.le.intro_sub _ h)]; exact h),
    fun h =>
    show ((x * x : ℕ) - (d a1 * y * y : ℕ) : ℤ) = 1 by
      rw [← Int.ofNat_sub <| le_of_lt <| Nat.lt_of_sub_eq_succ h, h]; 

Proof state:
a : ℕ
a1 : 1 < a
x y : ℕ
h : x * x - Pell.d a1 * y * y = 1
⊢ ↑1 = 1

Next tactic:
rfl
@[simp]
theorem pellZd_succ (n : ℕ) : pellZd a1 (n + 1) = pellZd a1 n * ⟨a, 1⟩ := by 

Proof state:
a : ℕ
a1 : 1 < a
n : ℕ
⊢ pellZd a1 (n + 1) = pellZd a1 n * { re := ↑a, im := 1 }

Next tactic:
simp [Zsqrtd.ext]
theorem isPell_one : IsPell (⟨a, 1⟩ : ℤ√(d a1)) :=
  show az a * az a - d a1 * 1 * 1 = 1 by 

Proof state:
a : ℕ
a1 : 1 < a
⊢ az a * az a - ↑(Pell.d a1) * 1 * 1 = 1

Next tactic:
simp [dz_val]
theorem isPell_pellZd : ∀ n : ℕ, IsPell (pellZd a1 n)
  | 0 => rfl
  | n + 1 => by
    

Proof state:
a : ℕ
a1 : 1 < a
n : ℕ
⊢ IsPell (pellZd a1 (n + 1))

Next tactic:
let o := isPell_one a1