File: Mathlib/Computability/EpsilonNFA.lean

full_name: εNFA.step
code: /-- An `εNFA` is a set of states (`σ`), a transition function from state to state labelled by the
  alphabet (`step`), a starting state (`start`) and a set of acceptance states (`accept`).
  Note the transition function sends a state to a `Set` of states and can make ε-transitions by
  inputing `none`.
  Since this definition allows for Automata with infinite states, a `Fintype` instance must be
  supplied for true `εNFA`'s. -/
structure εNFA (α : Type u) (σ : Type v) where
  /-- Transition function. The automaton is rendered non-deterministic by this transition function
  returning `Set σ` (rather than `σ`), and ε-transitions are made possible by taking `Option α`
  (rather than `α`). -/
  step : σ → Option α → Set σ
  /-- Starting states. -/
  start : Set σ
  /-- Set of acceptance states. -/
  accept : Set σ
goal: σ → Option α → Set σ

full_name: εNFA.start
code: /-- An `εNFA` is a set of states (`σ`), a transition function from state to state labelled by the
  alphabet (`step`), a starting state (`start`) and a set of acceptance states (`accept`).
  Note the transition function sends a state to a `Set` of states and can make ε-transitions by
  inputing `none`.
  Since this definition allows for Automata with infinite states, a `Fintype` instance must be
  supplied for true `εNFA`'s. -/
structure εNFA (α : Type u) (σ : Type v) where
  /-- Transition function. The automaton is rendered non-deterministic by this transition function
  returning `Set σ` (rather than `σ`), and ε-transitions are made possible by taking `Option α`
  (rather than `α`). -/
  step : σ → Option α → Set σ
  /-- Starting states. -/
  start : Set σ
  /-- Set of acceptance states. -/
  accept : Set σ
goal: Set σ

full_name: εNFA
code: /-- An `εNFA` is a set of states (`σ`), a transition function from state to state labelled by the
  alphabet (`step`), a starting state (`start`) and a set of acceptance states (`accept`).
  Note the transition function sends a state to a `Set` of states and can make ε-transitions by
  inputing `none`.
  Since this definition allows for Automata with infinite states, a `Fintype` instance must be
  supplied for true `εNFA`'s. -/
structure εNFA (α : Type u) (σ : Type v) where
  /-- Transition function. The automaton is rendered non-deterministic by this transition function
  returning `Set σ` (rather than `σ`), and ε-transitions are made possible by taking `Option α`
  (rather than `α`). -/
  step : σ → Option α → Set σ
  /-- Starting states. -/
  start : Set σ
  /-- Set of acceptance states. -/
  accept : Set σ
goal: Type (max u v)

full_name: εNFA.accept
code: /-- An `εNFA` is a set of states (`σ`), a transition function from state to state labelled by the
  alphabet (`step`), a starting state (`start`) and a set of acceptance states (`accept`).
  Note the transition function sends a state to a `Set` of states and can make ε-transitions by
  inputing `none`.
  Since this definition allows for Automata with infinite states, a `Fintype` instance must be
  supplied for true `εNFA`'s. -/
structure εNFA (α : Type u) (σ : Type v) where
  /-- Transition function. The automaton is rendered non-deterministic by this transition function
  returning `Set σ` (rather than `σ`), and ε-transitions are made possible by taking `Option α`
  (rather than `α`). -/
  step : σ → Option α → Set σ
  /-- Starting states. -/
  start : Set σ
  /-- Set of acceptance states. -/
  accept : Set σ
goal: Set σ

full_name: εNFA.εClosure.base
code: /-- The `εClosure` of a set is the set of states which can be reached by taking a finite string of
ε-transitions from an element of the set. -/
inductive εClosure (S : Set σ) : Set σ
  | base : ∀ s ∈ S, εClosure S s
  | step : ∀ (s), ∀ t ∈ M.step s none, εClosure S s → εClosure S t
goal: s ∈ S → M.εClosure S s

full_name: εNFA.εClosure.step
code: /-- The `εClosure` of a set is the set of states which can be reached by taking a finite string of
ε-transitions from an element of the set. -/
inductive εClosure (S : Set σ) : Set σ
  | base : ∀ s ∈ S, εClosure S s
  | step : ∀ (s), ∀ t ∈ M.step s none, εClosure S s → εClosure S t
goal: t ∈ M.step s none → M.εClosure S s → M.εClosure S t

full_name: εNFA.εClosure
code: /-- The `εClosure` of a set is the set of states which can be reached by taking a finite string of
ε-transitions from an element of the set. -/
inductive εClosure (S : Set σ) : Set σ
  | base : ∀ s ∈ S, εClosure S s
  | step : ∀ (s), ∀ t ∈ M.step s none, εClosure S s → εClosure S t
goal: Set σ

full_name: εNFA.subset_εClosure
code: @[simp]
theorem subset_εClosure (S : Set σ) : S ⊆ M.εClosure S 
goal: S ⊆ M.εClosure S

full_name: εNFA.εClosure_empty
code: @[simp]
theorem εClosure_empty : M.εClosure ∅ = ∅ 
goal: M.εClosure ∅ = ∅

full_name: εNFA.εClosure_univ
code: @[simp]
theorem εClosure_univ : M.εClosure univ = univ 
goal: M.εClosure Set.univ = Set.univ

full_name: εNFA.stepSet
code: /-- `M.stepSet S a` is the union of the ε-closure of `M.step s a` for all `s ∈ S`. -/
def stepSet (S : Set σ) (a : α) : Set σ 
goal: Set σ

full_name: εNFA.mem_stepSet_iff
code: @[simp]
theorem mem_stepSet_iff : s ∈ M.stepSet S a ↔ ∃ t ∈ S, s ∈ M.εClosure (M.step t a) 
goal: s ∈ M.stepSet S a ↔ ∃ t ∈ S, s ∈ M.εClosure (M.step t (some a))

full_name: εNFA.stepSet_empty
code: @[simp]
theorem stepSet_empty (a : α) : M.stepSet ∅ a = ∅ 
goal: M.stepSet ∅ a = ∅

full_name: εNFA.evalFrom
code: /-- `M.evalFrom S x` computes all possible paths through `M` with input `x` starting at an element
of `S`. -/
def evalFrom (start : Set σ) : List α → Set σ 
goal: List α → Set σ

full_name: εNFA.evalFrom_nil
code: @[simp]
theorem evalFrom_nil (S : Set σ) : M.evalFrom S [] = M.εClosure S 
goal: M.evalFrom S [] = M.εClosure S

full_name: εNFA.evalFrom_singleton
code: @[simp]
theorem evalFrom_singleton (S : Set σ) (a : α) : M.evalFrom S [a] = M.stepSet (M.εClosure S) a 
goal: M.evalFrom S [a] = M.stepSet (M.εClosure S) a

full_name: εNFA.evalFrom_append_singleton
code: @[simp]
theorem evalFrom_append_singleton (S : Set σ) (x : List α) (a : α) :
    M.evalFrom S (x ++ [a]) = M.stepSet (M.evalFrom S x) a 
goal: M.evalFrom S (x ++ [a]) = M.stepSet (M.evalFrom S x) a

full_name: εNFA.evalFrom_empty
code: @[simp]
theorem evalFrom_empty (x : List α) : M.evalFrom ∅ x = ∅ 
goal: M.evalFrom ∅ x = ∅

full_name: εNFA.eval
code: /-- `M.eval x` computes all possible paths through `M` with input `x` starting at an element of
`M.start`. -/
def eval 
goal: List α → Set σ

full_name: εNFA.eval_nil
code: @[simp]
theorem eval_nil : M.eval [] = M.εClosure M.start 
goal: M.eval [] = M.εClosure M.start

full_name: εNFA.eval_singleton
code: @[simp]
theorem eval_singleton (a : α) : M.eval [a] = M.stepSet (M.εClosure M.start) a 
goal: M.eval [a] = M.stepSet (M.εClosure M.start) a

full_name: εNFA.eval_append_singleton
code: @[simp]
theorem eval_append_singleton (x : List α) (a : α) : M.eval (x ++ [a]) = M.stepSet (M.eval x) a 
goal: M.eval (x ++ [a]) = M.stepSet (M.eval x) a

full_name: εNFA.accepts
code: /-- `M.accepts` is the language of `x` such that there is an accept state in `M.eval x`. -/
def accepts : Language α 
goal: Language α

full_name: εNFA.toNFA
code: /-- `M.toNFA` is an `NFA` constructed from an `εNFA` `M`. -/
def toNFA : NFA α σ 
goal: NFA α σ

full_name: εNFA.toNFA_evalFrom_match
code: @[simp]
theorem toNFA_evalFrom_match (start : Set σ) :
    M.toNFA.evalFrom (M.εClosure start) = M.evalFrom start 
goal: M.toNFA.evalFrom (M.εClosure start) = M.evalFrom start

full_name: εNFA.toNFA_correct
code: @[simp]
theorem toNFA_correct : M.toNFA.accepts = M.accepts 
goal: M.toNFA.accepts = M.accepts

full_name: εNFA.pumping_lemma
code: 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 
goal: ∃ a b c, x = a ++ b ++ c ∧ a.length + b.length ≤ Fintype.card (Set σ) ∧ b ≠ [] ∧ {a} * {b}∗ * {c} ≤ M.accepts

full_name: NFA.toεNFA
code: /-- `M.toεNFA` is an `εNFA` constructed from an `NFA` `M` by using the same start and accept
  states and transition functions. -/
def toεNFA (M : NFA α σ) : εNFA α σ 
goal: εNFA α σ

full_name: NFA.toεNFA_εClosure
code: @[simp]
theorem toεNFA_εClosure (M : NFA α σ) (S : Set σ) : M.toεNFA.εClosure S = S 
goal: M.toεNFA.εClosure S = S

full_name: NFA.toεNFA_evalFrom_match
code: @[simp]
theorem toεNFA_evalFrom_match (M : NFA α σ) (start : Set σ) :
    M.toεNFA.evalFrom start = M.evalFrom start 
goal: M.toεNFA.evalFrom start = M.evalFrom start

full_name: NFA.toεNFA_correct
code: @[simp]
theorem toεNFA_correct (M : NFA α σ) : M.toεNFA.accepts = M.accepts 
goal: M.toεNFA.accepts = M.accepts

full_name: εNFA.instZero
code: instance : Zero (εNFA α σ) 
goal: Zero (εNFA α σ)

full_name: εNFA.instOne
code: instance : One (εNFA α σ) 
goal: One (εNFA α σ)

full_name: εNFA.instInhabited
code: instance : Inhabited (εNFA α σ) 
goal: Inhabited (εNFA α σ)

full_name: εNFA.step_zero
code: @[simp]
theorem step_zero (s a) : (0 : εNFA α σ).step s a = ∅ 
goal: εNFA.step 0 s a = ∅

full_name: εNFA.step_one
code: @[simp]
theorem step_one (s a) : (1 : εNFA α σ).step s a = ∅ 
goal: εNFA.step 1 s a = ∅

full_name: εNFA.start_zero
code: @[simp]
theorem start_zero : (0 : εNFA α σ).start = ∅ 
goal: εNFA.start 0 = ∅

full_name: εNFA.start_one
code: @[simp]
theorem start_one : (1 : εNFA α σ).start = univ 
goal: εNFA.start 1 = Set.univ

full_name: εNFA.accept_zero
code: @[simp]
theorem accept_zero : (0 : εNFA α σ).accept = ∅ 
goal: εNFA.accept 0 = ∅

full_name: εNFA.accept_one
code: @[simp]
theorem accept_one : (1 : εNFA α σ).accept = univ 
goal: εNFA.accept 1 = Set.univ