@@ -23,7 +23,6 @@ open Computability
23
23
24
24
universe u v
25
25
26
-
27
26
/-- An NFA is a set of states (`σ`), a transition function from state to state labelled by the
28
27
alphabet (`step`), a set of starting states (`start`) and a set of acceptance states (`accept`).
29
28
Note the transition function sends a state to a `Set` of states. These are the states that it
@@ -36,64 +35,76 @@ structure NFA (α : Type u) (σ : Type v) where
36
35
/-- Set of accepting states -/
37
36
accept : Set σ
38
37
39
- variable {α : Type u} {σ σ' : Type v} ( M : NFA α σ)
38
+ variable {α : Type u} {σ : Type v} { M : NFA α σ}
40
39
41
40
namespace NFA
42
41
43
42
instance : Inhabited (NFA α σ) :=
44
43
⟨NFA.mk (fun _ _ => ∅) ∅ ∅⟩
45
44
45
+ variable (M) in
46
46
/-- `M.stepSet S a` is the union of `M.step s a` for all `s ∈ S`. -/
47
47
def stepSet (S : Set σ) (a : α) : Set σ :=
48
48
⋃ s ∈ S, M.step s a
49
49
50
- theorem mem_stepSet ( s : σ) ( S : Set σ) ( a : α) : s ∈ M.stepSet S a ↔ ∃ t ∈ S, s ∈ M.step t a := by
50
+ theorem mem_stepSet { s : σ} { S : Set σ} { a : α} : s ∈ M.stepSet S a ↔ ∃ t ∈ S, s ∈ M.step t a := by
51
51
simp [stepSet]
52
52
53
+ variable (M) in
53
54
@[simp]
54
55
theorem stepSet_empty (a : α) : M.stepSet ∅ a = ∅ := by simp [stepSet]
55
56
57
+ variable (M) in
56
58
/-- `M.evalFrom S x` computes all possible paths through `M` with input `x` starting at an element
57
59
of `S`. -/
58
- def evalFrom (start : Set σ) : List α → Set σ :=
59
- List.foldl M.stepSet start
60
+ def evalFrom (S : Set σ) : List α → Set σ :=
61
+ List.foldl M.stepSet S
60
62
63
+ variable (M) in
61
64
@[simp]
62
65
theorem evalFrom_nil (S : Set σ) : M.evalFrom S [] = S :=
63
66
rfl
64
67
68
+ variable (M) in
65
69
@[simp]
66
70
theorem evalFrom_singleton (S : Set σ) (a : α) : M.evalFrom S [a] = M.stepSet S a :=
67
71
rfl
68
72
73
+ variable (M) in
69
74
@[simp]
70
75
theorem evalFrom_append_singleton (S : Set σ) (x : List α) (a : α) :
71
76
M.evalFrom S (x ++ [a]) = M.stepSet (M.evalFrom S x) a := by
72
77
simp only [evalFrom, List.foldl_append, List.foldl_cons, List.foldl_nil]
73
78
79
+ variable (M) in
74
80
/-- `M.eval x` computes all possible paths though `M` with input `x` starting at an element of
75
81
`M.start`. -/
76
82
def eval : List α → Set σ :=
77
83
M.evalFrom M.start
78
84
85
+ variable (M) in
79
86
@[simp]
80
87
theorem eval_nil : M.eval [] = M.start :=
81
88
rfl
82
89
90
+ variable (M) in
83
91
@[simp]
84
92
theorem eval_singleton (a : α) : M.eval [a] = M.stepSet M.start a :=
85
93
rfl
86
94
95
+ variable (M) in
87
96
@[simp]
88
97
theorem eval_append_singleton (x : List α) (a : α) : M.eval (x ++ [a]) = M.stepSet (M.eval x) a :=
89
- evalFrom_append_singleton _ _ _ _
98
+ evalFrom_append_singleton ..
90
99
100
+ variable (M) in
91
101
/-- `M.accepts` is the language of `x` such that there is an accept state in `M.eval x`. -/
92
102
def accepts : Language α := {x | ∃ S ∈ M.accept, S ∈ M.eval x}
93
103
94
104
theorem mem_accepts {x : List α} : x ∈ M.accepts ↔ ∃ S ∈ M.accept, S ∈ M.evalFrom M.start x := by
95
105
rfl
96
106
107
+ variable (M) in
97
108
/-- `M.toDFA` is a `DFA` constructed from an `NFA` `M` using the subset construction. The
98
109
states is the type of `Set`s of `M.state` and the step function is `M.stepSet`. -/
99
110
def toDFA : DFA α (Set σ) where
@@ -121,7 +132,7 @@ namespace DFA
121
132
122
133
/-- `M.toNFA` is an `NFA` constructed from a `DFA` `M` by using the same start and accept
123
134
states and a transition function which sends `s` with input `a` to the singleton `M.step s a`. -/
124
- @[simps] def toNFA (M : DFA α σ' ) : NFA α σ' where
135
+ @[simps] def toNFA (M : DFA α σ) : NFA α σ where
125
136
step s a := {M.step s a}
126
137
start := {M.start}
127
138
accept := M.accept
@@ -146,3 +157,63 @@ theorem toNFA_correct (M : DFA α σ) : M.toNFA.accepts = M.accepts := by
146
157
· exact fun h => ⟨M.eval x, h, rfl⟩
147
158
148
159
end DFA
160
+
161
+ namespace NFA
162
+
163
+ variable (M) in
164
+ /-- `M.reverse` constructs an NFA with the same states as `M`, but all the transitions reversed. The
165
+ resulting automaton accepts a word `x` if and only if `M` accepts `List.reverse x`. -/
166
+ @[simps]
167
+ def reverse : NFA α σ where
168
+ step s a := { s' | s ∈ M.step s' a }
169
+ start := M.accept
170
+ accept := M.start
171
+
172
+ variable (M) in
173
+ @[simp]
174
+ theorem reverse_reverse : M.reverse.reverse = M := by
175
+ simp [reverse]
176
+
177
+ theorem disjoint_stepSet_reverse {a : α} {S S' : Set σ} :
178
+ Disjoint S (M.reverse.stepSet S' a) ↔ Disjoint S' (M.stepSet S a) := by
179
+ rw [← not_iff_not]
180
+ simp only [Set.not_disjoint_iff, mem_stepSet, reverse_step, Set.mem_setOf_eq]
181
+ tauto
182
+
183
+ theorem disjoint_evalFrom_reverse {x : List α} {S S' : Set σ}
184
+ (h : Disjoint S (M.reverse.evalFrom S' x)) : Disjoint S' (M.evalFrom S x.reverse) := by
185
+ simp only [evalFrom, List.foldl_reverse] at h ⊢
186
+ induction x generalizing S S' with
187
+ | nil =>
188
+ rw [disjoint_comm]
189
+ exact h
190
+ | cons x xs ih =>
191
+ rw [List.foldl_cons] at h
192
+ rw [List.foldr_cons, ← NFA.disjoint_stepSet_reverse, disjoint_comm]
193
+ exact ih h
194
+
195
+ theorem disjoint_evalFrom_reverse_iff {x : List α} {S S' : Set σ} :
196
+ Disjoint S (M.reverse.evalFrom S' x) ↔ Disjoint S' (M.evalFrom S x.reverse) :=
197
+ ⟨disjoint_evalFrom_reverse, fun h ↦ List.reverse_reverse x ▸ disjoint_evalFrom_reverse h⟩
198
+
199
+ @[simp]
200
+ theorem mem_accepts_reverse {x : List α} : x ∈ M.reverse.accepts ↔ x.reverse ∈ M.accepts := by
201
+ simp [mem_accepts, ← Set.not_disjoint_iff, not_iff_not, disjoint_evalFrom_reverse_iff]
202
+
203
+ end NFA
204
+
205
+ namespace Language
206
+
207
+ protected theorem IsRegular.reverse {L : Language α} (h : L.IsRegular) : L.reverse.IsRegular :=
208
+ have ⟨σ, _, M, hM⟩ := h
209
+ ⟨_, inferInstance, M.toNFA.reverse.toDFA, by ext; simp [hM]⟩
210
+
211
+ protected theorem IsRegular.of_reverse {L : Language α} (h : L.reverse.IsRegular) : L.IsRegular :=
212
+ L.reverse_reverse ▸ h.reverse
213
+
214
+ /-- Regular languages are closed under reversal. -/
215
+ @[simp]
216
+ theorem isRegular_reverse_iff {L : Language α} : L.reverse.IsRegular ↔ L.IsRegular :=
217
+ ⟨.of_reverse, .reverse⟩
218
+
219
+ end Language
0 commit comments