l3lab/ntp-mathlib huggingface dataset:
theorem PosSemidef.fromBlocks₁₁ [Fintype m] [DecidableEq m] [Fintype n] {A : Matrix m m 𝕜}
    (B : Matrix m n 𝕜) (D : Matrix n n 𝕜) (hA : A.PosDef) [Invertible A] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (D - Bᴴ * A⁻¹ * B).PosSemidef := by
  rw [PosSemidef, IsHermitian.fromBlocks₁₁ _ _ hA.1]
  constructor
  · refine' fun h => ⟨h.1, fun x => _⟩
    have := h.2 (-(A⁻¹ * B).mulVec x ⊕ᵥ x)
    rw [dotProduct_mulVec, schur_complement_eq₁₁ B D _ _ hA.1, neg_add_self, dotProduct_zero,
      zero_add] at this
    rw [dotProduct_mulVec]; exact this
  · refine' fun h => ⟨h.1, fun x => _⟩
    rw [dotProduct_mulVec, ← Sum.elim_comp_inl_inr x, schur_complement_eq₁₁ B D _ _ hA.1]
    apply le_add_of_nonneg_of_le
    · 

Proof state:
case mpr.ha
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : DecidableEq m
inst✝¹ : Fintype n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hA : PosDef A
inst✝ : Invertible A
h : PosSemidef (D - Bᴴ * A⁻¹ * B)
x : m ⊕ n → 𝕜
⊢ 0 ≤ vecMul (star (x ∘ Sum.inl + mulVec (A⁻¹ * B) (x ∘ Sum.inr))) A ⬝ᵥ (x ∘ Sum.inl + mulVec (A⁻¹ * B) (x ∘ Sum.inr))

Next tactic:
rw [← dotProduct_mulVec]
theorem PosSemidef.fromBlocks₁₁ [Fintype m] [DecidableEq m] [Fintype n] {A : Matrix m m 𝕜}
    (B : Matrix m n 𝕜) (D : Matrix n n 𝕜) (hA : A.PosDef) [Invertible A] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (D - Bᴴ * A⁻¹ * B).PosSemidef := by
  rw [PosSemidef, IsHermitian.fromBlocks₁₁ _ _ hA.1]
  constructor
  · refine' fun h => ⟨h.1, fun x => _⟩
    have := h.2 (-(A⁻¹ * B).mulVec x ⊕ᵥ x)
    rw [dotProduct_mulVec, schur_complement_eq₁₁ B D _ _ hA.1, neg_add_self, dotProduct_zero,
      zero_add] at this
    rw [dotProduct_mulVec]; exact this
  · refine' fun h => ⟨h.1, fun x => _⟩
    rw [dotProduct_mulVec, ← Sum.elim_comp_inl_inr x, schur_complement_eq₁₁ B D _ _ hA.1]
    apply le_add_of_nonneg_of_le
    · rw [← dotProduct_mulVec]
      

Proof state:
case mpr.ha
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : DecidableEq m
inst✝¹ : Fintype n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hA : PosDef A
inst✝ : Invertible A
h : PosSemidef (D - Bᴴ * A⁻¹ * B)
x : m ⊕ n → 𝕜
⊢ 0 ≤ star (x ∘ Sum.inl + mulVec (A⁻¹ * B) (x ∘ Sum.inr)) ⬝ᵥ mulVec A (x ∘ Sum.inl + mulVec (A⁻¹ * B) (x ∘ Sum.inr))

Next tactic:
apply hA.posSemidef.2
theorem PosSemidef.fromBlocks₁₁ [Fintype m] [DecidableEq m] [Fintype n] {A : Matrix m m 𝕜}
    (B : Matrix m n 𝕜) (D : Matrix n n 𝕜) (hA : A.PosDef) [Invertible A] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (D - Bᴴ * A⁻¹ * B).PosSemidef := by
  rw [PosSemidef, IsHermitian.fromBlocks₁₁ _ _ hA.1]
  constructor
  · refine' fun h => ⟨h.1, fun x => _⟩
    have := h.2 (-(A⁻¹ * B).mulVec x ⊕ᵥ x)
    rw [dotProduct_mulVec, schur_complement_eq₁₁ B D _ _ hA.1, neg_add_self, dotProduct_zero,
      zero_add] at this
    rw [dotProduct_mulVec]; exact this
  · refine' fun h => ⟨h.1, fun x => _⟩
    rw [dotProduct_mulVec, ← Sum.elim_comp_inl_inr x, schur_complement_eq₁₁ B D _ _ hA.1]
    apply le_add_of_nonneg_of_le
    · rw [← dotProduct_mulVec]
      apply hA.posSemidef.2
    · 

Proof state:
case mpr.hbc
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : DecidableEq m
inst✝¹ : Fintype n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hA : PosDef A
inst✝ : Invertible A
h : PosSemidef (D - Bᴴ * A⁻¹ * B)
x : m ⊕ n → 𝕜
⊢ 0 ≤ vecMul (star (x ∘ Sum.inr)) (D - Bᴴ * A⁻¹ * B) ⬝ᵥ x ∘ Sum.inr

Next tactic:
rw [← dotProduct_mulVec (star (x ∘ Sum.inr))]
theorem PosSemidef.fromBlocks₁₁ [Fintype m] [DecidableEq m] [Fintype n] {A : Matrix m m 𝕜}
    (B : Matrix m n 𝕜) (D : Matrix n n 𝕜) (hA : A.PosDef) [Invertible A] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (D - Bᴴ * A⁻¹ * B).PosSemidef := by
  rw [PosSemidef, IsHermitian.fromBlocks₁₁ _ _ hA.1]
  constructor
  · refine' fun h => ⟨h.1, fun x => _⟩
    have := h.2 (-(A⁻¹ * B).mulVec x ⊕ᵥ x)
    rw [dotProduct_mulVec, schur_complement_eq₁₁ B D _ _ hA.1, neg_add_self, dotProduct_zero,
      zero_add] at this
    rw [dotProduct_mulVec]; exact this
  · refine' fun h => ⟨h.1, fun x => _⟩
    rw [dotProduct_mulVec, ← Sum.elim_comp_inl_inr x, schur_complement_eq₁₁ B D _ _ hA.1]
    apply le_add_of_nonneg_of_le
    · rw [← dotProduct_mulVec]
      apply hA.posSemidef.2
    · rw [← dotProduct_mulVec (star (x ∘ Sum.inr))]
      

Proof state:
case mpr.hbc
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : DecidableEq m
inst✝¹ : Fintype n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hA : PosDef A
inst✝ : Invertible A
h : PosSemidef (D - Bᴴ * A⁻¹ * B)
x : m ⊕ n → 𝕜
⊢ 0 ≤ star (x ∘ Sum.inr) ⬝ᵥ mulVec (D - Bᴴ * A⁻¹ * B) (x ∘ Sum.inr)

Next tactic:
apply h.2
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ PosSemidef (fromBlocks A B Bᴴ D) ↔ PosSemidef (A - B * D⁻¹ * Bᴴ)

Next tactic:
rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ PosSemidef (fromBlocks D Bᴴ B A) ↔ PosSemidef (A - B * D⁻¹ * Bᴴ)

Next tactic:
convert PosSemidef.fromBlocks₁₁ Bᴴ A hD
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
  convert PosSemidef.fromBlocks₁₁ Bᴴ A hD <;>
    

Proof state:
case h.e'_1.h.e'_7.h.e'_8
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ B = Bᴴᴴ

Next tactic:
first
    | infer_instance
    | simp
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
  convert PosSemidef.fromBlocks₁₁ Bᴴ A hD <;>
    first
    | 

Proof state:
case h.e'_1.h.e'_7.h.e'_8
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ B = Bᴴᴴ

Next tactic:
infer_instance
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
  convert PosSemidef.fromBlocks₁₁ Bᴴ A hD <;>
    first
    | infer_instance
    | 

Proof state:
case h.e'_1.h.e'_7.h.e'_8
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ B = Bᴴᴴ

Next tactic:
simp
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
  convert PosSemidef.fromBlocks₁₁ Bᴴ A hD <;>
    

Proof state:
case h.e'_2.h.e'_7.h.e'_6.h.e'_5.h.e'_5
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ B = Bᴴᴴ

Next tactic:
first
    | infer_instance
    | simp
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
  convert PosSemidef.fromBlocks₁₁ Bᴴ A hD <;>
    first
    | 

Proof state:
case h.e'_2.h.e'_7.h.e'_6.h.e'_5.h.e'_5
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ B = Bᴴᴴ

Next tactic:
infer_instance
theorem PosSemidef.fromBlocks₂₂ [Fintype m] [Fintype n] [DecidableEq n] (A : Matrix m m 𝕜)
    (B : Matrix m n 𝕜) {D : Matrix n n 𝕜} (hD : D.PosDef) [Invertible D] :
    (fromBlocks A B Bᴴ D).PosSemidef ↔ (A - B * D⁻¹ * Bᴴ).PosSemidef := by
  rw [← posSemidef_submatrix_equiv (Equiv.sumComm n m), Equiv.sumComm_apply,
    fromBlocks_submatrix_sum_swap_sum_swap]
  convert PosSemidef.fromBlocks₁₁ Bᴴ A hD <;>
    first
    | infer_instance
    | 

Proof state:
case h.e'_2.h.e'_7.h.e'_6.h.e'_5.h.e'_5
l : Type u_1
m : Type u_2
n : Type u_3
α : Type u_4
𝕜 : Type u_5
inst✝⁶ : CommRing 𝕜
inst✝⁵ : PartialOrder 𝕜
inst✝⁴ : StarOrderedRing 𝕜
inst✝³ : Fintype m
inst✝² : Fintype n
inst✝¹ : DecidableEq n
A : Matrix m m 𝕜
B : Matrix m n 𝕜
D : Matrix n n 𝕜
hD : PosDef D
inst✝ : Invertible D
⊢ B = Bᴴᴴ

Next tactic:
simp
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  

Proof state:
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v : List (Symbol T N)
hyp : Rewrites r u v
⊢ ∃ p q, u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q

Next tactic:
induction hyp with
  | head xs =>
    use [], xs
    simp
  | cons x _ ih =>
    rcases ih with ⟨p', q', rfl, rfl⟩
    use x :: p', q'
    simp
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  induction hyp with
  

Proof state:
case head
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v xs : List (Symbol T N)
⊢ ∃ p q, Symbol.nonterminal r.input :: xs = p ++ [Symbol.nonterminal r.input] ++ q ∧ r.output ++ xs = p ++ r.output ++ q

Next tactic:
| head xs =>
    use [], xs
    simp
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  induction hyp with
  | head xs =>
    

Proof state:
case head
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v xs : List (Symbol T N)
⊢ ∃ p q, Symbol.nonterminal r.input :: xs = p ++ [Symbol.nonterminal r.input] ++ q ∧ r.output ++ xs = p ++ r.output ++ q

Next tactic:
use [], xs
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  induction hyp with
  | head xs =>
    use [], xs
    

Proof state:
case h
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v xs : List (Symbol T N)
⊢ Symbol.nonterminal r.input :: xs = [] ++ [Symbol.nonterminal r.input] ++ xs ∧ r.output ++ xs = [] ++ r.output ++ xs

Next tactic:
simp
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  induction hyp with
  | head xs =>
    use [], xs
    simp
  

Proof state:
case cons
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v : List (Symbol T N)
x : Symbol T N
s₁✝ s₂✝ : List (Symbol T N)
hrs✝ : Rewrites r s₁✝ s₂✝
ih : ∃ p q, s₁✝ = p ++ [Symbol.nonterminal r.input] ++ q ∧ s₂✝ = p ++ r.output ++ q
⊢ ∃ p q, x :: s₁✝ = p ++ [Symbol.nonterminal r.input] ++ q ∧ x :: s₂✝ = p ++ r.output ++ q

Next tactic:
| cons x _ ih =>
    rcases ih with ⟨p', q', rfl, rfl⟩
    use x :: p', q'
    simp
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  induction hyp with
  | head xs =>
    use [], xs
    simp
  | cons x _ ih =>
    

Proof state:
case cons
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v : List (Symbol T N)
x : Symbol T N
s₁✝ s₂✝ : List (Symbol T N)
hrs✝ : Rewrites r s₁✝ s₂✝
ih : ∃ p q, s₁✝ = p ++ [Symbol.nonterminal r.input] ++ q ∧ s₂✝ = p ++ r.output ++ q
⊢ ∃ p q, x :: s₁✝ = p ++ [Symbol.nonterminal r.input] ++ q ∧ x :: s₂✝ = p ++ r.output ++ q

Next tactic:
rcases ih with ⟨p', q', rfl, rfl⟩
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  induction hyp with
  | head xs =>
    use [], xs
    simp
  | cons x _ ih =>
    rcases ih with ⟨p', q', rfl, rfl⟩
    

Proof state:
case cons.intro.intro.intro
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v : List (Symbol T N)
x : Symbol T N
p' q' : List (Symbol T N)
hrs✝ : Rewrites r (p' ++ [Symbol.nonterminal r.input] ++ q') (p' ++ r.output ++ q')
⊢ ∃ p q,
    x :: (p' ++ [Symbol.nonterminal r.input] ++ q') = p ++ [Symbol.nonterminal r.input] ++ q ∧
      x :: (p' ++ r.output ++ q') = p ++ r.output ++ q

Next tactic:
use x :: p', q'
lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)}
    (hyp : r.Rewrites u v) :
    ∃ p : List (Symbol T N), ∃ q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by
  induction hyp with
  | head xs =>
    use [], xs
    simp
  | cons x _ ih =>
    rcases ih with ⟨p', q', rfl, rfl⟩
    use x :: p', q'
    

Proof state:
case h
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v : List (Symbol T N)
x : Symbol T N
p' q' : List (Symbol T N)
hrs✝ : Rewrites r (p' ++ [Symbol.nonterminal r.input] ++ q') (p' ++ r.output ++ q')
⊢ x :: (p' ++ [Symbol.nonterminal r.input] ++ q') = x :: p' ++ [Symbol.nonterminal r.input] ++ q' ∧
    x :: (p' ++ r.output ++ q') = x :: p' ++ r.output ++ q'

Next tactic:
simp
lemma rewrites_of_exists_parts (r : ContextFreeRule T N) (p q : List (Symbol T N)) :
    r.Rewrites (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q) := by
  

Proof state:
T : Type uT
N : Type uN
r : ContextFreeRule T N
p q : List (Symbol T N)
⊢ Rewrites r (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q)

Next tactic:
induction p with
  | nil         => exact Rewrites.head q
  | cons d l ih => exact Rewrites.cons d ih
lemma rewrites_of_exists_parts (r : ContextFreeRule T N) (p q : List (Symbol T N)) :
    r.Rewrites (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q) := by
  induction p with
  

Proof state:
case nil
T : Type uT
N : Type uN
r : ContextFreeRule T N
q : List (Symbol T N)
⊢ Rewrites r ([] ++ [Symbol.nonterminal r.input] ++ q) ([] ++ r.output ++ q)

Next tactic:
| nil         => exact Rewrites.head q
lemma rewrites_of_exists_parts (r : ContextFreeRule T N) (p q : List (Symbol T N)) :
    r.Rewrites (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q) := by
  induction p with
  | nil         => 

Proof state:
case nil
T : Type uT
N : Type uN
r : ContextFreeRule T N
q : List (Symbol T N)
⊢ Rewrites r ([] ++ [Symbol.nonterminal r.input] ++ q) ([] ++ r.output ++ q)

Next tactic:
exact Rewrites.head q
lemma rewrites_of_exists_parts (r : ContextFreeRule T N) (p q : List (Symbol T N)) :
    r.Rewrites (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q) := by
  induction p with
  | nil         => exact Rewrites.head q
  

Proof state:
case cons
T : Type uT
N : Type uN
r : ContextFreeRule T N
q : List (Symbol T N)
d : Symbol T N
l : List (Symbol T N)
ih : Rewrites r (l ++ [Symbol.nonterminal r.input] ++ q) (l ++ r.output ++ q)
⊢ Rewrites r (d :: l ++ [Symbol.nonterminal r.input] ++ q) (d :: l ++ r.output ++ q)

Next tactic:
| cons d l ih => exact Rewrites.cons d ih
lemma rewrites_of_exists_parts (r : ContextFreeRule T N) (p q : List (Symbol T N)) :
    r.Rewrites (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q) := by
  induction p with
  | nil         => exact Rewrites.head q
  | cons d l ih => 

Proof state:
case cons
T : Type uT
N : Type uN
r : ContextFreeRule T N
q : List (Symbol T N)
d : Symbol T N
l : List (Symbol T N)
ih : Rewrites r (l ++ [Symbol.nonterminal r.input] ++ q) (l ++ r.output ++ q)
⊢ Rewrites r (d :: l ++ [Symbol.nonterminal r.input] ++ q) (d :: l ++ r.output ++ q)

Next tactic:
exact Rewrites.cons d ih
/-- Rule `r` rewrites string `u` is to string `v` iff they share both a prefix `p` and postfix `q`
such that the remaining middle part of `u` is the input of `r` and the remaining middle part
of `u` is the output of `r`. -/
theorem rewrites_iff {r : ContextFreeRule T N} (u v : List (Symbol T N)) :
    r.Rewrites u v ↔ ∃ p q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q :=
  ⟨Rewrites.exists_parts, by 

Proof state:
T : Type uT
N : Type uN
r : ContextFreeRule T N
u v : List (Symbol T N)
⊢ (∃ p q, u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q) → Rewrites r u v

Next tactic:
rintro ⟨p, q, rfl, rfl⟩
/-- Rule `r` rewrites string `u` is to string `v` iff they share both a prefix `p` and postfix `q`
such that the remaining middle part of `u` is the input of `r` and the remaining middle part
of `u` is the output of `r`. -/
theorem rewrites_iff {r : ContextFreeRule T N} (u v : List (Symbol T N)) :
    r.Rewrites u v ↔ ∃ p q : List (Symbol T N),
      u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q :=
  ⟨Rewrites.exists_parts, by rintro ⟨p, q, rfl, rfl⟩; 

Proof state:
case intro.intro.intro
T : Type uT
N : Type uN
r : ContextFreeRule T N
p q : List (Symbol T N)
⊢ Rewrites r (p ++ [Symbol.nonterminal r.input] ++ q) (p ++ r.output ++ q)

Next tactic:
apply rewrites_of_exists_parts
/-- A given word `w` belongs to the language generated by a given context-free grammar `g` iff
`g` can derive the word `w` (wrapped as a string) from the initial nonterminal of `g` in some
number of steps. -/
@[simp]
lemma mem_language_iff (g : ContextFreeGrammar.{uN} T) (w : List T) :
    w ∈ g.language ↔ g.Derives [Symbol.nonterminal g.initial] (List.map Symbol.terminal w) := by
  

Proof state:
T : Type uT
g : ContextFreeGrammar T
w : List T
⊢ w ∈ language g ↔ Derives g [Symbol.nonterminal g.initial] (List.map Symbol.terminal w)

Next tactic:
rfl
/-- One step in the proof of the Tietze extension theorem. If `e : C(X, Y)` is a closed embedding
of a topological space into a normal topological space and `f : X →ᵇ ℝ` is a bounded continuous
function, then there exists a bounded continuous function `g : Y →ᵇ ℝ` of the norm `‖g‖ ≤ ‖f‖ / 3`
such that the distance between `g ∘ e` and `f` is at most `(2 / 3) * ‖f‖`. -/
theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : ClosedEmbedding e) :
    ∃ g : Y →ᵇ ℝ, ‖g‖ ≤ ‖f‖ / 3 ∧ dist (g.compContinuous e) f ≤ 2 / 3 * ‖f‖ := by
  

Proof state:
X : Type u_1
Y : Type u_2
inst✝² : TopologicalSpace X
inst✝¹ : TopologicalSpace Y
inst✝ : NormalSpace Y
f : X →ᵇ ℝ
e : C(X, Y)
he : ClosedEmbedding ⇑e
⊢ ∃ g, ‖g‖ ≤ ‖f‖ / 3 ∧ dist (compContinuous g e) f ≤ 2 / 3 * ‖f‖

Next tactic:
have h3 : (0 : ℝ) < 3 := by norm_num1
/-- One step in the proof of the Tietze extension theorem. If `e : C(X, Y)` is a closed embedding
of a topological space into a normal topological space and `f : X →ᵇ ℝ` is a bounded continuous
function, then there exists a bounded continuous function `g : Y →ᵇ ℝ` of the norm `‖g‖ ≤ ‖f‖ / 3`
such that the distance between `g ∘ e` and `f` is at most `(2 / 3) * ‖f‖`. -/
theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : ClosedEmbedding e) :
    ∃ g : Y →ᵇ ℝ, ‖g‖ ≤ ‖f‖ / 3 ∧ dist (g.compContinuous e) f ≤ 2 / 3 * ‖f‖ := by
  have h3 : (0 : ℝ) < 3 := by 

Proof state:
X : Type u_1
Y : Type u_2
inst✝² : TopologicalSpace X
inst✝¹ : TopologicalSpace Y
inst✝ : NormalSpace Y
f : X →ᵇ ℝ
e : C(X, Y)
he : ClosedEmbedding ⇑e
⊢ 0 < 3

Next tactic:
norm_num1
/-- One step in the proof of the Tietze extension theorem. If `e : C(X, Y)` is a closed embedding
of a topological space into a normal topological space and `f : X →ᵇ ℝ` is a bounded continuous
function, then there exists a bounded continuous function `g : Y →ᵇ ℝ` of the norm `‖g‖ ≤ ‖f‖ / 3`
such that the distance between `g ∘ e` and `f` is at most `(2 / 3) * ‖f‖`. -/
theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : ClosedEmbedding e) :
    ∃ g : Y →ᵇ ℝ, ‖g‖ ≤ ‖f‖ / 3 ∧ dist (g.compContinuous e) f ≤ 2 / 3 * ‖f‖ := by
  have h3 : (0 : ℝ) < 3 := by norm_num1
  

Proof state:
X : Type u_1
Y : Type u_2
inst✝² : TopologicalSpace X
inst✝¹ : TopologicalSpace Y
inst✝ : NormalSpace Y
f : X →ᵇ ℝ
e : C(X, Y)
he : ClosedEmbedding ⇑e
h3 : 0 < 3
⊢ ∃ g, ‖g‖ ≤ ‖f‖ / 3 ∧ dist (compContinuous g e) f ≤ 2 / 3 * ‖f‖

Next tactic:
have h23 : 0 < (2 / 3 : ℝ) := by norm_num1
/-- One step in the proof of the Tietze extension theorem. If `e : C(X, Y)` is a closed embedding
of a topological space into a normal topological space and `f : X →ᵇ ℝ` is a bounded continuous
function, then there exists a bounded continuous function `g : Y →ᵇ ℝ` of the norm `‖g‖ ≤ ‖f‖ / 3`
such that the distance between `g ∘ e` and `f` is at most `(2 / 3) * ‖f‖`. -/
theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : ClosedEmbedding e) :
    ∃ g : Y →ᵇ ℝ, ‖g‖ ≤ ‖f‖ / 3 ∧ dist (g.compContinuous e) f ≤ 2 / 3 * ‖f‖ := by
  have h3 : (0 : ℝ) < 3 := by norm_num1
  have h23 : 0 < (2 / 3 : ℝ) := by 

Proof state:
X : Type u_1
Y : Type u_2
inst✝² : TopologicalSpace X
inst✝¹ : TopologicalSpace Y
inst✝ : NormalSpace Y
f : X →ᵇ ℝ
e : C(X, Y)
he : ClosedEmbedding ⇑e
h3 : 0 < 3
⊢ 0 < 2 / 3

Next tactic:
norm_num1