stamina 0.3.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.
- data/.gemtest +0 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +33 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +16 -0
- data/README.md +78 -0
- data/Rakefile +23 -0
- data/bin/adl2dot +12 -0
- data/bin/classify +12 -0
- data/bin/redblue +12 -0
- data/bin/rpni +12 -0
- data/example/adl/automaton.adl +49 -0
- data/example/adl/sample.adl +53 -0
- data/example/basic/characteristic_sample.adl +32 -0
- data/example/basic/target.adl +9 -0
- data/example/competition/31_test.adl +1500 -0
- data/example/competition/31_training.adl +1759 -0
- data/lib/stamina.rb +19 -0
- data/lib/stamina/adl.rb +298 -0
- data/lib/stamina/automaton.rb +1237 -0
- data/lib/stamina/automaton/walking.rb +336 -0
- data/lib/stamina/classifier.rb +37 -0
- data/lib/stamina/command/adl2dot_command.rb +73 -0
- data/lib/stamina/command/classify_command.rb +57 -0
- data/lib/stamina/command/redblue_command.rb +58 -0
- data/lib/stamina/command/rpni_command.rb +58 -0
- data/lib/stamina/command/stamina_command.rb +79 -0
- data/lib/stamina/errors.rb +20 -0
- data/lib/stamina/induction/commons.rb +170 -0
- data/lib/stamina/induction/redblue.rb +264 -0
- data/lib/stamina/induction/rpni.rb +188 -0
- data/lib/stamina/induction/union_find.rb +377 -0
- data/lib/stamina/input_string.rb +123 -0
- data/lib/stamina/loader.rb +0 -0
- data/lib/stamina/markable.rb +42 -0
- data/lib/stamina/sample.rb +190 -0
- data/lib/stamina/version.rb +14 -0
- data/stamina.gemspec +190 -0
- data/stamina.noespec +35 -0
- data/tasks/debug_mail.rake +78 -0
- data/tasks/debug_mail.txt +13 -0
- data/tasks/gem.rake +68 -0
- data/tasks/spec_test.rake +79 -0
- data/tasks/unit_test.rake +77 -0
- data/tasks/yard.rake +51 -0
- data/test/stamina/adl_test.rb +491 -0
- data/test/stamina/automaton_additional_test.rb +190 -0
- data/test/stamina/automaton_classifier_test.rb +155 -0
- data/test/stamina/automaton_test.rb +1092 -0
- data/test/stamina/automaton_to_dot_test.rb +64 -0
- data/test/stamina/automaton_walking_test.rb +206 -0
- data/test/stamina/exit.rb +3 -0
- data/test/stamina/induction/induction_test.rb +70 -0
- data/test/stamina/induction/redblue_mergesamestatebug_expected.adl +19 -0
- data/test/stamina/induction/redblue_mergesamestatebug_pta.dot +64 -0
- data/test/stamina/induction/redblue_mergesamestatebug_sample.adl +9 -0
- data/test/stamina/induction/redblue_test.rb +83 -0
- data/test/stamina/induction/redblue_universal_expected.adl +4 -0
- data/test/stamina/induction/redblue_universal_sample.adl +5 -0
- data/test/stamina/induction/rpni_inria_expected.adl +7 -0
- data/test/stamina/induction/rpni_inria_sample.adl +9 -0
- data/test/stamina/induction/rpni_test.rb +129 -0
- data/test/stamina/induction/rpni_test_pta.dot +22 -0
- data/test/stamina/induction/rpni_universal_expected.adl +4 -0
- data/test/stamina/induction/rpni_universal_sample.adl +4 -0
- data/test/stamina/induction/union_find_test.rb +124 -0
- data/test/stamina/input_string_test.rb +323 -0
- data/test/stamina/markable_test.rb +70 -0
- data/test/stamina/randdfa.adl +66 -0
- data/test/stamina/sample.adl +4 -0
- data/test/stamina/sample_classify_test.rb +149 -0
- data/test/stamina/sample_test.rb +218 -0
- data/test/stamina/small_dfa.dot +16 -0
- data/test/stamina/small_dfa.gif +0 -0
- data/test/stamina/small_nfa.dot +18 -0
- data/test/stamina/small_nfa.gif +0 -0
- data/test/stamina/stamina_test.rb +69 -0
- data/test/test_all.rb +7 -0
- metadata +279 -0
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'stamina'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
module Stamina
|
5
|
+
class AutomataOperationsTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@dfa = ADL::parse_automaton <<-AUTOMATON
|
9
|
+
3 4
|
10
|
+
A true false
|
11
|
+
B false false
|
12
|
+
C false true
|
13
|
+
A B a
|
14
|
+
B C b
|
15
|
+
C C a
|
16
|
+
C B b
|
17
|
+
AUTOMATON
|
18
|
+
|
19
|
+
@another = ADL::parse_automaton <<-AUTOMATON
|
20
|
+
3 3
|
21
|
+
A true true
|
22
|
+
B false false
|
23
|
+
C false true
|
24
|
+
A B a
|
25
|
+
B C a
|
26
|
+
C C a
|
27
|
+
AUTOMATON
|
28
|
+
|
29
|
+
@small = ADL::parse_automaton <<-AUTOMATON
|
30
|
+
1 1
|
31
|
+
S true true
|
32
|
+
S S a
|
33
|
+
AUTOMATON
|
34
|
+
end
|
35
|
+
|
36
|
+
# With names of new states thrown away
|
37
|
+
def test_add_states1a
|
38
|
+
assert_equal(false, @dfa.accepts?('?'))
|
39
|
+
small_init = @dfa.add_automaton(@small)
|
40
|
+
@dfa.connect(@dfa.initial_state,small_init,'c')
|
41
|
+
|
42
|
+
assert_equal(4, @dfa.state_count)
|
43
|
+
assert_equal(6, @dfa.edge_count)
|
44
|
+
|
45
|
+
check_dfa_unchanged(@dfa)
|
46
|
+
assert_equal(true, @dfa.accepts?('? c'))
|
47
|
+
assert_equal(true, @dfa.accepts?('? c a a a'))
|
48
|
+
assert_equal(false, @dfa.accepts?('? c a a b a'))
|
49
|
+
|
50
|
+
assert_raise ArgumentError do
|
51
|
+
@dfa.get_state('S') # non-existing state
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
# Checks that the supplied automaton matches @dfa
|
57
|
+
def check_dfa_unchanged(automaton)
|
58
|
+
assert_equal(false, automaton.accepts?('?'))
|
59
|
+
assert_equal(false, automaton.accepts?('? a'))
|
60
|
+
assert_equal(false, automaton.accepts?('? a c'))
|
61
|
+
assert_equal(true, automaton.accepts?('? a b'))
|
62
|
+
assert_equal(true, automaton.accepts?('? a b a'))
|
63
|
+
assert_equal(false, automaton.accepts?('? a b a b'))
|
64
|
+
assert_equal(true, automaton.accepts?('? a b a b b'))
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_add_states1b
|
68
|
+
another_init = @dfa.add_automaton(@another)
|
69
|
+
|
70
|
+
@dfa.connect(@dfa.initial_state,another_init,'c')
|
71
|
+
|
72
|
+
assert_equal(6, @dfa.state_count)
|
73
|
+
assert_equal(8, @dfa.edge_count)
|
74
|
+
|
75
|
+
check_dfa_unchanged(@dfa)
|
76
|
+
assert_equal(true, @dfa.accepts?('? c'))
|
77
|
+
assert_equal(false, @dfa.accepts?('? c a'))
|
78
|
+
assert_equal(true, @dfa.accepts?('? c a a a'))
|
79
|
+
assert_equal(false, @dfa.accepts?('? c a a b a'))
|
80
|
+
end
|
81
|
+
|
82
|
+
# Without throwing away names of new states
|
83
|
+
def test_add_states2
|
84
|
+
small_init = @dfa.add_automaton(@small,false)
|
85
|
+
@dfa.connect(@dfa.initial_state,small_init,'c')
|
86
|
+
|
87
|
+
assert_equal(4, @dfa.state_count)
|
88
|
+
assert_equal(6, @dfa.edge_count)
|
89
|
+
|
90
|
+
@dfa.get_state('S') # this one should exist
|
91
|
+
end
|
92
|
+
|
93
|
+
# Testing with an empty automaton
|
94
|
+
|
95
|
+
def create_empty_automaton
|
96
|
+
empty = ADL::parse_automaton <<-AUTOMATON
|
97
|
+
1 0
|
98
|
+
B true true
|
99
|
+
AUTOMATON
|
100
|
+
empty.drop_state(empty.get_state("B"))
|
101
|
+
empty
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_add_states4a
|
105
|
+
empty = create_empty_automaton
|
106
|
+
empty.add_automaton(empty,false)
|
107
|
+
|
108
|
+
assert_equal(0, empty.state_count)
|
109
|
+
assert_equal(0, empty.edge_count)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_add_states4b
|
113
|
+
empty = create_empty_automaton
|
114
|
+
empty.add_automaton(empty,true)
|
115
|
+
|
116
|
+
assert_equal(0, empty.state_count)
|
117
|
+
assert_equal(0, empty.edge_count)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_add_states5
|
121
|
+
@dfa.add_automaton(create_empty_automaton,false)
|
122
|
+
assert_equal(3, @dfa.state_count);assert_equal(4, @dfa.edge_count);check_dfa_unchanged(@dfa)
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_add_states6
|
126
|
+
empty = create_empty_automaton
|
127
|
+
initial=empty.add_automaton(@dfa, true)
|
128
|
+
initial.initial!
|
129
|
+
assert_equal(3, empty.state_count);assert_equal(4, empty.edge_count);check_dfa_unchanged(empty)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_dup_1
|
133
|
+
empty = create_empty_automaton
|
134
|
+
anotherEmpty = empty.dup
|
135
|
+
|
136
|
+
anotherEmpty.add_state(:accepting => true)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Tests that adding states/transitions actually copies them
|
140
|
+
def test_add_states_really_copies
|
141
|
+
outAOrig_edge1 = @dfa.initial_state.out_edges.select { |e| e.symbol == 'a'}[0]
|
142
|
+
outAOrig_edge2 = outAOrig_edge1.to.out_edges.select { |e| e.symbol == 'a'}[0]
|
143
|
+
outAN_edge1 = @another.initial_state.out_edges.select { |e| e.symbol == 'a'}[0]
|
144
|
+
outAN_edge2 = outAN_edge1.to.out_edges.select { |e| e.symbol == 'a'}[0]
|
145
|
+
|
146
|
+
stateAO_O = @dfa.initial_state
|
147
|
+
stateAO_1 = @dfa.step(nil,'a')[0]
|
148
|
+
|
149
|
+
stateAN_O = @another.initial_state
|
150
|
+
stateAN_1 = @another.step(nil,'a')[0]
|
151
|
+
|
152
|
+
another_init = @dfa.add_automaton(@another)
|
153
|
+
|
154
|
+
@dfa.connect(@dfa.initial_state,another_init,'c')
|
155
|
+
|
156
|
+
assert_equal(6, @dfa.state_count)
|
157
|
+
assert_equal(8, @dfa.edge_count)
|
158
|
+
|
159
|
+
check_dfa_unchanged(@dfa)
|
160
|
+
assert_equal(true, @dfa.accepts?('? c'))
|
161
|
+
|
162
|
+
|
163
|
+
outA_edge1 = @dfa.initial_state.out_edges.select { |e| e.symbol == 'a'}[0]
|
164
|
+
outA_edge2 = outA_edge1.to.out_edges.select { |e| e.symbol == 'a'}[0]
|
165
|
+
|
166
|
+
stateA_O = @dfa.initial_state
|
167
|
+
stateA_1 = @dfa.step(nil,'a')[0]
|
168
|
+
|
169
|
+
outB_edge1 = another_init.out_edges.select { |e| e.symbol == 'a'}[0]
|
170
|
+
outB_edge2 = outB_edge1.to.out_edges.select { |e| e.symbol == 'a'}[0]
|
171
|
+
|
172
|
+
stateB_O = another_init
|
173
|
+
stateB_1 = another_init.step('a')[0]
|
174
|
+
|
175
|
+
assert_same stateAO_O,stateA_O
|
176
|
+
assert_same stateAO_1,stateA_1
|
177
|
+
assert_not_same stateAN_O,stateB_O
|
178
|
+
assert_not_same stateAN_1,stateB_1
|
179
|
+
|
180
|
+
assert_same outAOrig_edge1, outA_edge1
|
181
|
+
assert_same outAOrig_edge2, outA_edge2
|
182
|
+
assert_not_same outB_edge1, outAN_edge1
|
183
|
+
assert_not_same outB_edge2, outAN_edge2
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
|
188
|
+
end # class AutomataOperationsTest
|
189
|
+
end # module Stamina
|
190
|
+
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stamina/adl'
|
3
|
+
require 'stamina/stamina_test'
|
4
|
+
module Stamina
|
5
|
+
class Automaton
|
6
|
+
# Tests Classifier module, as to be installed on Automaton.
|
7
|
+
class ClassifierTest < StaminaTest
|
8
|
+
|
9
|
+
# Tests Classify#correctly_classified_by? is correct on valid sample against
|
10
|
+
# small_dfa example
|
11
|
+
def test_valid_sample_correctly_satified_by_small_dfa
|
12
|
+
assert_equal(true, @small_dfa.correctly_classify?(Sample.new))
|
13
|
+
sample = ADL::parse_sample <<-SAMPLE
|
14
|
+
-
|
15
|
+
+ b
|
16
|
+
+ b c
|
17
|
+
- b c a
|
18
|
+
- b c a c
|
19
|
+
- b c a c a
|
20
|
+
- b c a a
|
21
|
+
+ b c a b
|
22
|
+
+ b c a b c a c b
|
23
|
+
- z
|
24
|
+
- b z
|
25
|
+
SAMPLE
|
26
|
+
assert_equal '01100001100', sample.signature
|
27
|
+
assert_equal(true, @small_dfa.correctly_classify?(sample))
|
28
|
+
assert_equal sample.signature, @small_dfa.signature(sample)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Tests Classify#correctly_classified_by? is correct on invalid sample against
|
32
|
+
# small_dfa example
|
33
|
+
def test_invalid_sample_correctly_classified_by_small_dfa
|
34
|
+
sample = ADL::parse_sample <<-SAMPLE
|
35
|
+
-
|
36
|
+
+ b
|
37
|
+
+ b c
|
38
|
+
- b c a
|
39
|
+
# this one is reversed
|
40
|
+
+ b c a c
|
41
|
+
- b c a c a
|
42
|
+
- b c a a
|
43
|
+
+ b c a b
|
44
|
+
+ b c a b c a c b
|
45
|
+
- z
|
46
|
+
- b z
|
47
|
+
SAMPLE
|
48
|
+
assert_equal(false, @small_dfa.correctly_classify?(sample))
|
49
|
+
assert_equal '01100001100', @small_dfa.signature(sample)
|
50
|
+
|
51
|
+
sample = ADL::parse_sample <<-SAMPLE
|
52
|
+
-
|
53
|
+
+ b
|
54
|
+
+ b c
|
55
|
+
- b c a
|
56
|
+
- b c a c
|
57
|
+
- b c a c a
|
58
|
+
- b c a a
|
59
|
+
+ b c a b
|
60
|
+
+ b c a b c a c b
|
61
|
+
# this one is changed
|
62
|
+
+ z
|
63
|
+
- b z
|
64
|
+
SAMPLE
|
65
|
+
assert_equal(false, @small_dfa.correctly_classify?(sample))
|
66
|
+
assert_equal '01100001100', @small_dfa.signature(sample)
|
67
|
+
|
68
|
+
sample = ADL::parse_sample <<-SAMPLE
|
69
|
+
-
|
70
|
+
+ b
|
71
|
+
+ b c
|
72
|
+
- b c a
|
73
|
+
- b c a c
|
74
|
+
- b c a c a
|
75
|
+
- b c a a
|
76
|
+
+ b c a b
|
77
|
+
# this one is changed
|
78
|
+
- b c a b c a c b
|
79
|
+
- z
|
80
|
+
- b z
|
81
|
+
SAMPLE
|
82
|
+
assert_equal(false, @small_dfa.correctly_classify?(sample))
|
83
|
+
assert_equal '01100001100', @small_dfa.signature(sample)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Tests Classify#correctly_classify? is correct on valid sample against
|
87
|
+
# small_nfa example
|
88
|
+
def test_valid_sample_correctly_satified_by_small_nfa
|
89
|
+
assert_equal(true, @small_nfa.correctly_classify?(Sample.new))
|
90
|
+
sample = ADL::parse_sample <<-SAMPLE
|
91
|
+
+
|
92
|
+
+ a
|
93
|
+
- a a
|
94
|
+
+ a a b
|
95
|
+
+ a b
|
96
|
+
+ a b c a
|
97
|
+
- a b c
|
98
|
+
+ a b b b b b b
|
99
|
+
- a z
|
100
|
+
- z
|
101
|
+
SAMPLE
|
102
|
+
assert_equal(true, @small_nfa.correctly_classify?(sample))
|
103
|
+
assert_equal sample.signature, @small_nfa.signature(sample)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Tests Classify#correctly_classify? is correct on invalid sample against
|
107
|
+
# small_nfa example
|
108
|
+
def test_invalid_sample_correctly_satified_by_small_nfa
|
109
|
+
sample = ADL::parse_sample <<-SAMPLE
|
110
|
+
# this one is changed
|
111
|
+
-
|
112
|
+
+ a
|
113
|
+
- a a
|
114
|
+
+ a a b
|
115
|
+
+ a b
|
116
|
+
+ a b c a
|
117
|
+
- a b c
|
118
|
+
+ a b b b b b b
|
119
|
+
- a z
|
120
|
+
- z
|
121
|
+
SAMPLE
|
122
|
+
assert_equal(false, @small_nfa.correctly_classify?(sample))
|
123
|
+
sample = ADL::parse_sample <<-SAMPLE
|
124
|
+
+
|
125
|
+
+ a
|
126
|
+
- a a
|
127
|
+
+ a a b
|
128
|
+
# this one is changed
|
129
|
+
- a b
|
130
|
+
+ a b c a
|
131
|
+
- a b c
|
132
|
+
+ a b b b b b b
|
133
|
+
- a z
|
134
|
+
- z
|
135
|
+
SAMPLE
|
136
|
+
assert_equal(false, @small_nfa.correctly_classify?(sample))
|
137
|
+
sample = ADL::parse_sample <<-SAMPLE
|
138
|
+
+
|
139
|
+
+ a
|
140
|
+
# this one is changed
|
141
|
+
+ a a
|
142
|
+
+ a a b
|
143
|
+
+ a b
|
144
|
+
+ a b c a
|
145
|
+
- a b c
|
146
|
+
+ a b b b b b b
|
147
|
+
- a z
|
148
|
+
- z
|
149
|
+
SAMPLE
|
150
|
+
assert_equal(false, @small_nfa.correctly_classify?(sample))
|
151
|
+
end
|
152
|
+
|
153
|
+
end # class ClassifierTest
|
154
|
+
end # class Automaton
|
155
|
+
end # module Stamina
|
@@ -0,0 +1,1092 @@
|
|
1
|
+
require 'stamina/stamina_test'
|
2
|
+
require 'stamina/automaton'
|
3
|
+
module Stamina
|
4
|
+
|
5
|
+
class AutomatonTest < StaminaTest
|
6
|
+
|
7
|
+
# Tests that an automaton can be created with onself=true
|
8
|
+
def test_new_on_self
|
9
|
+
Automaton.new(true) do |fa|
|
10
|
+
fa.add_state(:initial => true)
|
11
|
+
add_state(:accepting => true)
|
12
|
+
connect(0,1,'a')
|
13
|
+
fa.connect(1,0,'b')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Tests that an automaton can be created with onself=true
|
18
|
+
def test_new_not_on_self
|
19
|
+
Automaton.new(false) do |fa|
|
20
|
+
fa.add_state(:initial => true)
|
21
|
+
fa.add_state(:accepting => true)
|
22
|
+
fa.connect(0,1,'a')
|
23
|
+
fa.connect(1,0,'b')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Tests Automaton documentation example.
|
28
|
+
def test_documentation_example
|
29
|
+
# Building an automaton for the regular language a(ba)*
|
30
|
+
# It's a deterministic one, so we enforce it!
|
31
|
+
fa = Automaton.new do
|
32
|
+
add_state(:initial => true)
|
33
|
+
add_state(:accepting => true)
|
34
|
+
connect(0,1,'a')
|
35
|
+
connect(1,0,'b')
|
36
|
+
end
|
37
|
+
|
38
|
+
# And we now it accepts 'a b a b a', and rejects 'a b' as well as ''
|
39
|
+
assert_equal(true, fa.accepts?('? a b a b a'))
|
40
|
+
assert_equal(false,fa.accepts?('? a b'))
|
41
|
+
assert_equal(true, fa.rejects?('?'))
|
42
|
+
end
|
43
|
+
|
44
|
+
### tests on small dfa #######################################################
|
45
|
+
|
46
|
+
# Tests Automaton#states on examples
|
47
|
+
def test_states_on_examples
|
48
|
+
assert_equal(4,@small_dfa.states.size)
|
49
|
+
assert_equal(4,@small_nfa.states.size)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Tests Automaton#edges on examples
|
53
|
+
def test_edges_on_examples
|
54
|
+
assert_equal(6,@small_dfa.edges.size)
|
55
|
+
assert_equal(7,@small_nfa.edges.size)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Tests Automaton#state_count on examples
|
59
|
+
def test_state_count_on_examples
|
60
|
+
assert_equal(4, @small_dfa.state_count)
|
61
|
+
assert_equal(4, @small_nfa.state_count)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Tests Automaton#edge_count on examples
|
65
|
+
def test_edge_count_on_examples
|
66
|
+
assert_equal(6, @small_dfa.edge_count)
|
67
|
+
assert_equal(7, @small_nfa.edge_count)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Tests Automaton#ith_state on examples
|
71
|
+
def test_ith_state_on_examples
|
72
|
+
@examples.each do |fa|
|
73
|
+
states = []
|
74
|
+
0.upto(fa.state_count-1) do |i|
|
75
|
+
states << fa.ith_state(i)
|
76
|
+
end
|
77
|
+
assert_equal(fa.states, states)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Tests Automaton#ith_states on examples
|
82
|
+
def test_ith_states_on_examples
|
83
|
+
assert_equal(@small_dfa.states, @small_dfa.ith_states(0,1,2,3))
|
84
|
+
assert_equal([@small_dfa.ith_state(1)], @small_dfa.ith_states(1))
|
85
|
+
assert_equal(@small_nfa.states, @small_nfa.ith_states(0,1,2,3))
|
86
|
+
assert_equal([@small_nfa.ith_state(1)], @small_nfa.ith_states(1))
|
87
|
+
end
|
88
|
+
|
89
|
+
# Tests Automaton#ith_edge on examples
|
90
|
+
def test_ith_edge_on_examples
|
91
|
+
@examples.each do |fa|
|
92
|
+
edges = []
|
93
|
+
0.upto(fa.edge_count-1) do |i|
|
94
|
+
edges << fa.ith_edge(i)
|
95
|
+
end
|
96
|
+
assert_equal(fa.edges, edges)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Tests Automaton#ith_edges on examples
|
101
|
+
def test_ith_edges_on_examples
|
102
|
+
assert_equal(@small_dfa.edges, @small_dfa.ith_edges(0,1,2,3,4,5))
|
103
|
+
assert_equal([@small_dfa.ith_edge(1)], @small_dfa.ith_edges(1))
|
104
|
+
assert_equal([@small_dfa.ith_edge(1), @small_dfa.ith_edge(4)], @small_dfa.ith_edges(1,4))
|
105
|
+
assert_equal(@small_nfa.edges, @small_nfa.ith_edges(0,1,2,3,4,5,6))
|
106
|
+
assert_equal([@small_nfa.ith_edge(1)], @small_nfa.ith_edges(1))
|
107
|
+
assert_equal([@small_nfa.ith_edge(1), @small_nfa.ith_edge(4)], @small_nfa.ith_edges(1,4))
|
108
|
+
end
|
109
|
+
|
110
|
+
# Tests Automaton#each_state on examples
|
111
|
+
def test_each_state_on_examples
|
112
|
+
@examples.each do |fa|
|
113
|
+
states = []
|
114
|
+
fa.each_state {|s| states << s}
|
115
|
+
assert_equal(fa.states, states)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Tests Automaton#each_edge on examples
|
120
|
+
def test_each_state_on_examples
|
121
|
+
@examples.each do |fa|
|
122
|
+
edges = []
|
123
|
+
fa.each_edge {|e| edges << e}
|
124
|
+
assert_equal(fa.edges, edges)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Tests Automaton#in_edges on examples
|
129
|
+
def test_in_edges_on_examples
|
130
|
+
assert_equal(@small_dfa.ith_edges(4), @small_dfa.in_edges(0,true))
|
131
|
+
assert_equal(@small_dfa.ith_edges(0,5), @small_dfa.in_edges(1,true))
|
132
|
+
assert_equal(@small_dfa.ith_edges(1,3), @small_dfa.in_edges(2,true))
|
133
|
+
assert_equal(@small_dfa.ith_edges(2), @small_dfa.in_edges(3,true))
|
134
|
+
|
135
|
+
assert_equal(@small_nfa.ith_edges(5), @small_nfa.in_edges(0,true))
|
136
|
+
assert_equal(@small_nfa.ith_edges(0,1,6), @small_nfa.in_edges(1,true))
|
137
|
+
assert_equal(@small_nfa.ith_edges(2), @small_nfa.in_edges(2,true))
|
138
|
+
assert_equal(@small_nfa.ith_edges(3,4), @small_nfa.in_edges(3,true))
|
139
|
+
end
|
140
|
+
|
141
|
+
# Tests Automaton#in_edges on examples
|
142
|
+
def test_in_edges_and_out_edges_by_state_name
|
143
|
+
dfa = ADL.parse_automaton <<-DFA
|
144
|
+
2 2
|
145
|
+
First true false
|
146
|
+
Second false true
|
147
|
+
First Second a
|
148
|
+
Second First b
|
149
|
+
DFA
|
150
|
+
assert_equal dfa.ith_edges(0), dfa.in_edges('Second')
|
151
|
+
assert_equal dfa.ith_edges(0), dfa.out_edges('First')
|
152
|
+
end
|
153
|
+
|
154
|
+
# Tests Automaton#out_edges on examples
|
155
|
+
def test_out_edges_on_examples
|
156
|
+
assert_equal(@small_dfa.ith_edges(0), @small_dfa.out_edges(0,true))
|
157
|
+
assert_equal(@small_dfa.ith_edges(1,2,5), @small_dfa.out_edges(1,true))
|
158
|
+
assert_equal(@small_dfa.ith_edges(4), @small_dfa.out_edges(2,true))
|
159
|
+
assert_equal(@small_dfa.ith_edges(3), @small_dfa.out_edges(3,true))
|
160
|
+
|
161
|
+
assert_equal(@small_nfa.ith_edges(0), @small_nfa.out_edges(0,true))
|
162
|
+
assert_equal(@small_nfa.ith_edges(1,2,3), @small_nfa.out_edges(1,true))
|
163
|
+
assert_equal(@small_nfa.ith_edges(4,6), @small_nfa.out_edges(2,true))
|
164
|
+
assert_equal(@small_nfa.ith_edges(5), @small_nfa.out_edges(3,true))
|
165
|
+
end
|
166
|
+
|
167
|
+
# Tests Automaton#in_symbols on examples
|
168
|
+
def test_in_symbols_on_examples
|
169
|
+
assert_equal(['c'], @small_dfa.in_symbols(0,true))
|
170
|
+
assert_equal(['a','c'], @small_dfa.in_symbols(1,true))
|
171
|
+
assert_equal(['b'], @small_dfa.in_symbols(2,true))
|
172
|
+
assert_equal(['a'], @small_dfa.in_symbols(3,true))
|
173
|
+
|
174
|
+
assert_equal(['a'], @small_nfa.in_symbols(0,true))
|
175
|
+
assert_equal([nil,'a'], @small_nfa.in_symbols(1,true))
|
176
|
+
assert_equal(['b'], @small_nfa.in_symbols(2,true))
|
177
|
+
assert_equal(['b','c'], @small_nfa.in_symbols(3,true))
|
178
|
+
end
|
179
|
+
|
180
|
+
# Tests Automaton#out_edges on examples
|
181
|
+
def test_out_symbols_on_examples
|
182
|
+
assert_equal(['a'], @small_dfa.out_symbols(0,true))
|
183
|
+
assert_equal(['a', 'b', 'c'], @small_dfa.out_symbols(1,true))
|
184
|
+
assert_equal(['c'], @small_dfa.out_symbols(2,true))
|
185
|
+
assert_equal(['b'], @small_dfa.out_symbols(3,true))
|
186
|
+
|
187
|
+
assert_equal(['a'], @small_nfa.out_symbols(0,true))
|
188
|
+
assert_equal([nil, 'b'], @small_nfa.out_symbols(1,true))
|
189
|
+
assert_equal([nil, 'c'], @small_nfa.out_symbols(2,true))
|
190
|
+
assert_equal(['a'], @small_nfa.out_symbols(3,true))
|
191
|
+
end
|
192
|
+
|
193
|
+
# Tests Automaton#adjacent_states on examples
|
194
|
+
def test_adjacent_states_on_examples
|
195
|
+
assert_equal(@small_dfa.ith_states(1,2), @small_dfa.adjacent_states(0).sort)
|
196
|
+
assert_equal(@small_dfa.ith_states(0,1,2,3), @small_dfa.adjacent_states(1).sort)
|
197
|
+
assert_equal(@small_dfa.ith_states(0,1,3), @small_dfa.adjacent_states(2).sort)
|
198
|
+
assert_equal(@small_dfa.ith_states(1,2), @small_dfa.adjacent_states(3).sort)
|
199
|
+
|
200
|
+
assert_equal(@small_nfa.ith_states(1,3), @small_nfa.adjacent_states(0).sort)
|
201
|
+
assert_equal(@small_nfa.ith_states(0,1,2,3), @small_nfa.adjacent_states(1).sort)
|
202
|
+
assert_equal(@small_nfa.ith_states(1,3), @small_nfa.adjacent_states(2).sort)
|
203
|
+
assert_equal(@small_nfa.ith_states(0,1,2), @small_nfa.adjacent_states(3).sort)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Tests Automaton#in_adjacent_states on examples
|
207
|
+
def test_in_adjacent_states_on_examples
|
208
|
+
assert_equal(@small_dfa.ith_states(2), @small_dfa.in_adjacent_states(0).sort)
|
209
|
+
assert_equal(@small_dfa.ith_states(0,1), @small_dfa.in_adjacent_states(1).sort)
|
210
|
+
assert_equal(@small_dfa.ith_states(1,3), @small_dfa.in_adjacent_states(2).sort)
|
211
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.in_adjacent_states(3).sort)
|
212
|
+
|
213
|
+
assert_equal(@small_nfa.ith_states(3), @small_nfa.in_adjacent_states(0).sort)
|
214
|
+
assert_equal(@small_nfa.ith_states(0,1,2), @small_nfa.in_adjacent_states(1).sort)
|
215
|
+
assert_equal(@small_nfa.ith_states(1), @small_nfa.in_adjacent_states(2).sort)
|
216
|
+
assert_equal(@small_nfa.ith_states(1,2), @small_nfa.in_adjacent_states(3).sort)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Tests Automaton#out_adjacent_states on examples
|
220
|
+
def test_out_adjacent_states_on_examples
|
221
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.out_adjacent_states(0).sort)
|
222
|
+
assert_equal(@small_dfa.ith_states(1,2,3), @small_dfa.out_adjacent_states(1).sort)
|
223
|
+
assert_equal(@small_dfa.ith_states(0), @small_dfa.out_adjacent_states(2).sort)
|
224
|
+
assert_equal(@small_dfa.ith_states(2), @small_dfa.out_adjacent_states(3).sort)
|
225
|
+
|
226
|
+
assert_equal(@small_nfa.ith_states(1), @small_nfa.out_adjacent_states(0).sort)
|
227
|
+
assert_equal(@small_nfa.ith_states(1,2,3), @small_nfa.out_adjacent_states(1).sort)
|
228
|
+
assert_equal(@small_nfa.ith_states(1,3), @small_nfa.out_adjacent_states(2).sort)
|
229
|
+
assert_equal(@small_nfa.ith_states(0), @small_nfa.out_adjacent_states(3).sort)
|
230
|
+
end
|
231
|
+
|
232
|
+
# Tests Automaton#initial_states on examples
|
233
|
+
def test_initial_states_on_examples
|
234
|
+
assert_equal([@small_dfa.ith_state(3)], @small_dfa.initial_states())
|
235
|
+
assert_equal(@small_nfa.ith_states(0,3), @small_nfa.initial_states().sort)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Tests Automaton#initial_state on examples
|
239
|
+
def test_initial_state_on_examples
|
240
|
+
assert_equal(@small_dfa.ith_state(3), @small_dfa.initial_state())
|
241
|
+
end
|
242
|
+
|
243
|
+
# Tests Automaton#step on examples
|
244
|
+
def test_step_on_examples
|
245
|
+
assert_equal([], @small_dfa.step(0,'b'))
|
246
|
+
@small_dfa.each_state do |s|
|
247
|
+
s.out_edges.each do |e|
|
248
|
+
assert_equal([e.target], @small_dfa.step(s,e.symbol))
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
assert_equal([], @small_nfa.step(0, 'b'))
|
253
|
+
assert_equal(@small_nfa.ith_states(1), @small_nfa.step(0, 'a'))
|
254
|
+
assert_equal(@small_nfa.ith_states(2,3), @small_nfa.step(1, 'b'))
|
255
|
+
assert_equal(@small_nfa.ith_states(1), @small_nfa.step(1, nil))
|
256
|
+
end
|
257
|
+
|
258
|
+
# Tests Automaton#dfa_step on examples
|
259
|
+
def test_dfa_step_on_examples
|
260
|
+
assert_equal(nil, @small_dfa.dfa_step(0,'b'))
|
261
|
+
@small_dfa.each_state do |s|
|
262
|
+
s.out_edges.each do |e|
|
263
|
+
assert_equal(e.target, @small_dfa.dfa_step(s,e.symbol))
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# Tests Automaton#delta on examples
|
269
|
+
def test_delta_on_examples
|
270
|
+
assert_equal([], @small_dfa.delta(0,'b'))
|
271
|
+
@small_dfa.each_state do |s|
|
272
|
+
s.out_edges.each do |e|
|
273
|
+
assert_equal([e.target], @small_dfa.delta(s,e.symbol))
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
assert_equal([], @small_nfa.delta(0,'b'))
|
278
|
+
assert_equal(@small_nfa.ith_states(1,2,3), @small_nfa.delta(1, 'b').sort)
|
279
|
+
assert_equal(@small_nfa.ith_states(), @small_nfa.delta(1, 'a').sort)
|
280
|
+
assert_equal(@small_nfa.ith_states(1), @small_nfa.delta(0, 'a').sort)
|
281
|
+
assert_equal(@small_nfa.ith_states(1,2,3), @small_nfa.delta(2, 'b').sort)
|
282
|
+
end
|
283
|
+
|
284
|
+
# Tests Automaton#dfa_delta on examples
|
285
|
+
def test_dfa_delta_on_examples
|
286
|
+
assert_equal(nil, @small_dfa.dfa_delta(0,'b'))
|
287
|
+
@small_dfa.each_state do |s|
|
288
|
+
s.out_edges.each do |e|
|
289
|
+
assert_equal(e.target, @small_dfa.dfa_delta(s,e.symbol))
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
### tests by methods #########################################################
|
295
|
+
|
296
|
+
# Tests Automaton#add_state
|
297
|
+
def test_add_state
|
298
|
+
Automaton.new(false) do |fa|
|
299
|
+
s0 = fa.add_state
|
300
|
+
assert_equal(1, fa.state_count)
|
301
|
+
assert_equal(false, s0.initial?)
|
302
|
+
assert_equal(false, s0.accepting?)
|
303
|
+
|
304
|
+
s1 = fa.add_state(:initial => true)
|
305
|
+
assert_equal(2, fa.state_count)
|
306
|
+
assert_equal(true, s1.initial?)
|
307
|
+
assert_equal(false, s1.accepting?)
|
308
|
+
|
309
|
+
s2 = fa.add_state(:initial => true, :accepting => true)
|
310
|
+
assert_equal(3, fa.state_count)
|
311
|
+
assert_equal(true, s2.initial?)
|
312
|
+
assert_equal(true, s2.accepting?)
|
313
|
+
|
314
|
+
s3 = fa.add_state(:myownkey => "blambeau")
|
315
|
+
assert_equal(4, fa.state_count)
|
316
|
+
assert_equal(false, s3.initial?)
|
317
|
+
assert_equal(false, s3.accepting?)
|
318
|
+
assert_equal("blambeau", s3[:myownkey])
|
319
|
+
|
320
|
+
assert_equal(0, fa.edge_count)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Simply tests that aliases of add_state work.
|
325
|
+
def test_add_state_aliases
|
326
|
+
Automaton.new(false) do |fa|
|
327
|
+
assert_not_nil(s0 = fa.add_state(:initial => true))
|
328
|
+
assert_not_nil(s1 = fa.create_state)
|
329
|
+
assert_not_nil fa.add_edge(s0,s1, 'a')
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# Tests Automaton#add_edge
|
334
|
+
def test_add_edge
|
335
|
+
Automaton.new(false) do |fa|
|
336
|
+
s0 = fa.add_state(:initial => true)
|
337
|
+
s1 = fa.add_state(:initial => false, :accepting => true)
|
338
|
+
edge = fa.add_edge(s0, s1, {:symbol => 'a'})
|
339
|
+
|
340
|
+
# check automaton
|
341
|
+
assert_equal(2, fa.state_count)
|
342
|
+
assert_equal(1, fa.edge_count)
|
343
|
+
|
344
|
+
# check edge
|
345
|
+
assert_equal('a', edge.symbol)
|
346
|
+
assert_equal(s0, edge.source)
|
347
|
+
assert_equal(s0, edge.from)
|
348
|
+
assert_equal(s1, edge.target)
|
349
|
+
assert_equal(s1, edge.to)
|
350
|
+
|
351
|
+
# check states
|
352
|
+
assert_equal([edge], s0.out_edges)
|
353
|
+
assert_equal([edge], s1.in_edges)
|
354
|
+
assert_equal(true, s0.deterministic?)
|
355
|
+
assert_equal(true, s1.deterministic?)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Simply tests that aliases of add_edge work.
|
360
|
+
def test_add_edge_aliases
|
361
|
+
Automaton.new(false) do |fa|
|
362
|
+
s0 = fa.add_state(:initial => true)
|
363
|
+
s1 = fa.create_state
|
364
|
+
assert_not_nil fa.add_edge(s0,s1, 'a')
|
365
|
+
assert_not_nil fa.create_edge(s0,s1,'b')
|
366
|
+
assert_not_nil fa.connect(s0,s1,'c')
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# Tests queries of states by names
|
371
|
+
def test_state_names_1
|
372
|
+
s0,s1,s2 = nil,nil,nil
|
373
|
+
simple_dfa = Automaton.new(false) do |fa|
|
374
|
+
s0 = fa.add_state(:initial => true, :name => 'A')
|
375
|
+
s1 = fa.add_state(:accepting => true, :name => 'B')
|
376
|
+
s2 = fa.add_state(:name => 'C')
|
377
|
+
fa.connect(s0, s1, 'a')
|
378
|
+
fa.connect(s1, s1, 'b')
|
379
|
+
fa.connect(s1, s2, 'c')
|
380
|
+
end
|
381
|
+
assert_raise ArgumentError do
|
382
|
+
simple_dfa.get_state(56) # wrong type
|
383
|
+
end
|
384
|
+
assert_raise ArgumentError do
|
385
|
+
simple_dfa.get_state('T') # non-existing name
|
386
|
+
end
|
387
|
+
|
388
|
+
assert_raise ArgumentError do
|
389
|
+
simple_dfa.get_state('') # non-existing state
|
390
|
+
end
|
391
|
+
|
392
|
+
assert_raise ArgumentError do
|
393
|
+
simple_dfa.get_state(nil) # nil name
|
394
|
+
end
|
395
|
+
assert_equal s0,simple_dfa.get_state('A')
|
396
|
+
assert_equal s1,simple_dfa.get_state('B')
|
397
|
+
assert_equal s2,simple_dfa.get_state('C')
|
398
|
+
end
|
399
|
+
|
400
|
+
# tests queries of states by names
|
401
|
+
def test_state_names_2
|
402
|
+
simple_dfa = Automaton.new(false) do |fa|
|
403
|
+
fa.add_state(:initial => true)
|
404
|
+
end
|
405
|
+
assert_raise ArgumentError do
|
406
|
+
simple_dfa.get_state('') # non-existing state
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
# Tests Automaton#drop_state
|
411
|
+
def test_drop_state
|
412
|
+
s0, s1, e00, e01, e10, e11 = nil
|
413
|
+
fa = Automaton.new do |fa|
|
414
|
+
s0 = fa.add_state(:initial => true)
|
415
|
+
s1 = fa.add_state
|
416
|
+
e01 = fa.connect(s0, s1, 'a')
|
417
|
+
e00 = fa.connect(s0, s0, 'b')
|
418
|
+
e10 = fa.connect(s1, s0, 'b')
|
419
|
+
e11 = fa.connect(s1, s1, 'a')
|
420
|
+
end
|
421
|
+
|
422
|
+
fa.drop_state(s1)
|
423
|
+
assert_equal(false, fa.states.include?(s1))
|
424
|
+
assert_equal(1, fa.state_count)
|
425
|
+
assert_equal(1, fa.edge_count)
|
426
|
+
assert_equal(-1, s1.index)
|
427
|
+
assert_equal(-1, e01.index)
|
428
|
+
assert_equal(-1, e10.index)
|
429
|
+
assert_equal(-1, e11.index)
|
430
|
+
assert_equal(0, s0.index)
|
431
|
+
assert_equal(0, e00.index)
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_drop_state_respects_indexing
|
435
|
+
fa = Stamina::ADL.parse_automaton <<-EOF
|
436
|
+
5 5
|
437
|
+
0 true false
|
438
|
+
1 false false
|
439
|
+
2 false false
|
440
|
+
3 false false
|
441
|
+
4 false false
|
442
|
+
0 1 a
|
443
|
+
0 2 b
|
444
|
+
1 2 b
|
445
|
+
2 3 a
|
446
|
+
3 4 b
|
447
|
+
EOF
|
448
|
+
fa.drop_state(1)
|
449
|
+
assert_equal 4, fa.state_count
|
450
|
+
end
|
451
|
+
|
452
|
+
# Tests Automaton#drop_state
|
453
|
+
def test_drop_state_aliases
|
454
|
+
s0, s1, e00, e01, e10, e11 = nil
|
455
|
+
fa = Automaton.new do |fa|
|
456
|
+
s0 = fa.add_state(:initial => true)
|
457
|
+
s1 = fa.add_state
|
458
|
+
e01 = fa.connect(s0, s1, 'a')
|
459
|
+
e00 = fa.connect(s0, s0, 'b')
|
460
|
+
e10 = fa.connect(s1, s0, 'b')
|
461
|
+
e11 = fa.connect(s1, s1, 'a')
|
462
|
+
end
|
463
|
+
|
464
|
+
fa.delete_state(s1)
|
465
|
+
assert_equal(1, fa.state_count)
|
466
|
+
assert_equal(1, fa.edge_count)
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_same_state_cannot_be_dropped_twice
|
470
|
+
s0, s1, e00, e01, e10, e11 = nil
|
471
|
+
fa = Automaton.new do |fa|
|
472
|
+
s0 = fa.add_state(:initial => true)
|
473
|
+
s1 = fa.add_state
|
474
|
+
e01 = fa.connect(s0, s1, 'a')
|
475
|
+
e00 = fa.connect(s0, s0, 'b')
|
476
|
+
e10 = fa.connect(s1, s0, 'b')
|
477
|
+
e11 = fa.connect(s1, s1, 'a')
|
478
|
+
end
|
479
|
+
|
480
|
+
fa.drop_state(s1)
|
481
|
+
assert_equal(false, fa.states.include?(s1))
|
482
|
+
assert_raise ArgumentError do
|
483
|
+
fa.drop_state(s1)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
# Tests Automaton#drop_states
|
488
|
+
def test_drop_states
|
489
|
+
s0, s1, s2, e00, e01, e10, e11, e02, e21 = nil
|
490
|
+
fa = Automaton.new do |fa|
|
491
|
+
s0 = fa.add_state(:initial => true)
|
492
|
+
s1, s2 = fa.add_n_states(2)
|
493
|
+
e01 = fa.connect(s0, s1, 'a')
|
494
|
+
e00 = fa.connect(s0, s0, 'b')
|
495
|
+
e10 = fa.connect(s1, s0, 'b')
|
496
|
+
e11 = fa.connect(s1, s1, 'a')
|
497
|
+
e02 = fa.connect(s0, s2, 'c')
|
498
|
+
e21 = fa.connect(s2, s1, 'a')
|
499
|
+
end
|
500
|
+
|
501
|
+
fa.drop_states(s1,s2)
|
502
|
+
assert_equal(1, fa.state_count)
|
503
|
+
assert_equal(1, fa.edge_count)
|
504
|
+
assert_equal(-1, s1.index)
|
505
|
+
assert_equal(-1, s2.index)
|
506
|
+
assert_equal(false, fa.states.include?(s1))
|
507
|
+
assert_equal(false, fa.states.include?(s2))
|
508
|
+
end
|
509
|
+
|
510
|
+
# Tests Automaton#drop_edge
|
511
|
+
def test_drop_edge
|
512
|
+
s0, s1, e01, e10 = nil
|
513
|
+
fa = Automaton.new do |fa|
|
514
|
+
s0 = fa.add_state(:initial => true)
|
515
|
+
s1 = fa.add_state
|
516
|
+
e01 = fa.connect(s0, s1, 'a')
|
517
|
+
e10 = fa.connect(s1, s0, 'b')
|
518
|
+
end
|
519
|
+
|
520
|
+
# we drop second edge
|
521
|
+
fa.drop_edge(e10)
|
522
|
+
assert_equal(2, fa.state_count)
|
523
|
+
assert_equal(1, fa.edge_count)
|
524
|
+
assert_equal(0, e01.index, 'First edge index has not changed')
|
525
|
+
|
526
|
+
# connect it again
|
527
|
+
e10 = fa.connect(s1, s0, 'b')
|
528
|
+
|
529
|
+
# we drop the first one this time
|
530
|
+
fa.drop_edge(e01)
|
531
|
+
assert_equal(2, fa.state_count)
|
532
|
+
assert_equal(1, fa.edge_count)
|
533
|
+
assert_equal(0, e10.index, 'Second edge became first')
|
534
|
+
end
|
535
|
+
|
536
|
+
# Tests Automaton#drop_edge
|
537
|
+
def test_drop_edge_by_index
|
538
|
+
s0, s1, e01, e10 = nil
|
539
|
+
fa = Automaton.new do |fa|
|
540
|
+
s0 = fa.add_state(:initial => true)
|
541
|
+
s1 = fa.add_state
|
542
|
+
e01 = fa.connect(s0, s1, 'a')
|
543
|
+
e10 = fa.connect(s1, s0, 'b')
|
544
|
+
end
|
545
|
+
|
546
|
+
# we drop second edge
|
547
|
+
fa.drop_edge(1)
|
548
|
+
assert_equal(2, fa.state_count)
|
549
|
+
assert_equal(1, fa.edge_count)
|
550
|
+
assert_equal(0, e01.index, 'First edge index has not changed')
|
551
|
+
end
|
552
|
+
|
553
|
+
# Tests aliases of Automaton#drop_edge
|
554
|
+
def test_drop_edge_aliases
|
555
|
+
s0, s1, e01, e10 = nil
|
556
|
+
fa = Automaton.new do |fa|
|
557
|
+
s0 = fa.add_state(:initial => true)
|
558
|
+
s1 = fa.add_state
|
559
|
+
e01 = fa.connect(s0, s1, 'a')
|
560
|
+
e10 = fa.connect(s1, s0, 'b')
|
561
|
+
end
|
562
|
+
|
563
|
+
# we drop second edge
|
564
|
+
fa.delete_edge(e10)
|
565
|
+
assert_equal(2, fa.state_count)
|
566
|
+
assert_equal(1, fa.edge_count)
|
567
|
+
assert_equal(0, e01.index, 'First edge index has not changed')
|
568
|
+
end
|
569
|
+
|
570
|
+
# Tests that an edge cannot be dropped twice
|
571
|
+
def test_same_edge_cannot_be_dropped_twice
|
572
|
+
s0, s1, e01, e10 = nil
|
573
|
+
fa = Automaton.new do |fa|
|
574
|
+
s0 = fa.add_state(:initial => true)
|
575
|
+
s1 = fa.add_state
|
576
|
+
e01 = fa.connect(s0, s1, 'a')
|
577
|
+
e10 = fa.connect(s1, s0, 'b')
|
578
|
+
end
|
579
|
+
|
580
|
+
# we drop first edge
|
581
|
+
fa.drop_edge(e01)
|
582
|
+
|
583
|
+
# cannot drop it again
|
584
|
+
assert_raise ArgumentError do
|
585
|
+
fa.drop_edge(e01)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
# Tests Automaton#drop_edges
|
590
|
+
def test_drop_edges
|
591
|
+
s0, s1, e01, e10, e11 = nil
|
592
|
+
fa = Automaton.new do |fa|
|
593
|
+
s0 = fa.add_state(:initial => true)
|
594
|
+
s1 = fa.add_state
|
595
|
+
e10 = fa.connect(s1, s0, 'b')
|
596
|
+
e01 = fa.connect(s0, s1, 'a')
|
597
|
+
e11 = fa.connect(s1, s1, 'a')
|
598
|
+
end
|
599
|
+
|
600
|
+
fa.drop_edges(e10,e11)
|
601
|
+
assert_equal(2, fa.state_count)
|
602
|
+
assert_equal(1, fa.edge_count)
|
603
|
+
assert_equal(0, e01.index)
|
604
|
+
end
|
605
|
+
|
606
|
+
# Tests that Automaton#drop_edges allows removing all edges
|
607
|
+
def test_drop_edges_recognizes_sub_transaction
|
608
|
+
s0, ea, eb, ec = nil
|
609
|
+
fa = Automaton.new do |fa|
|
610
|
+
s0 = fa.add_state(:initial => true)
|
611
|
+
ea = fa.connect(s0, s0, 'a')
|
612
|
+
eb = fa.connect(s0, s0, 'b')
|
613
|
+
ec = fa.connect(s0, s0, 'c')
|
614
|
+
end
|
615
|
+
fa.drop_edges(ea, eb, ec)
|
616
|
+
assert_equal(0, fa.edge_count)
|
617
|
+
assert_equal(0, s0.in_edges.size)
|
618
|
+
assert_equal(0, s0.out_edges.size)
|
619
|
+
end
|
620
|
+
|
621
|
+
# Tests Automaton#drop_edges
|
622
|
+
def test_drop_edges_allow_any_order_of_arguments
|
623
|
+
s0, s1, e01, e10, e11 = nil
|
624
|
+
fa = Automaton.new do |fa|
|
625
|
+
s0 = fa.add_state(:initial => true)
|
626
|
+
s1 = fa.add_state
|
627
|
+
e10 = fa.connect(s1, s0, 'b')
|
628
|
+
e01 = fa.connect(s0, s1, 'a')
|
629
|
+
e11 = fa.connect(s1, s1, 'a')
|
630
|
+
end
|
631
|
+
|
632
|
+
fa.drop_edges(e11,e10)
|
633
|
+
assert_equal(2, fa.state_count)
|
634
|
+
assert_equal(1, fa.edge_count)
|
635
|
+
assert_equal(0, e01.index)
|
636
|
+
end
|
637
|
+
|
638
|
+
# Tests aliases of Automaton#drop_edges
|
639
|
+
def test_drop_edges_aliases
|
640
|
+
s0, s1, e01, e10, e11 = nil
|
641
|
+
fa = Automaton.new do |fa|
|
642
|
+
s0 = fa.add_state(:initial => true)
|
643
|
+
s1 = fa.add_state
|
644
|
+
e10 = fa.connect(s1, s0, 'b')
|
645
|
+
e01 = fa.connect(s0, s1, 'a')
|
646
|
+
e11 = fa.connect(s1, s1, 'a')
|
647
|
+
end
|
648
|
+
|
649
|
+
fa.delete_edges(e10,e11)
|
650
|
+
assert_equal(2, fa.state_count)
|
651
|
+
assert_equal(1, fa.edge_count)
|
652
|
+
assert_equal(0, e01.index)
|
653
|
+
end
|
654
|
+
|
655
|
+
# Tests Automaton#edges on invalid edge arguments
|
656
|
+
def test_drop_edges_detects_invalid_edges
|
657
|
+
s0, s1, e01, e10, e11 = nil
|
658
|
+
fa = Automaton.new do |fa|
|
659
|
+
s0 = fa.add_state(:initial => true)
|
660
|
+
s1 = fa.add_state
|
661
|
+
e10 = fa.connect(s1, s0, 'b')
|
662
|
+
e01 = fa.connect(s0, s1, 'a')
|
663
|
+
e11 = fa.connect(s1, s1, 'a')
|
664
|
+
end
|
665
|
+
|
666
|
+
fa.drop_edge(e10)
|
667
|
+
assert_raise ArgumentError do
|
668
|
+
fa.drop_edges(e11,e10)
|
669
|
+
end
|
670
|
+
assert_equal(2, fa.state_count)
|
671
|
+
assert_equal(2, fa.edge_count)
|
672
|
+
end
|
673
|
+
|
674
|
+
### tests by scenarios #######################################################
|
675
|
+
|
676
|
+
# Tests creating an automaton for the empty regular language
|
677
|
+
def test_automaton_of_empty_language
|
678
|
+
fa, s0 = nil
|
679
|
+
assert_nothing_raised do
|
680
|
+
fa = Automaton.new do |fa|
|
681
|
+
s0 = fa.add_state(:initial => true, :accepting => false)
|
682
|
+
end
|
683
|
+
end
|
684
|
+
assert_equal(1, fa.state_count)
|
685
|
+
assert_equal(0, fa.edge_count)
|
686
|
+
assert_equal(true, fa.deterministic?)
|
687
|
+
assert_equal([s0], fa.initial_states)
|
688
|
+
assert_equal(s0, fa.initial_state)
|
689
|
+
assert_equal([s0], fa.states)
|
690
|
+
assert_equal([], fa.edges)
|
691
|
+
assert_equal([], fa.in_edges(s0))
|
692
|
+
assert_equal([], fa.out_edges(s0))
|
693
|
+
assert_equal([], fa.in_symbols(s0))
|
694
|
+
assert_equal([], fa.out_symbols(s0))
|
695
|
+
assert_equal([], fa.adjacent_states(s0))
|
696
|
+
assert_equal([], fa.in_adjacent_states(s0))
|
697
|
+
assert_equal([], fa.out_adjacent_states(s0))
|
698
|
+
end
|
699
|
+
|
700
|
+
# Tests creating an automaton for the regular language that only accepts the
|
701
|
+
# empty string.
|
702
|
+
def test_automaton_of_lambda_language
|
703
|
+
fa, s0 = nil
|
704
|
+
assert_nothing_raised do
|
705
|
+
fa = Automaton.new do |fa|
|
706
|
+
s0 = fa.add_state(:initial => true, :accepting => true)
|
707
|
+
end
|
708
|
+
end
|
709
|
+
assert_equal(1, fa.state_count)
|
710
|
+
assert_equal(0, fa.edge_count)
|
711
|
+
assert_equal([s0], fa.states)
|
712
|
+
assert_equal(true, fa.deterministic?)
|
713
|
+
assert_equal([s0], fa.initial_states)
|
714
|
+
assert_equal(s0, fa.initial_state)
|
715
|
+
assert_equal([], fa.edges)
|
716
|
+
assert_equal([], fa.in_edges(s0))
|
717
|
+
assert_equal([], fa.out_edges(s0))
|
718
|
+
assert_equal([], fa.in_symbols(s0))
|
719
|
+
assert_equal([], fa.out_symbols(s0))
|
720
|
+
assert_equal([], fa.adjacent_states(s0))
|
721
|
+
assert_equal([], fa.in_adjacent_states(s0))
|
722
|
+
assert_equal([], fa.out_adjacent_states(s0))
|
723
|
+
end
|
724
|
+
|
725
|
+
# Tests that automaton can be created with nil symbols on edges
|
726
|
+
def test_automaton_with_epsilon
|
727
|
+
fa, s0, s1, edge = nil
|
728
|
+
assert_nothing_raised do
|
729
|
+
fa = Automaton.new(false) do |fa|
|
730
|
+
s0 = fa.add_state(:initial => true, :accepting => true)
|
731
|
+
s1 = fa.add_state
|
732
|
+
edge = fa.connect(s0, s1, {:symbol => nil})
|
733
|
+
assert_equal(nil, edge.symbol)
|
734
|
+
end
|
735
|
+
end
|
736
|
+
assert_equal(false, fa.deterministic?)
|
737
|
+
assert_equal([s0,s1], fa.initial_states.sort)
|
738
|
+
assert_equal(true, fa.initial_states.include?(fa.initial_state))
|
739
|
+
end
|
740
|
+
|
741
|
+
# Tests creation an automaton with one accepting state with looping 'a'
|
742
|
+
# symbol.
|
743
|
+
def test_automaton_of_whole_langage_on_a
|
744
|
+
fa, s0, e0 = nil
|
745
|
+
assert_nothing_raised do
|
746
|
+
fa = Automaton.new do |fa|
|
747
|
+
s0 = fa.add_state(:initial => true, :accepting => true)
|
748
|
+
e0 = fa.add_edge(s0, s0, {:symbol => 'a'})
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
# check the whole automaton
|
753
|
+
assert_equal(1, fa.state_count)
|
754
|
+
assert_equal(1, fa.edge_count)
|
755
|
+
assert_equal([s0], fa.states)
|
756
|
+
assert_equal([e0], fa.edges)
|
757
|
+
assert_equal(true, fa.deterministic?)
|
758
|
+
assert_equal([s0], fa.initial_states)
|
759
|
+
assert_equal(s0, fa.initial_state)
|
760
|
+
assert_equal([e0], fa.in_edges(s0))
|
761
|
+
assert_equal([e0], fa.out_edges(s0))
|
762
|
+
assert_equal(['a'], fa.in_symbols(s0))
|
763
|
+
assert_equal(['a'], fa.out_symbols(s0))
|
764
|
+
assert_equal([s0], fa.adjacent_states(s0))
|
765
|
+
assert_equal([s0], fa.in_adjacent_states(s0))
|
766
|
+
assert_equal([s0], fa.out_adjacent_states(s0))
|
767
|
+
end
|
768
|
+
|
769
|
+
# Tests creating a simple deterministic automaton
|
770
|
+
def test_deterministic_fa_with_two_states
|
771
|
+
s0, s1, e01, e10, fa = nil
|
772
|
+
|
773
|
+
# automaton construction, should not raise anything
|
774
|
+
fa = Automaton.new do |a|
|
775
|
+
s0 = a.add_state(:initial => true)
|
776
|
+
s1 = a.add_state(:accepting => true)
|
777
|
+
e01 = a.add_edge(s0, s1, 'a')
|
778
|
+
e10 = a.add_edge(s1, s0, 'b')
|
779
|
+
end
|
780
|
+
|
781
|
+
# check automaton
|
782
|
+
assert_equal(2, fa.state_count)
|
783
|
+
assert_equal(2, fa.edge_count)
|
784
|
+
assert_equal(true, fa.deterministic?)
|
785
|
+
assert_equal([s0], fa.initial_states)
|
786
|
+
assert_equal(s0, fa.initial_state)
|
787
|
+
assert_equal([s0,s1], fa.states)
|
788
|
+
assert_equal([e01,e10], fa.edges)
|
789
|
+
|
790
|
+
# check state s0
|
791
|
+
assert_equal(true, s0.initial?)
|
792
|
+
assert_equal(false, s0.accepting?)
|
793
|
+
assert_equal(true, s0.deterministic?)
|
794
|
+
assert_equal([e01], s0.out_edges)
|
795
|
+
assert_equal([e10], s0.in_edges)
|
796
|
+
|
797
|
+
# check state s1
|
798
|
+
assert_equal(false, s1.initial?)
|
799
|
+
assert_equal(true, s1.accepting?)
|
800
|
+
assert_equal(true, s1.deterministic?)
|
801
|
+
assert_equal([e10], s1.out_edges)
|
802
|
+
assert_equal([e01], s1.in_edges)
|
803
|
+
|
804
|
+
# check edge 01
|
805
|
+
assert_equal('a', e01.symbol)
|
806
|
+
assert_equal(s0, e01.source)
|
807
|
+
assert_equal(s1, e01.target)
|
808
|
+
|
809
|
+
# check edge 10
|
810
|
+
assert_equal('b', e10.symbol)
|
811
|
+
assert_equal(s1, e10.source)
|
812
|
+
assert_equal(s0, e10.target)
|
813
|
+
|
814
|
+
# check the whole automaton
|
815
|
+
assert_equal(2, fa.state_count)
|
816
|
+
assert_equal(2, fa.edge_count)
|
817
|
+
assert_equal([s0, s1], fa.states)
|
818
|
+
assert_equal([e01, e10], fa.edges)
|
819
|
+
assert_equal([e10], fa.in_edges(s0))
|
820
|
+
assert_equal([e01], fa.out_edges(s0))
|
821
|
+
assert_equal(['b'], fa.in_symbols(s0))
|
822
|
+
assert_equal(['a'], fa.out_symbols(s0))
|
823
|
+
assert_equal([e01], fa.in_edges(s1))
|
824
|
+
assert_equal([e10], fa.out_edges(s1))
|
825
|
+
assert_equal(['a'], fa.in_symbols(s1))
|
826
|
+
assert_equal(['b'], fa.out_symbols(s1))
|
827
|
+
assert_equal([s1], fa.adjacent_states(s0))
|
828
|
+
assert_equal([s1], fa.in_adjacent_states(s0))
|
829
|
+
assert_equal([s1], fa.out_adjacent_states(s0))
|
830
|
+
assert_equal([s0], fa.adjacent_states(s1))
|
831
|
+
assert_equal([s0], fa.in_adjacent_states(s1))
|
832
|
+
assert_equal([s0], fa.out_adjacent_states(s1))
|
833
|
+
|
834
|
+
# check that it is recognized as a deterministic automaton
|
835
|
+
assert_equal true, fa.deterministic?
|
836
|
+
end
|
837
|
+
|
838
|
+
# Tests nfa.deterministic? on documentation example
|
839
|
+
def test_documentation_example2
|
840
|
+
# create some automaton (here a non deterministic automaton)
|
841
|
+
nfa = Automaton.new do |fa|
|
842
|
+
s0 = fa.add_state(:initial => true, :accepting => false)
|
843
|
+
s1 = fa.add_state(:initial => false, :accepting => true)
|
844
|
+
s2 = fa.add_state(:initial => false, :accepting => true)
|
845
|
+
fa.add_edge(s0, s1, 'a')
|
846
|
+
fa.add_edge(s0, s2, 'a')
|
847
|
+
end
|
848
|
+
|
849
|
+
# check that it is recognized as a non deterministic one
|
850
|
+
assert_equal false,nfa.deterministic?
|
851
|
+
end
|
852
|
+
|
853
|
+
# Tests Node#delta on a deterministic automaton
|
854
|
+
def test_state_delta_on_deterministic
|
855
|
+
nfa, s0, s1, s2 = nil
|
856
|
+
nfa = Automaton.new do |fa|
|
857
|
+
s0 = fa.add_state(:initial => true)
|
858
|
+
s1, s2 = fa.add_state, fa.add_state
|
859
|
+
fa.connect(s0, s1, 'a')
|
860
|
+
fa.connect(s0, s2, 'b')
|
861
|
+
fa.connect(s1, s0, 'b')
|
862
|
+
fa.connect(s1, s2, 'c')
|
863
|
+
end
|
864
|
+
assert_equal(true, nfa.deterministic?)
|
865
|
+
|
866
|
+
# letting state choose its data-structure
|
867
|
+
assert_equal([s1], s0.delta('a'))
|
868
|
+
assert_equal([s2], s0.delta('b'))
|
869
|
+
assert_equal([], s0.delta('c'))
|
870
|
+
assert_equal([s0], s1.delta('b'))
|
871
|
+
assert_equal([s2], s1.delta('c'))
|
872
|
+
end
|
873
|
+
|
874
|
+
# Tests Node#delta on a non deterministic automaton
|
875
|
+
def test_state_delta_on_non_deterministic
|
876
|
+
fa, s0, s1, s2 = nil
|
877
|
+
fa = Automaton.new do |fa|
|
878
|
+
s0 = fa.add_state(:initial => true)
|
879
|
+
s1, s2 = fa.add_state, fa.add_state
|
880
|
+
fa.connect(s0, s1, 'a')
|
881
|
+
fa.connect(s0, s2, 'a')
|
882
|
+
fa.connect(s1, s1, 'b')
|
883
|
+
fa.connect(s1, s2, 'b')
|
884
|
+
end
|
885
|
+
assert_equal(false, fa.deterministic?)
|
886
|
+
assert_equal([s1,s2], s0.delta('a').sort)
|
887
|
+
assert_equal([], s0.delta('c').sort)
|
888
|
+
assert_equal([s1,s2], s1.delta('b').sort)
|
889
|
+
assert_equal([], s2.delta('a').sort)
|
890
|
+
assert_equal([], s2.delta('b').sort)
|
891
|
+
end
|
892
|
+
|
893
|
+
# Tests Node#delta on a non deterministic automaton with epsilon letters
|
894
|
+
def test_state_delta_on_non_deterministic_with_epsilon
|
895
|
+
#
|
896
|
+
# tests on s0 -a-> s1 -a-> s2
|
897
|
+
# with a looping nil on s1
|
898
|
+
#
|
899
|
+
fa, s0, s1, s2, s3, s4 = nil
|
900
|
+
fa = Automaton.new do |fa|
|
901
|
+
s0 = fa.add_state(:initial => true)
|
902
|
+
s1, s2 = fa.add_state, fa.add_state
|
903
|
+
fa.connect(s0,s1,'a')
|
904
|
+
fa.connect(s1,s1,nil)
|
905
|
+
fa.connect(s1,s2,'a')
|
906
|
+
end
|
907
|
+
assert_equal(false, fa.deterministic?)
|
908
|
+
assert_equal([], s0.delta('b'))
|
909
|
+
assert_equal([s1], s0.delta('a'))
|
910
|
+
assert_equal([s2], s1.delta('a'))
|
911
|
+
assert_equal([s1], s1.delta(nil))
|
912
|
+
|
913
|
+
#
|
914
|
+
# tests on s0 -a-> s1 -nil-> s2
|
915
|
+
#
|
916
|
+
fa = Automaton.new do |fa|
|
917
|
+
s0 = fa.add_state(:initial => true)
|
918
|
+
s1, s2 = fa.add_state, fa.add_state
|
919
|
+
fa.connect(s0,s1,'a')
|
920
|
+
fa.connect(s1,s2,nil)
|
921
|
+
end
|
922
|
+
assert_equal(false, fa.deterministic?)
|
923
|
+
assert_equal([], s0.delta(nil))
|
924
|
+
assert_equal([s1,s2], s0.delta('a').sort)
|
925
|
+
assert_equal([], s1.delta('a'))
|
926
|
+
assert_equal([s2], s1.delta(nil))
|
927
|
+
|
928
|
+
#
|
929
|
+
# tests on s0 -a-> s1 -nil-> s2 -a-> s3
|
930
|
+
#
|
931
|
+
fa = Automaton.new do |fa|
|
932
|
+
s0 = fa.add_state(:initial => true)
|
933
|
+
s1, s2, s3 = fa.add_state, fa.add_state, fa.add_state
|
934
|
+
fa.connect(s0,s1,'a')
|
935
|
+
fa.connect(s1,s2,nil)
|
936
|
+
fa.connect(s2,s3,'a')
|
937
|
+
end
|
938
|
+
assert_equal(false, fa.deterministic?)
|
939
|
+
assert_equal([], s0.delta(nil))
|
940
|
+
assert_equal([s1,s2], s0.delta('a').sort)
|
941
|
+
assert_equal([s3], s1.delta('a'))
|
942
|
+
assert_equal([s3], s2.delta('a'))
|
943
|
+
assert_equal([s2], s1.delta(nil))
|
944
|
+
|
945
|
+
# s0 -a-> s1 -nil-> s2
|
946
|
+
# s1 <-a- s1
|
947
|
+
# s1<->a
|
948
|
+
fa = Automaton.new do |fa|
|
949
|
+
s0 = fa.add_state(:initial => true)
|
950
|
+
s1, s2 = fa.add_state, fa.add_state
|
951
|
+
fa.connect(s0,s1,'a')
|
952
|
+
fa.connect(s1,s1,'a')
|
953
|
+
fa.connect(s1,s2,nil)
|
954
|
+
fa.connect(s2,s1,'a')
|
955
|
+
end
|
956
|
+
assert_equal(false, fa.deterministic?)
|
957
|
+
assert_equal([s1,s2], s0.delta('a').sort)
|
958
|
+
assert_equal([s1,s2], s1.delta('a').sort)
|
959
|
+
assert_equal([s1,s2], s2.delta('a').sort)
|
960
|
+
|
961
|
+
# s0 -nil-> s1 -a-> s2 -nil-> s3
|
962
|
+
# s1 -a-> s4
|
963
|
+
fa = Automaton.new do |fa|
|
964
|
+
s0 = fa.add_state(:initial => true)
|
965
|
+
s1, s2, s3, s4 = fa.add_n_states(4)
|
966
|
+
fa.connect(s0,s1,nil)
|
967
|
+
fa.connect(s1,s2,'a')
|
968
|
+
fa.connect(s2,s3,nil)
|
969
|
+
fa.connect(s1,s4,'a')
|
970
|
+
end
|
971
|
+
assert_equal(false, fa.deterministic?)
|
972
|
+
assert_equal([s1], s0.delta(nil))
|
973
|
+
assert_equal([s2,s3,s4], s0.delta('a').sort)
|
974
|
+
assert_equal([s2,s3,s4], s1.delta('a').sort)
|
975
|
+
end
|
976
|
+
|
977
|
+
# Tests State#dfa_delta on a deterministic automaton
|
978
|
+
def test_state_dfa_delta_on_deterministic
|
979
|
+
fa, s0, s1, s2 = nil
|
980
|
+
fa = Automaton.new do |fa|
|
981
|
+
s0 = fa.add_state(:initial => true)
|
982
|
+
s1, s2 = fa.add_state, fa.add_state
|
983
|
+
fa.connect(s0, s1, 'a')
|
984
|
+
fa.connect(s0, s2, 'b')
|
985
|
+
fa.connect(s1, s0, 'b')
|
986
|
+
fa.connect(s1, s2, 'c')
|
987
|
+
end
|
988
|
+
assert_equal(true, fa.deterministic?)
|
989
|
+
|
990
|
+
# letting state choose its data-structure
|
991
|
+
assert_equal(s1, s0.dfa_delta('a'))
|
992
|
+
assert_equal(s2, s0.dfa_delta('b'))
|
993
|
+
assert_equal(nil, s0.dfa_delta('c'))
|
994
|
+
assert_equal(s0, s1.dfa_delta('b'))
|
995
|
+
assert_equal(s2, s1.dfa_delta('c'))
|
996
|
+
end
|
997
|
+
|
998
|
+
# Tests State#epsilon_closure
|
999
|
+
def test_epsilon_closure_on_non_deterministic_automaton
|
1000
|
+
s0, s1, s2, s3, s4 = nil
|
1001
|
+
fa = Automaton.new do |fa|
|
1002
|
+
s0 = fa.add_state(:initial => true) #
|
1003
|
+
s1, s2, s3, s4 = fa.add_n_states(4) # s1 -b-> s3
|
1004
|
+
fa.connect(s0, s1, 'a') # a
|
1005
|
+
fa.connect(s0, s2, 'a') # s0
|
1006
|
+
fa.connect(s1, s3, 'b') # a
|
1007
|
+
fa.connect(s2, s4, 'c') # s2 -c-> s4
|
1008
|
+
end #
|
1009
|
+
fa.states.each do |s|
|
1010
|
+
assert_equal([s], s.epsilon_closure)
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
fa.connect(s2, s2, 'b')
|
1014
|
+
assert_equal([s2], s2.delta('b'))
|
1015
|
+
|
1016
|
+
fa.connect(s2, s1, nil)
|
1017
|
+
assert_equal([s1], s2.step(nil))
|
1018
|
+
assert_equal([s1,s2], s2.epsilon_closure.sort)
|
1019
|
+
assert_equal([s1,s2,s3], s2.delta('b').sort)
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
# Tests Walking#walk on a non-deterministic automaton.
|
1023
|
+
def test_state_delta_on_non_deterministic_automaton_from_walkbug
|
1024
|
+
s0, s1, s2, s3, s4 = nil
|
1025
|
+
fa = Automaton.new do |fa|
|
1026
|
+
s0 = fa.add_state(:initial => true)
|
1027
|
+
s1, s2, s3, s4 = fa.add_n_states(4)
|
1028
|
+
fa.connect(s0, s1, 'a')
|
1029
|
+
fa.connect(s0, s2, 'a')
|
1030
|
+
fa.connect(s1, s3, 'b')
|
1031
|
+
fa.connect(s2, s4, 'c')
|
1032
|
+
fa.connect(s2, s2, 'b')
|
1033
|
+
fa.connect(s2, s1, nil)
|
1034
|
+
end
|
1035
|
+
assert_equal([s1,s2,s3], s2.delta('b').sort)
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
### Dup test section ###########################################################
|
1039
|
+
|
1040
|
+
def test_automaton_can_be_duplicated
|
1041
|
+
dup = @small_dfa.dup
|
1042
|
+
assert_equal @small_dfa.state_count, dup.state_count
|
1043
|
+
assert_equal @small_dfa.edge_count, dup.edge_count
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
### Alphabet test section ######################################################
|
1047
|
+
|
1048
|
+
def test_alphabet_on_examples
|
1049
|
+
assert_equal ['a', 'b', 'c'], @small_dfa.alphabet
|
1050
|
+
assert_equal ['a', 'b', 'c'], @small_nfa.alphabet
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def test_valid_alphabet_may_be_set
|
1054
|
+
dfa = @small_dfa.dup
|
1055
|
+
dfa.alphabet = ['c', 'a', 'b', 'z']
|
1056
|
+
assert_equal ['a','b','c','z'], dfa.alphabet
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
def test_invalid_alphabet_cannot_be_set
|
1060
|
+
dfa = @small_dfa.dup
|
1061
|
+
assert_raise ArgumentError do
|
1062
|
+
dfa.alphabet = ['a', 'b']
|
1063
|
+
end
|
1064
|
+
assert_raise ArgumentError do
|
1065
|
+
dfa.alphabet = ['a', 'a', 'b']
|
1066
|
+
end
|
1067
|
+
assert_raise ArgumentError do
|
1068
|
+
dfa.alphabet = ['a', 'b', nil]
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
### tests initial state cache ##################################################
|
1073
|
+
def test_initial_state_cache_works_correctly
|
1074
|
+
dfa = Stamina::ADL.parse_automaton <<-EOF
|
1075
|
+
2 2
|
1076
|
+
0 true false
|
1077
|
+
1 false true
|
1078
|
+
0 1 a
|
1079
|
+
1 0 b
|
1080
|
+
EOF
|
1081
|
+
initial, other = dfa.ith_state(0), dfa.ith_state(1)
|
1082
|
+
assert_equal initial, dfa.initial_state
|
1083
|
+
initial[:hello] = "world"
|
1084
|
+
assert_equal initial, dfa.initial_state
|
1085
|
+
dfa.ith_state(0)[:initial] = false
|
1086
|
+
dfa.ith_state(1)[:initial] = true
|
1087
|
+
assert_equal other, dfa.initial_state
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
end # module Stamina
|