stamina 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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