NFA-to-DFA 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []