-- Mathlib/Computability/EpsilonNFA.lean
theorem mem_accepts_iff_exists_path {x : List α} :
    x ∈ M.accepts ↔
      ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x' where
  mp

Proof state:
case intro.intro
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝¹ : s₂ ∈ M.accept
s₁ : σ
left✝ : s₁ ∈ M.start
h : ∃ x', x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Tactic:
tauto

Result:
no goals

Proof state:
case intro.intro
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝¹ : s₂ ∈ M.accept
s₁ : σ
left✝ : s₁ ∈ M.start
h : s₂ ∈ M.evalFrom {s₁} x
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Tactic:
rw [mem_evalFrom_iff_exists_path] at h

Result:
case intro.intro
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝¹ : s₂ ∈ M.accept
s₁ : σ
left✝ : s₁ ∈ M.start
h : ∃ x', x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Proof state:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
⊢ (∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x') → x ∈ M.accepts

Tactic:
intro ⟨s₁, s₂, x', hs₁, hs₂, h⟩

Result:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₁ s₂ : σ
x' : List (Option α)
hs₁ : s₁ ∈ M.start
hs₂ : s₂ ∈ M.accept
h : x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'
⊢ x ∈ M.accepts

Proof state:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₁ s₂ : σ
x' : List (Option α)
hs₁ : s₁ ∈ M.start
hs₂ : s₂ ∈ M.accept
h : x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'
⊢ x ∈ M.accepts

Tactic:
have := M.mem_evalFrom_iff_exists.mpr ⟨_, hs₁, M.mem_evalFrom_iff_exists_path.mpr ⟨_, h⟩⟩

Result:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₁ s₂ : σ
x' : List (Option α)
hs₁ : s₁ ∈ M.start
hs₂ : s₂ ∈ M.accept
h : x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'
this : s₂ ∈ M.evalFrom M.start x
⊢ x ∈ M.accepts

Proof state:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₁ s₂ : σ
x' : List (Option α)
hs₁ : s₁ ∈ M.start
hs₂ : s₂ ∈ M.accept
h : x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'
this : s₂ ∈ M.evalFrom M.start x
⊢ x ∈ M.accepts

Tactic:
exact ⟨s₂, hs₂, this⟩

Result:
no goals

Proof state:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝ : s₂ ∈ M.accept
h : ∃ t ∈ M.start, s₂ ∈ M.evalFrom {t} x
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Tactic:
obtain ⟨s₁, _, h⟩ := h

Result:
case intro.intro
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝¹ : s₂ ∈ M.accept
s₁ : σ
left✝ : s₁ ∈ M.start
h : s₂ ∈ M.evalFrom {s₁} x
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Proof state:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
⊢ x ∈ M.accepts → ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Tactic:
intro ⟨s₂, _, h⟩

Result:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝ : s₂ ∈ M.accept
h : s₂ ∈ M.eval x
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Proof state:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝ : s₂ ∈ M.accept
h : s₂ ∈ M.eval x
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'

Tactic:
rw [eval, mem_evalFrom_iff_exists] at h

Result:
α : Type u
σ : Type v
M : εNFA α σ
x : List α
s₂ : σ
left✝ : s₂ ∈ M.accept
h : ∃ t ∈ M.start, s₂ ∈ M.evalFrom {t} x
⊢ ∃ s₁ s₂ x', s₁ ∈ M.start ∧ s₂ ∈ M.accept ∧ x'.reduceOption = x ∧ M.IsPath s₁ s₂ x'