Source file state_elimination.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
open Strong.Finite
module type Regex = sig
type t
val epsilon : t
val (^.) : t -> t -> t
val (|.) : t -> t -> t
val star : t -> t
end
module type NFA = sig
module States : Strong.Natural.T
module Transitions : Strong.Natural.T
type label
val label : Transitions.n elt -> label
val source : Transitions.n elt -> States.n elt
val target : Transitions.n elt -> States.n elt
module Initials : Array.T with type a = States.n elt
module Finals : Array.T with type a = States.n elt
end
module Convert
(Regex : Regex) (NFA: NFA with type label := Regex.t) :
sig
val result : (NFA.Initials.n, (NFA.Finals.n elt * Regex.t list) list) Array.t
end =
struct
type temp =
| Unused
| Label of Regex.t
| Final of { index: NFA.Finals.n elt; mutable regexes : Regex.t list }
type state = {
mutable preds: (state * Regex.t) list;
mutable succs: (state * Regex.t) list;
mutable temp: temp;
}
let is_alive = function {preds = []; succs = []; _} -> false | _ -> true
let state_counter = ref 0
let make_state () = incr state_counter;
{ preds = []; succs = []; temp = Unused }
let states : (NFA.States.n, state) Array.t =
Array.init NFA.States.n (fun _ -> make_state ())
let update_list state label = function
| (state', label') :: rest when state == state' ->
(state', Regex.(|.) label label') :: rest
| otherwise -> (state, label) :: otherwise
let link source target label = (
source.succs <- update_list target label source.succs;
target.preds <- update_list source label target.preds;
)
let () = Set.iter NFA.Transitions.n (fun transition ->
link
states.(NFA.source transition)
states.(NFA.target transition)
(NFA.label transition)
)
let initials =
let prepare_initial nfa_state =
let state = make_state () in
link state states.(nfa_state) Regex.epsilon;
state
in
Array.map prepare_initial NFA.Initials.table
let finals =
let prepare_final nfa_state =
let state = make_state () in
link states.(nfa_state) state Regex.epsilon;
state
in
Array.map prepare_final NFA.Finals.table
let normalize_transitions transitions =
let to_temp transitions =
assert (List.for_all (fun (state, _) -> state.temp = Unused) transitions);
List.iter (fun (state, label) ->
if is_alive state then (
match state.temp with
| Unused -> state.temp <- Label label
| Label label' -> state.temp <- Label (Regex.(|.) label label')
| Final _ -> assert false
)
) transitions
in
let extract_temp (state, _) =
match state.temp with
| Unused -> None
| Label label -> state.temp <- Unused; Some (state, label)
| Final _ -> assert false
in
to_temp transitions;
List.filter_map extract_temp transitions
let eliminate state =
decr state_counter;
let preds = state.preds and succs = state.succs in
state.succs <- [];
state.preds <- [];
let stars =
List.fold_left
(fun acc (succ, label) ->
if succ == state then Regex.(|.) label acc else acc)
Regex.epsilon
succs
in
let preds = normalize_transitions preds in
let succs = normalize_transitions succs in
let stars =
if stars == Regex.epsilon
then Regex.epsilon
else Regex.star stars
in
List.iter (fun (succ, label_succ) ->
List.iter (fun (pred, label_pred) ->
let label = Regex.(
if stars == epsilon
then label_pred ^. stars ^. label_succ
else label_pred ^. label_succ
)
in
link pred succ label;
) preds
) succs
let () = Array.iter eliminate states
let result =
let normalize_initial initial = normalize_transitions initial.succs in
let normalized = Array.map normalize_initial initials in
let tag_final index state = state.temp <- Final {index; regexes = []} in
Array.iteri tag_final finals;
let non_null = ref [] in
let prepare_transition (state, regex) =
match state.temp with
| Final t ->
if t.regexes = [] then non_null := state.temp :: !non_null;
t.regexes <- regex :: t.regexes
| _ -> assert false
in
let flush_final = function
| Final t ->
let result = t.index, t.regexes in
t.regexes <- [];
result
| _ -> assert false
in
let prepare_initial transitions =
List.iter prepare_transition transitions;
let result = List.map flush_final !non_null in
non_null := [];
result
in
Array.map prepare_initial normalized
end
let convert
(type regex initials finals)
(module Regex : Regex with type t = regex)
(module NFA : NFA with type label = regex
and type Initials.n = initials
and type Finals.n = finals)
: (initials, (finals elt * regex list) list) Array.t
=
let module Result = Convert(Regex)(NFA) in
Result.result