nfa2dfa 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/state.rb CHANGED
@@ -1,67 +1,72 @@
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
1
+ require 'graphviz'
2
+ require_relative 'transition.rb'
3
+ # Part of Nfa2Dfa module
4
+ module Nfa2Dfa
5
+ # State of automaton
6
+ class State
7
+ attr_reader :id, :is_final, :graphviz_node, :is_starting
8
+
9
+ def initialize(id)
10
+ @id = id
11
+ @is_final = false
12
+ @transitions = []
13
+ @graphviz_init = false
14
+ @is_starting = false
15
+ end
16
+
17
+ def to_starting_node
18
+ @is_starting = true
19
+ end
20
+
21
+ def to_s
22
+ @id.to_s
23
+ end
24
+
25
+ def graph_id
26
+ is_starting ? (@id + '/init') : @id
27
+ end
28
+
29
+ def to_graph_node(viz_graph)
30
+ if @is_final
31
+ @graphviz_node = viz_graph.add_nodes(
32
+ graph_id, :shape => 'doublecircle')
33
+ else
34
+ @graphviz_node = viz_graph.add_nodes(graph_id, :shape => 'circle')
35
+ end
36
+ @graphviz_init = false
37
+ end
38
+
39
+ def finalize
40
+ @is_final = true
41
+ end
42
+
43
+ def add_transition(tr)
44
+ @transitions.insert(@transitions.size, tr)
45
+ end
46
+
47
+ def clear_transitions
48
+ @transitions.clear
49
+ end
50
+
51
+ def associate_transitions(all_transitions)
52
+ @transitions.clear
53
+ @id.split(',').each do |id_part|
54
+ all_transitions.each do |transition|
55
+ if id_part == transition.beginning_state.id
56
+ add_transition(transition)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def get_next(char)
63
+ ret_val = []
64
+ @transitions.each do |trans|
65
+ if trans.alphabet == char
66
+ ret_val.insert(ret_val.size, trans.ending_state)
67
+ end
68
+ end
69
+ ret_val
70
+ end
71
+ end
72
+ end
data/lib/transition.rb CHANGED
@@ -1,24 +1,31 @@
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
1
+ require 'graphviz'
2
+ require_relative 'state.rb'
3
+ # Part of Nfa2Dfa module
4
+ module Nfa2Dfa
5
+ # Transition between states
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(
18
+ @beginning_state.graphviz_node,
19
+ @ending_state.graphviz_node, :label => @alphabet)
20
+ end
21
+
22
+ def to_s
23
+ ret = @beginning_state.to_s + '-' + alphabet + '-' + @ending_state.to_s
24
+ ret
25
+ end
26
+
27
+ def print
28
+ puts @beginning_state.id + '-' + @alphabet + '-' + @ending_state.id
29
+ end
30
+ end
31
+ end
@@ -1,134 +1,139 @@
1
- require 'rspec'
2
- require 'spec_helper'
3
- require_relative '../lib/automaton.rb'
4
-
5
- describe Nfa2Dfa::Automaton do
6
- before(:each) do
7
- @file_path = "#{File.dirname(__FILE__)}/testdata/valid_input.automat"
8
- @file_path2 = "#{File.dirname(__FILE__)}/testdata/valid_input2.automat"
9
- @file_path3 = "#{File.dirname(__FILE__)}/testdata/valid_input3.automat"
10
- end
11
- context "initializes as" do
12
- it "valid automaton" do
13
- mat = Automaton.init(@file_path)
14
- mat.should_not eq NIL
15
- mat.class.should eq Nfa2Dfa::Automaton
16
- end
17
- it "invalid automaton, when there is invalid input" do
18
- mat = Automaton.init("#{File.dirname(__FILE__)}/testdata/invalid_input.automat")
19
- mat.should eq NIL
20
- end
21
- end
22
- it "should be exportable in same format by method 'to_str'" do
23
- valid_str = "z f\na b\nz-a-f f-b-f\nz\nf"
24
- mat = Automaton.init(@file_path)
25
- mat.to_str.should eq valid_str
26
- end
27
-
28
- context "accepts method resolves" do
29
- subject { Automaton.init(@file_path) }
30
- it "valid words" do
31
- (subject.accepts? "a b").should eq true
32
- (subject.accepts? "a").should eq true
33
- (subject.accepts? "a b b b").should eq true
34
- (subject.accepts? "a b b").should eq true
35
- end
36
-
37
- it "invalid words" do
38
- (subject.accepts? "").should eq false
39
- (subject.accepts? "a a").should eq false
40
- (subject.accepts? "a a ").should eq false
41
- (subject.accepts? "a b a").should eq false
42
- end
43
- end
44
-
45
- it "should be able to check if automat is deterministic" do
46
- Automaton.init(@file_path).deterministic?.should eq true
47
- Automaton.init(@file_path2).deterministic?.should eq false
48
- end
49
-
50
- context "can create deterministic automaton" do
51
- it "returns Automaton class" do
52
- mat1 = Automaton.init(@file_path)
53
- mat2 = Automaton.init(@file_path2)
54
- mat3 = Automaton.init(@file_path3)
55
- mat1.determine.class.should eq Nfa2Dfa::Automaton
56
- mat2.determine.class.should eq Nfa2Dfa::Automaton
57
- mat3.determine.class.should eq Nfa2Dfa::Automaton
58
- end
59
- it "returns same instance of Automaton when already deterministic" do
60
- mat1 = Automaton.init(@file_path)
61
- mat1det = mat1.determine
62
- mat1.should eq mat1det
63
- end
64
- it "returns deterministic automaton" do
65
- mat2 = Automaton.init(@file_path2)
66
- mat2det = mat2.determine
67
- mat2det.deterministic?.should eq true
68
- end
69
-
70
- it "which can accept same words" do
71
- mat2 = Automaton.init(@file_path2)
72
- mat2det = mat2.determine
73
- word = ""
74
- (mat2.accepts? word).should eq mat2det.accepts? word
75
- (mat2.accepts? word).should eq true
76
- word = "a a"
77
- (mat2.accepts? word).should eq mat2det.accepts? word
78
- (mat2.accepts? word).should eq true
79
- word = "a b"
80
- (mat2.accepts? word).should eq mat2det.accepts? word
81
- (mat2.accepts? word).should eq true
82
- word = "a c"
83
- (mat2.accepts? word).should eq mat2det.accepts? word
84
- (mat2.accepts? word).should eq true
85
- word = "a c c"
86
- (mat2.accepts? word).should eq mat2det.accepts? word
87
- (mat2.accepts? word).should eq true
88
- word = "a c c a"
89
- (mat2.accepts? word).should eq mat2det.accepts? word
90
- (mat2.accepts? word).should eq true
91
- word = "a c c a c a"
92
- (mat2.accepts? word).should eq mat2det.accepts? word
93
- (mat2.accepts? word).should eq true
94
- word = "a c c a c a a b"
95
- (mat2.accepts? word).should eq mat2det.accepts? word
96
- (mat2.accepts? word).should eq true
97
- word = "c a b c a b c"
98
- (mat2.accepts? word).should eq mat2det.accepts? word
99
- (mat2.accepts? word).should eq true
100
- word = "a c c b c"
101
- (mat2.accepts? word).should eq mat2det.accepts? word
102
- (mat2.accepts? word).should eq true
103
- end
104
-
105
- it "which rejects same words" do
106
- mat2 = Automaton.init(@file_path3)
107
- mat2det = mat2.determine
108
- word = "0"
109
- (mat2.accepts? word).should eq mat2det.accepts? word
110
- (mat2.accepts? word).should eq false
111
- word = "1"
112
- (mat2.accepts? word).should eq mat2det.accepts? word
113
- (mat2.accepts? word).should eq false
114
- word = "0 1"
115
- (mat2.accepts? word).should eq mat2det.accepts? word
116
- (mat2.accepts? word).should eq false
117
- word = "1 0"
118
- (mat2.accepts? word).should eq mat2det.accepts? word
119
- (mat2.accepts? word).should eq false
120
- word = "1 1 1 1 0"
121
- (mat2.accepts? word).should eq mat2det.accepts? word
122
- (mat2.accepts? word).should eq false
123
- word = "0 0 0 0 1"
124
- (mat2.accepts? word).should eq mat2det.accepts? word
125
- (mat2.accepts? word).should eq false
126
- end
127
-
128
- it "should have method for exporting as GraphViz 'to_graph'" do
129
- mat = Automaton.init(@file_path2)
130
- expect(mat.methods.include?(:to_graph)).to be true
131
- end
132
- end
133
- end
134
-
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+ require_relative '../lib/automaton.rb'
4
+
5
+ describe Nfa2Dfa::Automaton do
6
+ before(:each) do
7
+ @file_path = "#{File.dirname(__FILE__)}/testdata/valid_input.automat"
8
+ @file_path2 = "#{File.dirname(__FILE__)}/testdata/valid_input2.automat"
9
+ @file_path3 = "#{File.dirname(__FILE__)}/testdata/valid_input3.automat"
10
+ end
11
+
12
+ context 'initializes as' do
13
+ it 'valid automaton' do
14
+ mat = Automaton.init(@file_path)
15
+ mat.should_not eq NIL
16
+ mat.class.should eq Nfa2Dfa::Automaton
17
+ end
18
+
19
+ it 'invalid automaton, when there is invalid input' do
20
+ mat = Automaton.init("#{File.dirname(__FILE__)}" +
21
+ '/testdata/invalid_input.automat')
22
+ mat.should eq NIL
23
+ end
24
+ end
25
+
26
+ it 'should be exportable in same format by method \'to_str\'' do
27
+ valid_str = "z f\na b\nz-a-f f-b-f\nz\nf"
28
+ mat = Automaton.init(@file_path)
29
+ mat.to_str.should eq valid_str
30
+ end
31
+
32
+ context 'accepts method resolves' do
33
+ subject { Automaton.init(@file_path) }
34
+ it 'valid words' do
35
+ (subject.accepts? 'a b').should eq true
36
+ (subject.accepts? 'a').should eq true
37
+ (subject.accepts? 'a b b b').should eq true
38
+ (subject.accepts? 'a b b').should eq true
39
+ end
40
+
41
+ it 'invalid words' do
42
+ (subject.accepts? '').should eq false
43
+ (subject.accepts? 'a a').should eq false
44
+ (subject.accepts? 'a a ').should eq false
45
+ (subject.accepts? 'a b a').should eq false
46
+ end
47
+ end
48
+
49
+ it 'should be able to check if automat is deterministic' do
50
+ Automaton.init(@file_path).deterministic?.should eq true
51
+ Automaton.init(@file_path2).deterministic?.should eq false
52
+ end
53
+
54
+ context 'can create deterministic automaton' do
55
+ it 'returns Automaton class' do
56
+ mat1 = Automaton.init(@file_path)
57
+ mat2 = Automaton.init(@file_path2)
58
+ mat3 = Automaton.init(@file_path3)
59
+ mat1.determine.class.should eq Nfa2Dfa::Automaton
60
+ mat2.determine.class.should eq Nfa2Dfa::Automaton
61
+ mat3.determine.class.should eq Nfa2Dfa::Automaton
62
+ end
63
+
64
+ it 'returns same instance of Automaton when already deterministic' do
65
+ mat1 = Automaton.init(@file_path)
66
+ mat1det = mat1.determine
67
+ mat1.should eq mat1det
68
+ end
69
+
70
+ it 'returns deterministic automaton' do
71
+ mat2 = Automaton.init(@file_path2)
72
+ mat2det = mat2.determine
73
+ mat2det.deterministic?.should eq true
74
+ end
75
+
76
+ it 'which can accept same words' do
77
+ mat2 = Automaton.init(@file_path2)
78
+ mat2det = mat2.determine
79
+ word = ''
80
+ (mat2.accepts? word).should eq mat2det.accepts? word
81
+ (mat2.accepts? word).should eq true
82
+ word = 'a a'
83
+ (mat2.accepts? word).should eq mat2det.accepts? word
84
+ (mat2.accepts? word).should eq true
85
+ word = 'a b'
86
+ (mat2.accepts? word).should eq mat2det.accepts? word
87
+ (mat2.accepts? word).should eq true
88
+ word = 'a c'
89
+ (mat2.accepts? word).should eq mat2det.accepts? word
90
+ (mat2.accepts? word).should eq true
91
+ word = 'a c c'
92
+ (mat2.accepts? word).should eq mat2det.accepts? word
93
+ (mat2.accepts? word).should eq true
94
+ word = 'a c c a'
95
+ (mat2.accepts? word).should eq mat2det.accepts? word
96
+ (mat2.accepts? word).should eq true
97
+ word = 'a c c a c a'
98
+ (mat2.accepts? word).should eq mat2det.accepts? word
99
+ (mat2.accepts? word).should eq true
100
+ word = 'a c c a c a a b'
101
+ (mat2.accepts? word).should eq mat2det.accepts? word
102
+ (mat2.accepts? word).should eq true
103
+ word = 'c a b c a b c'
104
+ (mat2.accepts? word).should eq mat2det.accepts? word
105
+ (mat2.accepts? word).should eq true
106
+ word = 'a c c b c'
107
+ (mat2.accepts? word).should eq mat2det.accepts? word
108
+ (mat2.accepts? word).should eq true
109
+ end
110
+
111
+ it 'which rejects same words' do
112
+ mat2 = Automaton.init(@file_path3)
113
+ mat2det = mat2.determine
114
+ word = '0'
115
+ (mat2.accepts? word).should eq mat2det.accepts? word
116
+ (mat2.accepts? word).should eq false
117
+ word = '1'
118
+ (mat2.accepts? word).should eq mat2det.accepts? word
119
+ (mat2.accepts? word).should eq false
120
+ word = '0 1'
121
+ (mat2.accepts? word).should eq mat2det.accepts? word
122
+ (mat2.accepts? word).should eq false
123
+ word = '1 0'
124
+ (mat2.accepts? word).should eq mat2det.accepts? word
125
+ (mat2.accepts? word).should eq false
126
+ word = '1 1 1 1 0'
127
+ (mat2.accepts? word).should eq mat2det.accepts? word
128
+ (mat2.accepts? word).should eq false
129
+ word = '0 0 0 0 1'
130
+ (mat2.accepts? word).should eq mat2det.accepts? word
131
+ (mat2.accepts? word).should eq false
132
+ end
133
+
134
+ it 'should have method for exporting as GraphViz \'to_graph\'' do
135
+ mat = Automaton.init(@file_path2)
136
+ expect(mat.methods.include?(:to_graph)).to be true
137
+ end
138
+ end
139
+ end