nfa2dfa 1.0.2

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.
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: []