Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 384ba88

Browse files
committed
feat(computability/*FA): Deterministic and Nondeterministic Finite Automata (#5038)
Definition and equivalence of NFA's and DFA's Co-authored-by: foxthomson <11833933+foxthomson@users.noreply.github.com>
1 parent eb6d5f1 commit 384ba88

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

src/computability/DFA.lean

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/-
2+
Copyright (c) 2020 Fox Thomson. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Fox Thomson
5+
-/
6+
7+
import data.fintype.basic
8+
import computability.language
9+
10+
/-!
11+
# Deterministic Finite Automata
12+
This file contains the definition of a Deterministic Finite Automaton (DFA), a state machine which
13+
determines whether a string (implemented as a list over an arbitrary alphabet) is in a regular set
14+
in linear time.
15+
Note that this definition allows for Automaton with infinite states, a `fintype` instance must be
16+
supplied for true DFA's.
17+
-/
18+
19+
universes u v
20+
21+
/-- A DFA is a set of states (`σ`), a transition function from state to state labelled by the
22+
alphabet (`step`), a starting state (`start`) and a set of acceptance states (`accept`). -/
23+
structure DFA (α : Type u) (σ : Type v) :=
24+
(step : σ → α → σ)
25+
(start : σ)
26+
(accept : set σ)
27+
28+
namespace DFA
29+
30+
variables {α : Type u} {σ σ₁ σ₂ σ₃ : Type v} (M : DFA α σ)
31+
32+
instance [inhabited σ] : inhabited (DFA α σ) :=
33+
⟨DFA.mk (λ _ _, default σ) (default σ) ∅⟩
34+
35+
/-- `M.eval_from s x` evaluates `M` with input `x` starting from the state `s`. -/
36+
def eval_from (start : σ) : list α → σ :=
37+
list.foldl M.step start
38+
39+
/-- `M.eval x` evaluates `M` with input `x` starting from the state `M.start`. -/
40+
def eval := M.eval_from M.start
41+
42+
/-- `M.accepts` is the language of `x` such that `M.eval x` is an accept state. -/
43+
def accepts : language α :=
44+
λ x, M.eval x ∈ M.accept
45+
46+
end DFA

src/computability/NFA.lean

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/-
2+
Copyright (c) 2020 Fox Thomson. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Fox Thomson
5+
-/
6+
7+
import data.fintype.basic
8+
import computability.DFA
9+
10+
/-!
11+
# Nondeterministic Finite Automata
12+
This file contains the definition of a Nondeterministic Finite Automaton (NFA), a state machine
13+
which determines whether a string (implemented as a list over an arbitrary alphabet) is in a regular
14+
set by evaluating the string over every possible path.
15+
We show that DFA's are equivalent to NFA's however the construction from NFA to DFA uses an
16+
exponential number of states.
17+
Note that this definition allows for Automaton with infinite states, a `fintype` instance must be
18+
supplied for true NFA's.
19+
-/
20+
21+
universes u v
22+
23+
/-- An NFA is a set of states (`σ`), a transition function from state to state labelled by the
24+
alphabet (`step`), a starting state (`start`) and a set of acceptance states (`accept`).
25+
Note the transition function sends a state to a `set` of states. These are the states that it
26+
may be sent to. -/
27+
structure NFA (α : Type u) (σ : Type v) :=
28+
(step : σ → α → set σ)
29+
(start : set σ)
30+
(accept : set σ)
31+
32+
variables {α : Type u} {σ σ' σ₁ σ₂ σ₃ : Type v} (M : NFA α σ)
33+
34+
namespace NFA
35+
36+
instance : inhabited (NFA α σ') := ⟨ NFA.mk (λ _ _, ∅) ∅ ∅ ⟩
37+
38+
/-- `M.step_set S a` is the union of `M.step s a` for all `s ∈ S`. -/
39+
def step_set : set σ → α → set σ :=
40+
λ Ss a, Ss >>= (λ S, (M.step S a))
41+
42+
lemma mem_step_set (s : σ) (S : set σ) (a : α) :
43+
s ∈ M.step_set S a ↔ ∃ t ∈ S, s ∈ M.step t a :=
44+
by simp only [step_set, set.mem_Union, set.bind_def]
45+
46+
/-- `M.eval_from S x` computes all possible paths though `M` with input `x` starting at an element
47+
of `S`. -/
48+
def eval_from (start : set σ) : list α → set σ :=
49+
list.foldl M.step_set start
50+
51+
/-- `M.eval x` computes all possible paths though `M` with input `x` starting at an element of
52+
`M.start`. -/
53+
def eval := M.eval_from M.start
54+
55+
/-- `M.accepts` is the language of `x` such that there is an accept state in `M.eval x`. -/
56+
def accepts : language α :=
57+
λ x, ∃ S ∈ M.accept, S ∈ M.eval x
58+
59+
/-- `M.to_DFA` is an `DFA` constructed from a `NFA` `M` using the subset construction. The
60+
states is the type of `set`s of `M.state` and the step function is `M.step_set`. -/
61+
def to_DFA : DFA α (set σ) :=
62+
{ step := M.step_set,
63+
start := M.start,
64+
accept := {S | ∃ s ∈ S, s ∈ M.accept} }
65+
66+
@[simp] lemma to_DFA_correct :
67+
M.to_DFA.accepts = M.accepts :=
68+
begin
69+
ext x,
70+
rw [accepts, DFA.accepts, eval, DFA.eval],
71+
change list.foldl _ _ _ ∈ {S | _} ↔ _,
72+
finish
73+
end
74+
75+
end NFA
76+
77+
namespace DFA
78+
79+
/-- `M.to_NFA` is an `NFA` constructed from a `DFA` `M` by using the same start and accept
80+
states and a transition function which sends `s` with input `a` to the singleton `M.step s a`. -/
81+
def to_NFA (M : DFA α σ') : NFA α σ' :=
82+
{ step := λ s a, {M.step s a},
83+
start := {M.start},
84+
accept := M.accept }
85+
86+
@[simp] lemma to_NFA_eval_from_match (M : DFA α σ) (start : σ) (s : list α) :
87+
M.to_NFA.eval_from {start} s = {M.eval_from start s} :=
88+
begin
89+
change list.foldl M.to_NFA.step_set {start} s = {list.foldl M.step start s},
90+
induction s with a s ih generalizing start,
91+
{ tauto },
92+
{ rw [list.foldl, list.foldl],
93+
have h : M.to_NFA.step_set {start} a = {M.step start a},
94+
{ rw NFA.step_set,
95+
finish },
96+
rw h,
97+
tauto }
98+
end
99+
100+
@[simp] lemma to_NFA_correct (M : DFA α σ) :
101+
M.to_NFA.accepts = M.accepts :=
102+
begin
103+
ext x,
104+
change (∃ S H, S ∈ M.to_NFA.eval_from {M.start} x) ↔ _,
105+
rw to_NFA_eval_from_match,
106+
split,
107+
{ rintro ⟨ S, hS₁, hS₂ ⟩,
108+
rw set.mem_singleton_iff at hS₂,
109+
rw hS₂ at hS₁,
110+
assumption },
111+
{ intro h,
112+
use M.eval x,
113+
finish }
114+
end
115+
116+
end DFA

0 commit comments

Comments
 (0)