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.
Files changed (80) hide show
  1. data/.gemtest +0 -0
  2. data/CHANGELOG.md +22 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +33 -0
  5. data/LICENCE.md +22 -0
  6. data/Manifest.txt +16 -0
  7. data/README.md +78 -0
  8. data/Rakefile +23 -0
  9. data/bin/adl2dot +12 -0
  10. data/bin/classify +12 -0
  11. data/bin/redblue +12 -0
  12. data/bin/rpni +12 -0
  13. data/example/adl/automaton.adl +49 -0
  14. data/example/adl/sample.adl +53 -0
  15. data/example/basic/characteristic_sample.adl +32 -0
  16. data/example/basic/target.adl +9 -0
  17. data/example/competition/31_test.adl +1500 -0
  18. data/example/competition/31_training.adl +1759 -0
  19. data/lib/stamina.rb +19 -0
  20. data/lib/stamina/adl.rb +298 -0
  21. data/lib/stamina/automaton.rb +1237 -0
  22. data/lib/stamina/automaton/walking.rb +336 -0
  23. data/lib/stamina/classifier.rb +37 -0
  24. data/lib/stamina/command/adl2dot_command.rb +73 -0
  25. data/lib/stamina/command/classify_command.rb +57 -0
  26. data/lib/stamina/command/redblue_command.rb +58 -0
  27. data/lib/stamina/command/rpni_command.rb +58 -0
  28. data/lib/stamina/command/stamina_command.rb +79 -0
  29. data/lib/stamina/errors.rb +20 -0
  30. data/lib/stamina/induction/commons.rb +170 -0
  31. data/lib/stamina/induction/redblue.rb +264 -0
  32. data/lib/stamina/induction/rpni.rb +188 -0
  33. data/lib/stamina/induction/union_find.rb +377 -0
  34. data/lib/stamina/input_string.rb +123 -0
  35. data/lib/stamina/loader.rb +0 -0
  36. data/lib/stamina/markable.rb +42 -0
  37. data/lib/stamina/sample.rb +190 -0
  38. data/lib/stamina/version.rb +14 -0
  39. data/stamina.gemspec +190 -0
  40. data/stamina.noespec +35 -0
  41. data/tasks/debug_mail.rake +78 -0
  42. data/tasks/debug_mail.txt +13 -0
  43. data/tasks/gem.rake +68 -0
  44. data/tasks/spec_test.rake +79 -0
  45. data/tasks/unit_test.rake +77 -0
  46. data/tasks/yard.rake +51 -0
  47. data/test/stamina/adl_test.rb +491 -0
  48. data/test/stamina/automaton_additional_test.rb +190 -0
  49. data/test/stamina/automaton_classifier_test.rb +155 -0
  50. data/test/stamina/automaton_test.rb +1092 -0
  51. data/test/stamina/automaton_to_dot_test.rb +64 -0
  52. data/test/stamina/automaton_walking_test.rb +206 -0
  53. data/test/stamina/exit.rb +3 -0
  54. data/test/stamina/induction/induction_test.rb +70 -0
  55. data/test/stamina/induction/redblue_mergesamestatebug_expected.adl +19 -0
  56. data/test/stamina/induction/redblue_mergesamestatebug_pta.dot +64 -0
  57. data/test/stamina/induction/redblue_mergesamestatebug_sample.adl +9 -0
  58. data/test/stamina/induction/redblue_test.rb +83 -0
  59. data/test/stamina/induction/redblue_universal_expected.adl +4 -0
  60. data/test/stamina/induction/redblue_universal_sample.adl +5 -0
  61. data/test/stamina/induction/rpni_inria_expected.adl +7 -0
  62. data/test/stamina/induction/rpni_inria_sample.adl +9 -0
  63. data/test/stamina/induction/rpni_test.rb +129 -0
  64. data/test/stamina/induction/rpni_test_pta.dot +22 -0
  65. data/test/stamina/induction/rpni_universal_expected.adl +4 -0
  66. data/test/stamina/induction/rpni_universal_sample.adl +4 -0
  67. data/test/stamina/induction/union_find_test.rb +124 -0
  68. data/test/stamina/input_string_test.rb +323 -0
  69. data/test/stamina/markable_test.rb +70 -0
  70. data/test/stamina/randdfa.adl +66 -0
  71. data/test/stamina/sample.adl +4 -0
  72. data/test/stamina/sample_classify_test.rb +149 -0
  73. data/test/stamina/sample_test.rb +218 -0
  74. data/test/stamina/small_dfa.dot +16 -0
  75. data/test/stamina/small_dfa.gif +0 -0
  76. data/test/stamina/small_nfa.dot +18 -0
  77. data/test/stamina/small_nfa.gif +0 -0
  78. data/test/stamina/stamina_test.rb +69 -0
  79. data/test/test_all.rb +7 -0
  80. 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