nfa2dfa 1.0.2

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