NFA-to-DFA 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/lib/automaton.rb +310 -0
  3. data/lib/state.rb +65 -0
  4. data/lib/transition.rb +22 -0
  5. metadata +46 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dfd6b44cf52809252cbc5a8657bbeedd881febd4
4
+ data.tar.gz: c97a3151f4c9b8f79c1ece3a5a323ba3b7a1167f
5
+ SHA512:
6
+ metadata.gz: d503c1d3b97952d578abb318ed435914e2eef4866811321c076c5ef3a80a87155a07db13ce6966fb5e58bba8c8d356f19124745915a44bd6bedfc93f7554af10
7
+ data.tar.gz: a51012d5dec578b58a4a66e0dea5ca4ca7bfc1f4253ba110cb25e2e032e361de8c5b48f9ca2bbb458446dc24d2693687dd3ff67ce397ad3c04d3ae56f9f8097e
@@ -0,0 +1,310 @@
1
+ #z f - mnozina stavu
2
+ #a b - vstupni abeceda
3
+ #z-a-f f-b-f - prechod Q-T-Q ze stavu Q pres pismeno T do stavu Q
4
+ #z - Pocatecni stav
5
+ #f - mnozina koncovych stavu
6
+
7
+ require 'graphviz'
8
+ require_relative 'state.rb'
9
+ require_relative 'transition.rb'
10
+ class Automaton
11
+
12
+ public
13
+
14
+ def to_str
15
+ ret_val = ""
16
+ str = ""
17
+ @states.each do |state|
18
+ str += state.id + " "
19
+ end
20
+ ret_val += str.byteslice(0, str.length-1) + "\n"
21
+ str = ""
22
+ @alphabet.each do |a|
23
+ str+= a + " "
24
+ end
25
+ ret_val += str.byteslice(0, str.length-1) + "\n"
26
+ str = ""
27
+ @transitions.each do |trans|
28
+ str += trans.beginning_state.id + "-" + trans.alphabet + "-" + trans.ending_state.id + " "
29
+ end
30
+ ret_val += str.byteslice(0, str.length-1) + "\n"
31
+ str = ""
32
+ ret_val += @starting_state.id + "\n"
33
+ @states.each do |state|
34
+ if state.is_final == true
35
+ str += state.id + " "
36
+ end
37
+ end
38
+ ret_val += str.byteslice(0, str.length-1)
39
+ ret_val
40
+ end
41
+
42
+ def to_graph(path)
43
+ g = GraphViz.new( :G, :type => :digraph)
44
+ @states.each do |state|
45
+ #puts state.id
46
+ state.to_graph_node(g)
47
+ end
48
+ g.each_node() do |name, node|
49
+ # puts name
50
+ end
51
+ @transitions.each do |trans|
52
+ trans.to_graph_transition(g)
53
+ end
54
+ g.each_edge do |ed|
55
+ #puts ed.node_one + " " + ed.node_two
56
+ end
57
+ g.output( :png => path )
58
+ end
59
+
60
+ def self.init(path)
61
+ #nacteni ze souboru
62
+ if File.file?(path)
63
+ data_arr = Array.new
64
+ index = 0
65
+ File.open(path).each_line do |line|
66
+ data_arr[index] = line
67
+ index = index + 1
68
+ end
69
+ if validate(data_arr)
70
+ get_valid_input(data_arr)
71
+ else
72
+ puts "Invalid input"
73
+ NIL
74
+ end
75
+ else
76
+ puts "Invalid input"
77
+ NIL
78
+ end
79
+ end
80
+
81
+ def self.validate(data_arr)
82
+ parsed = []
83
+ data_arr.each do |item|
84
+ parsed.push item.split(' ')
85
+ end
86
+ validate_transitions(parsed[0], parsed[1], parsed[2]) && validate_states(parsed[0], parsed[3], parsed[4])
87
+ end
88
+
89
+ #format: pismeno<mezera>pismeno...
90
+ def accepts?(data)
91
+ formatted_input = data.split(' ')
92
+ @stack = Array.new
93
+ @stack.push(@starting_state)
94
+ formatted_input.size == 0 ? @starting_state.is_final : recurs_accepts?(formatted_input, 0)
95
+ end
96
+
97
+ def deterministic?
98
+ @states.each do |state|
99
+ @alphabet.each do |char|
100
+ if state.get_next(char).size > 1
101
+ return false
102
+ end
103
+ end
104
+ end
105
+ true
106
+ end
107
+
108
+ def determine
109
+ deterministic? ? self : determine_prot
110
+ end
111
+
112
+ protected
113
+
114
+ attr_accessor :states, :alphabet, :transitions, :starting_state, :stack
115
+
116
+ def recurs_accepts?(data, index)
117
+ ret_val = false
118
+ if @stack.size != 0
119
+ cnt = resolve_state_on_stack(data[index])
120
+ index = index + 1
121
+ if index == data.size
122
+ cnt.times do
123
+ if @stack.pop.is_final
124
+ ret_val = true
125
+ end
126
+ end
127
+ else
128
+ return recurs_accepts?(data,index)
129
+ end
130
+ end
131
+ ret_val
132
+ end
133
+
134
+ def self.get_valid_input(data_arr)
135
+ states = Array.new
136
+ fin = data_arr[4].split(' ')
137
+
138
+ data_arr[0].split(' ').each do |wrd|
139
+ states.push State.new(wrd)
140
+ end
141
+ fin.include?(states[0].id)
142
+ states.each do |st|
143
+ (fin.include? st.id) ? st.finalize : NIL
144
+ end
145
+ alphabet = Array.new
146
+ data_arr[1].split(' ').each do |wrd|
147
+ alphabet.insert(alphabet.size, wrd)
148
+ end
149
+ transitions = Array.new
150
+ data_arr[2].split(' ').each do |wrd|
151
+ trans = wrd.split('-')
152
+ state1 = NIL
153
+ state2 = NIL
154
+ states.each do |item|
155
+ trans[0] == item.id ? state1 = item : NIL
156
+ trans[2] == item.id ? state2 = item : NIL
157
+ state1 != NIL && state2 != NIL ? break : NIL
158
+ end
159
+ transitions.insert(transitions.size, Transition.new(state1, trans[1], state2))
160
+ state1.add_transition(transitions[transitions.size-1])
161
+ end
162
+ starting = NIL
163
+ states.each do |item2|
164
+ if item2.id == data_arr[3].split(' ')[0]
165
+ starting = item2
166
+ item2.to_starting_node
167
+ break
168
+ end
169
+ end
170
+ Automaton.new(states, alphabet, transitions, starting)
171
+ end
172
+
173
+ def determine_prot
174
+ #https://edux.fit.cvut.cz/courses/BI-AAG/_media/lectures/03/bi-aag-03-operace_s_automaty-4.pdf
175
+ undetermined_states = Array.new
176
+ determined_states = Array.new
177
+ transits = Array.new
178
+ tot_transits = Array.new
179
+ curr_states = Array.new
180
+ undetermined_states[0] = @starting_state.clone
181
+ new_begin_state = undetermined_states[0]
182
+ while(undetermined_states.size > 0)
183
+ temp_state = undetermined_states[0]
184
+ curr_states.clear
185
+ transits.clear
186
+ @alphabet.each do |char|
187
+ t_states_by_char = temp_state.get_next(char)
188
+ if t_states_by_char.size > 0
189
+ state_id = merge_state_names(t_states_by_char)
190
+ state = find_state(state_id, determined_states, undetermined_states)
191
+ if state
192
+ transits.push(Transition.new(temp_state, char, state))
193
+ tot_transits.push(Transition.new(temp_state, char, state))
194
+ else
195
+ #Tvorba noveho statu
196
+ state = State.new(state_id)
197
+ state.associate_transitions(@transitions)
198
+ undetermined_states.push(state)
199
+ transits.push(Transition.new(temp_state, char, state))
200
+ tot_transits.push(Transition.new(temp_state, char, state))
201
+ end
202
+ end
203
+ end
204
+ temp_state.clear_transitions
205
+ transits.each do |transit|
206
+ temp_state.add_transition(transit)
207
+ end
208
+ undetermined_states.delete(temp_state)
209
+ determined_states.push(temp_state)
210
+ end
211
+
212
+ determined_states
213
+ @alphabet
214
+ tot_transits
215
+ new_begin_state
216
+ finals = associate_finals(determined_states)
217
+ Automaton.new(determined_states, @alphabet.clone, tot_transits, new_begin_state)
218
+ end
219
+
220
+ private
221
+
222
+ def associate_finals(stat)
223
+ ret_val = Array.new
224
+ @states.each do |orig|
225
+ if orig.is_final
226
+ stat.each do |state|
227
+ state.id.split(',').each do |id|
228
+ if id == orig.id
229
+ state.finalize
230
+ ret_val.push(state)
231
+ break 2
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
237
+ ret_val
238
+ end
239
+
240
+ def find_state(state_id, container, container2)
241
+ str = ""
242
+ state_id.split(' ').sort.each do |st|
243
+ str += st
244
+ end
245
+ # state_id = str.slice(0, str.size - 2)
246
+ container.each do |state|
247
+ if state.id == state_id
248
+ return state
249
+ end
250
+ end
251
+ container2.each do |state|
252
+ if state.id == state_id
253
+ return state
254
+ end
255
+ end
256
+ NIL
257
+ end
258
+
259
+ def merge_state_names(states)
260
+ arr = Array.new
261
+ states.each do |state|
262
+ arr.push(state.id)
263
+ end
264
+ arr = arr.uniq.sort
265
+ last = arr.pop
266
+ str = ""
267
+ arr.each do |id|
268
+ str += id + ","
269
+ end
270
+ str += last
271
+ str
272
+ end
273
+
274
+ def resolve_state_on_stack(char)
275
+ popped = @stack.pop
276
+ arr = popped.get_next(char)
277
+ arr.each do |item|
278
+ @stack.push(item)
279
+ end
280
+ arr.size
281
+ end
282
+
283
+ def initialize(stat_arr, alph_arr, trans_arr, start)
284
+ @states = stat_arr
285
+ @alphabet = alph_arr
286
+ @transitions = trans_arr
287
+ @starting_state = start
288
+ end
289
+
290
+ def self.validate_states(states, start, final)
291
+ if states.include? start[0]
292
+ final.each do |fin|
293
+ if !(states.include? fin)
294
+ return false
295
+ end
296
+ return true
297
+ end
298
+ return false
299
+ end
300
+ return false
301
+ end
302
+
303
+ def self.validate_transitions(states, alphabet, transitions)
304
+ transitions.each do |tr|
305
+ trans = tr.split('-')
306
+ ((states.include? trans[0]) && (states.include? trans[2]) && (alphabet.include? trans[1])) ? NIL : (return false)
307
+ end
308
+ true
309
+ end
310
+ end
@@ -0,0 +1,65 @@
1
+ # To change this template, choose Tools | Templates
2
+ # and open the template in the editor.
3
+
4
+ require 'graphviz'
5
+ require_relative 'transition.rb'
6
+
7
+ class State
8
+ attr_reader :id, :is_final, :graphviz_node, :is_starting
9
+
10
+ def initialize(id)
11
+ @id = id
12
+ @is_final = false
13
+ @transitions = Array.new
14
+ @graphviz_init = false
15
+ @is_starting = false
16
+ end
17
+
18
+ def to_starting_node
19
+ @is_starting = true
20
+ end
21
+
22
+ def graph_id
23
+ is_starting ? (@id + "/init") : @id
24
+ end
25
+
26
+ def to_graph_node(graphviz_graph)
27
+ if @is_final
28
+ @graphviz_node = graphviz_graph.add_nodes(graph_id, :shape => "doublecircle")
29
+ else
30
+ @graphviz_node = graphviz_graph.add_nodes(graph_id, :shape => "circle")
31
+ end
32
+ @graphviz_init = false
33
+ end
34
+
35
+ def finalize
36
+ @is_final = true
37
+ end
38
+
39
+ def add_transition(tr)
40
+ @transitions.insert(@transitions.size, tr)
41
+ end
42
+
43
+ def clear_transitions
44
+ @transitions.clear
45
+ end
46
+
47
+ def associate_transitions(all_transitions)
48
+ @transitions.clear
49
+ @id.split(',').each do |id_part|
50
+ all_transitions.each do |transition|
51
+ if id_part == transition.beginning_state.id
52
+ add_transition(transition)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ def get_next(char)
59
+ ret_val = Array.new
60
+ @transitions.each do |trans|
61
+ trans.alphabet == char ? ret_val.insert(ret_val.size, trans.ending_state) : NIL
62
+ end
63
+ ret_val
64
+ end
65
+ end
@@ -0,0 +1,22 @@
1
+
2
+ require 'graphviz'
3
+ require_relative 'state.rb'
4
+
5
+ class Transition
6
+
7
+ attr_reader :beginning_state, :alphabet, :ending_state
8
+
9
+ def initialize(beg_state, alphabet, end_state)
10
+ @beginning_state = beg_state
11
+ @alphabet = alphabet
12
+ @ending_state = end_state
13
+ end
14
+
15
+ def to_graph_transition(graphviz_graph)
16
+ graphviz_graph.add_edges( @beginning_state.graphviz_node, @ending_state.graphviz_node, :label => @alphabet)
17
+ end
18
+
19
+ def print
20
+ puts @beginning_state.id + "-" + @alphabet + "-" + @ending_state.id
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: NFA-to-DFA
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin Zachov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-15 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Finite automaton determinizer
14
+ email: nick@quaran.to
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/state.rb
20
+ - lib/automaton.rb
21
+ - lib/transition.rb
22
+ homepage: http://fit.cvut.cz
23
+ licenses:
24
+ - GNU GPL
25
+ metadata: {}
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubyforge_project:
42
+ rubygems_version: 2.0.3
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: Hola!
46
+ test_files: []