stamina 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gemtest +0 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +33 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +16 -0
- data/README.md +78 -0
- data/Rakefile +23 -0
- data/bin/adl2dot +12 -0
- data/bin/classify +12 -0
- data/bin/redblue +12 -0
- data/bin/rpni +12 -0
- data/example/adl/automaton.adl +49 -0
- data/example/adl/sample.adl +53 -0
- data/example/basic/characteristic_sample.adl +32 -0
- data/example/basic/target.adl +9 -0
- data/example/competition/31_test.adl +1500 -0
- data/example/competition/31_training.adl +1759 -0
- data/lib/stamina.rb +19 -0
- data/lib/stamina/adl.rb +298 -0
- data/lib/stamina/automaton.rb +1237 -0
- data/lib/stamina/automaton/walking.rb +336 -0
- data/lib/stamina/classifier.rb +37 -0
- data/lib/stamina/command/adl2dot_command.rb +73 -0
- data/lib/stamina/command/classify_command.rb +57 -0
- data/lib/stamina/command/redblue_command.rb +58 -0
- data/lib/stamina/command/rpni_command.rb +58 -0
- data/lib/stamina/command/stamina_command.rb +79 -0
- data/lib/stamina/errors.rb +20 -0
- data/lib/stamina/induction/commons.rb +170 -0
- data/lib/stamina/induction/redblue.rb +264 -0
- data/lib/stamina/induction/rpni.rb +188 -0
- data/lib/stamina/induction/union_find.rb +377 -0
- data/lib/stamina/input_string.rb +123 -0
- data/lib/stamina/loader.rb +0 -0
- data/lib/stamina/markable.rb +42 -0
- data/lib/stamina/sample.rb +190 -0
- data/lib/stamina/version.rb +14 -0
- data/stamina.gemspec +190 -0
- data/stamina.noespec +35 -0
- data/tasks/debug_mail.rake +78 -0
- data/tasks/debug_mail.txt +13 -0
- data/tasks/gem.rake +68 -0
- data/tasks/spec_test.rake +79 -0
- data/tasks/unit_test.rake +77 -0
- data/tasks/yard.rake +51 -0
- data/test/stamina/adl_test.rb +491 -0
- data/test/stamina/automaton_additional_test.rb +190 -0
- data/test/stamina/automaton_classifier_test.rb +155 -0
- data/test/stamina/automaton_test.rb +1092 -0
- data/test/stamina/automaton_to_dot_test.rb +64 -0
- data/test/stamina/automaton_walking_test.rb +206 -0
- data/test/stamina/exit.rb +3 -0
- data/test/stamina/induction/induction_test.rb +70 -0
- data/test/stamina/induction/redblue_mergesamestatebug_expected.adl +19 -0
- data/test/stamina/induction/redblue_mergesamestatebug_pta.dot +64 -0
- data/test/stamina/induction/redblue_mergesamestatebug_sample.adl +9 -0
- data/test/stamina/induction/redblue_test.rb +83 -0
- data/test/stamina/induction/redblue_universal_expected.adl +4 -0
- data/test/stamina/induction/redblue_universal_sample.adl +5 -0
- data/test/stamina/induction/rpni_inria_expected.adl +7 -0
- data/test/stamina/induction/rpni_inria_sample.adl +9 -0
- data/test/stamina/induction/rpni_test.rb +129 -0
- data/test/stamina/induction/rpni_test_pta.dot +22 -0
- data/test/stamina/induction/rpni_universal_expected.adl +4 -0
- data/test/stamina/induction/rpni_universal_sample.adl +4 -0
- data/test/stamina/induction/union_find_test.rb +124 -0
- data/test/stamina/input_string_test.rb +323 -0
- data/test/stamina/markable_test.rb +70 -0
- data/test/stamina/randdfa.adl +66 -0
- data/test/stamina/sample.adl +4 -0
- data/test/stamina/sample_classify_test.rb +149 -0
- data/test/stamina/sample_test.rb +218 -0
- data/test/stamina/small_dfa.dot +16 -0
- data/test/stamina/small_dfa.gif +0 -0
- data/test/stamina/small_nfa.dot +18 -0
- data/test/stamina/small_nfa.gif +0 -0
- data/test/stamina/stamina_test.rb +69 -0
- data/test/test_all.rb +7 -0
- metadata +279 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stamina'
|
3
|
+
module Stamina
|
4
|
+
module Utils
|
5
|
+
class DotTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@automaton = Automaton.new do |a|
|
9
|
+
add_state(:initial => true, :accepting => false)
|
10
|
+
add_state(:initial => false, :accepting => true)
|
11
|
+
add_state(:initial => false, :accepting => true, :error => true)
|
12
|
+
connect(0, 1, 'a')
|
13
|
+
connect(1, 0, 'b')
|
14
|
+
connect(1, 2, 'a')
|
15
|
+
connect(2, 2, nil)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_attributes2dot
|
20
|
+
attrs = {:label => 'hello'}
|
21
|
+
assert_equal 'label="hello"', @automaton.send(:attributes2dot, attrs)
|
22
|
+
attrs = {:label => 'hello', :color => 'red'}
|
23
|
+
assert_equal 'color="red" label="hello"', @automaton.send(:attributes2dot, attrs)
|
24
|
+
attrs = {:label => 'O"Neil'}
|
25
|
+
assert_equal 'label="O\"Neil"', @automaton.send(:attributes2dot, attrs)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_automaton_to_dot_with_default_rewriter
|
29
|
+
expected = <<-EOF
|
30
|
+
#digraph G {
|
31
|
+
# graph [rankdir="LR"];
|
32
|
+
# 0 [color="black" fillcolor="green" shape="circle" style="filled"];
|
33
|
+
# 1 [color="black" fillcolor="white" shape="doublecircle" style="filled"];
|
34
|
+
# 2 [color="black" fillcolor="red" shape="doublecircle" style="filled"];
|
35
|
+
# 0 -> 1 [label="a"];
|
36
|
+
# 1 -> 0 [label="b"];
|
37
|
+
# 1 -> 2 [label="a"];
|
38
|
+
# 2 -> 2 [label=""];
|
39
|
+
#}
|
40
|
+
EOF
|
41
|
+
expected = expected.gsub(/^\s+#/,'')
|
42
|
+
assert_equal expected, @automaton.to_dot
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_automaton_with_specific_rewriter
|
46
|
+
expected = <<-EOF
|
47
|
+
#digraph G {
|
48
|
+
# graph [];
|
49
|
+
# 0 [accepting="false" initial="true"];
|
50
|
+
# 1 [accepting="true" initial="false"];
|
51
|
+
# 2 [accepting="true" error="true" initial="false"];
|
52
|
+
# 0 -> 1 [symbol="a"];
|
53
|
+
# 1 -> 0 [symbol="b"];
|
54
|
+
# 1 -> 2 [symbol="a"];
|
55
|
+
# 2 -> 2 [symbol=""];
|
56
|
+
#}
|
57
|
+
EOF
|
58
|
+
expected = expected.gsub(/^\s+#/,'')
|
59
|
+
assert_equal expected, @automaton.to_dot {|elm,kind| elm.data}
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stamina/stamina_test'
|
3
|
+
module Stamina
|
4
|
+
class Automaton
|
5
|
+
# Tests Walking module on Automaton class
|
6
|
+
class WalkingTest < StaminaTest
|
7
|
+
|
8
|
+
# Tests Walking#step on examples
|
9
|
+
def test_step_on_examples
|
10
|
+
assert_equal([], @small_dfa.step(0, 'b'))
|
11
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.step(0, 'a'))
|
12
|
+
assert_equal(@small_dfa.ith_states(1,3), @small_dfa.step([0,1], 'a').sort)
|
13
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.step([0,2], 'a').sort)
|
14
|
+
|
15
|
+
assert_equal([], @small_nfa.step(0, 'b'))
|
16
|
+
assert_equal(@small_nfa.ith_states(1), @small_nfa.step(0, 'a'))
|
17
|
+
assert_equal([], @small_nfa.step(2, 'b'))
|
18
|
+
assert_equal(@small_nfa.ith_states(2,3), @small_nfa.step(1, 'b').sort)
|
19
|
+
assert_equal(@small_nfa.ith_states(0,1), @small_nfa.step([0,3], 'a').sort)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Tests Walking#dfa_step on examples
|
23
|
+
def test_step_on_examples
|
24
|
+
assert_equal(nil, @small_dfa.dfa_step(0, 'b'))
|
25
|
+
assert_equal(@small_dfa.ith_state(1), @small_dfa.dfa_step(0, 'a'))
|
26
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.dfa_step([0], 'a'))
|
27
|
+
assert_equal(@small_dfa.ith_states(1,3), @small_dfa.dfa_step([0,1], 'a').sort)
|
28
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.dfa_step([0,2], 'a').sort)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Tests Walking#delta on examples
|
32
|
+
def test_delta_on_examples
|
33
|
+
assert_equal([], @small_dfa.delta(0, 'b'))
|
34
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.delta(0, 'a'))
|
35
|
+
assert_equal(@small_dfa.ith_states(1,3), @small_dfa.delta([0,1], 'a').sort)
|
36
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.delta([0,2], 'a').sort)
|
37
|
+
|
38
|
+
assert_equal([], @small_nfa.delta(0, 'b'))
|
39
|
+
assert_equal(@small_nfa.ith_states(1), @small_nfa.delta(0, 'a'))
|
40
|
+
assert_equal(@small_nfa.ith_states(1,2,3), @small_nfa.delta(2, 'b').sort)
|
41
|
+
assert_equal(@small_nfa.ith_states(1,2,3), @small_nfa.delta(1, 'b').sort)
|
42
|
+
assert_equal(@small_nfa.ith_states(0,1), @small_nfa.delta([0,3], 'a').sort)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Tests Walking#dfa_delta on examples
|
46
|
+
def test_delta_on_examples
|
47
|
+
assert_equal(nil, @small_dfa.dfa_delta(0, 'b'))
|
48
|
+
assert_equal(@small_dfa.ith_state(1), @small_dfa.dfa_delta(0, 'a'))
|
49
|
+
assert_equal(@small_dfa.ith_states(1,3), @small_dfa.dfa_delta([0,1], 'a').sort)
|
50
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.dfa_delta([0,2], 'a').sort)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Tests Walking#split on examples
|
54
|
+
def test_split_on_examples
|
55
|
+
assert_equal([[], @small_dfa.ith_states(3), []], @small_dfa.split('?'))
|
56
|
+
assert_equal([[], @small_dfa.ith_states(3), ['a']], @small_dfa.split('? a'))
|
57
|
+
assert_equal([['b'], @small_dfa.ith_states(2), []], @small_dfa.split('? b'))
|
58
|
+
assert_equal([['b'], @small_dfa.ith_states(2), ['a']], @small_dfa.split('? b a'))
|
59
|
+
assert_equal([['b','c'], @small_dfa.ith_states(0), []], @small_dfa.split('? b c'))
|
60
|
+
|
61
|
+
assert_equal([[], @small_nfa.ith_states(0,3), []], @small_nfa.split('?'))
|
62
|
+
assert_equal([[], @small_nfa.ith_states(0,3), ['b']], @small_nfa.split('? b'))
|
63
|
+
assert_equal([['a'], @small_nfa.ith_states(0,1), []], @small_nfa.split('? a',nil,true))
|
64
|
+
assert_equal([['a'], @small_nfa.ith_states(0,1), ['c']], @small_nfa.split('? a c',nil,true))
|
65
|
+
assert_equal([['a','b'], @small_nfa.ith_states(1,2,3), []], @small_nfa.split('? a b',nil,true))
|
66
|
+
end
|
67
|
+
|
68
|
+
# Tests Walking#dfa_split on examples
|
69
|
+
def test_split_on_examples
|
70
|
+
assert_equal([[], @small_dfa.ith_state(3), []], @small_dfa.dfa_split('?'))
|
71
|
+
assert_equal([[], @small_dfa.ith_state(3), ['a']], @small_dfa.dfa_split('? a'))
|
72
|
+
assert_equal([['b'], @small_dfa.ith_state(2), []], @small_dfa.dfa_split('? b'))
|
73
|
+
assert_equal([['b'], @small_dfa.ith_state(2), ['a']], @small_dfa.dfa_split('? b a'))
|
74
|
+
assert_equal([['b','c'], @small_dfa.ith_state(0), []], @small_dfa.dfa_split('? b c'))
|
75
|
+
assert_equal([['b','c'], @small_dfa.ith_states(0), []], @small_dfa.dfa_split('? b c',[3]))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Tests Walking#reached on examples
|
79
|
+
def test_reached_on_examples
|
80
|
+
assert_equal([], @small_dfa.reached('? a a'))
|
81
|
+
assert_equal(@small_dfa.ith_states(2), @small_dfa.reached('? b'))
|
82
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.reached('? b c a c'))
|
83
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.reached('? a c', @small_dfa.ith_state(0)))
|
84
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.reached('? a c',0))
|
85
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.reached('? a',[0]))
|
86
|
+
assert_equal(@small_dfa.ith_states(1,3), @small_dfa.reached('? a',[0,1]))
|
87
|
+
assert_equal(@small_dfa.ith_states(2), @small_dfa.reached('? b',[3,1]))
|
88
|
+
assert_equal(@small_dfa.ith_states(2), @small_dfa.reached('? b',[0,3,1]))
|
89
|
+
|
90
|
+
assert_equal(@small_nfa.ith_states(0,3), @small_nfa.reached('?').sort)
|
91
|
+
assert_equal(@small_nfa.ith_states(0,1), @small_nfa.reached('? a').sort)
|
92
|
+
assert_equal(@small_nfa.ith_states(1,2,3), @small_nfa.reached('? a b').sort)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Tests Walking#dfa_reached on examples
|
96
|
+
def test_dfa_reached_on_examples
|
97
|
+
assert_equal(nil, @small_dfa.dfa_reached('? a a'))
|
98
|
+
assert_equal(@small_dfa.ith_state(2), @small_dfa.dfa_reached('? b'))
|
99
|
+
assert_equal(@small_dfa.ith_state(1), @small_dfa.dfa_reached('? b c a c'))
|
100
|
+
assert_equal(@small_dfa.ith_state(1), @small_dfa.dfa_reached('? a c', @small_dfa.ith_state(0)))
|
101
|
+
assert_equal(@small_dfa.ith_state(1), @small_dfa.dfa_reached('? a c',0))
|
102
|
+
assert_equal(@small_dfa.ith_states(1), @small_dfa.dfa_reached('? a',[0]))
|
103
|
+
assert_equal(@small_dfa.ith_states(1,3), @small_dfa.dfa_reached('? a',[0,1]))
|
104
|
+
assert_equal(@small_dfa.ith_states(2), @small_dfa.dfa_reached('? b',[3,1]))
|
105
|
+
assert_equal(@small_dfa.ith_states(2), @small_dfa.dfa_reached('? b',[0,3,1]))
|
106
|
+
end
|
107
|
+
|
108
|
+
# Tests Walking#dfa_reached
|
109
|
+
def test_dfa_reached_on_simple_deterministic_automaton
|
110
|
+
s0, s1 = nil
|
111
|
+
fa = Automaton.new do |fa|
|
112
|
+
s0 = fa.add_state(:initial => true)
|
113
|
+
s1 = fa.add_state
|
114
|
+
fa.connect(s0, s1, 'a')
|
115
|
+
fa.connect(s1, s0, 'b')
|
116
|
+
end
|
117
|
+
assert_equal(s0, fa.dfa_reached('? '))
|
118
|
+
assert_equal(s1, fa.dfa_reached('? a'))
|
119
|
+
assert_equal(s0, fa.dfa_reached('? a b'))
|
120
|
+
assert_equal(s1, fa.dfa_reached('? a b a'))
|
121
|
+
assert_equal(s0, fa.dfa_reached('? a b a b'))
|
122
|
+
assert_nil(fa.dfa_reached('? a a'))
|
123
|
+
assert_nil(fa.dfa_reached('? b'))
|
124
|
+
assert_nil(fa.dfa_reached('? a b b'))
|
125
|
+
end
|
126
|
+
|
127
|
+
# Tests Walking#reached on a deterministic automaton
|
128
|
+
def test_reached_on_simple_deterministic_automaton
|
129
|
+
s0, s1 = nil
|
130
|
+
fa = Automaton.new do |fa|
|
131
|
+
s0 = fa.add_state(:initial => true)
|
132
|
+
s1 = fa.add_state
|
133
|
+
fa.connect(s0, s1, 'a')
|
134
|
+
fa.connect(s1, s0, 'b')
|
135
|
+
end
|
136
|
+
assert_equal([s0], fa.reached('?'))
|
137
|
+
assert_equal([s1], fa.reached('? a'))
|
138
|
+
assert_equal([s0], fa.reached('? a b'))
|
139
|
+
assert_equal([s1], fa.reached('? a b a'))
|
140
|
+
assert_equal([s0], fa.reached('? a b a b'))
|
141
|
+
assert_equal([], fa.reached('? a a'))
|
142
|
+
assert_equal([], fa.reached('? b'))
|
143
|
+
assert_equal([], fa.reached('? a b b'))
|
144
|
+
end
|
145
|
+
|
146
|
+
# Tests Walking#reached on a non-deterministic automaton.
|
147
|
+
def test_reached_on_non_deterministic_automaton
|
148
|
+
s0, s1, s2, s3, s4 = nil
|
149
|
+
fa = Automaton.new do |fa|
|
150
|
+
s0 = fa.add_state(:initial => true) #
|
151
|
+
s1, s2, s3, s4 = fa.add_n_states(4) # s1 -b-> s3
|
152
|
+
fa.connect(s0, s1, 'a') # a
|
153
|
+
fa.connect(s0, s2, 'a') # s0
|
154
|
+
fa.connect(s1, s3, 'b') # a
|
155
|
+
fa.connect(s2, s4, 'c') # s2 -c-> s4
|
156
|
+
end #
|
157
|
+
assert_equal([], s2.delta('b'))
|
158
|
+
assert_equal([s0], fa.reached('?'))
|
159
|
+
assert_equal([], fa.reached('? c'))
|
160
|
+
assert_equal([s1,s2], fa.reached('? a').sort)
|
161
|
+
assert_equal([s3], fa.reached('? a b'))
|
162
|
+
assert_equal([s4], fa.reached('? a c'))
|
163
|
+
assert_equal([s1,s2], fa.reached('? a').sort)
|
164
|
+
|
165
|
+
# add a looping b on s2
|
166
|
+
fa.connect(s2, s2, 'b')
|
167
|
+
assert_equal([s2,s3], fa.reached('? a b').sort)
|
168
|
+
|
169
|
+
# add an epsilon from s2 to s1
|
170
|
+
fa.connect(s2, s1, nil)
|
171
|
+
assert_equal([s1,s2], fa.reached('? a').sort)
|
172
|
+
assert_equal([s1,s2,s3], fa.reached('? a b').sort)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Tests Walking#accepts? and Walking#rejects?
|
176
|
+
def test_accepts_and_rejects
|
177
|
+
fa = Automaton.new do
|
178
|
+
add_state(:initial => true)
|
179
|
+
add_state(:accepting => true)
|
180
|
+
add_state(:error => true)
|
181
|
+
add_state(:accepting => true, :error => true)
|
182
|
+
connect(0,1,'a')
|
183
|
+
connect(1,0,'b')
|
184
|
+
connect(0,2,'b')
|
185
|
+
connect(1,3,'a')
|
186
|
+
end
|
187
|
+
assert_equal(false, fa.accepts?("?"))
|
188
|
+
assert_equal(true, fa.accepts?("? a"))
|
189
|
+
assert_equal(false, fa.accepts?("? a b"))
|
190
|
+
assert_equal(true, fa.accepts?("? a b a"))
|
191
|
+
assert_equal(false, fa.accepts?("? z"), "not accepts? on no state")
|
192
|
+
assert_equal(false, fa.accepts?("? b"), "not accepts? on non accepting error state")
|
193
|
+
assert_equal(false, fa.accepts?("? a a"), "not accepts? on accepting error state")
|
194
|
+
|
195
|
+
assert_equal(true, fa.rejects?("?"))
|
196
|
+
assert_equal(false, fa.rejects?("? a"))
|
197
|
+
assert_equal(true, fa.rejects?("? a b"))
|
198
|
+
assert_equal(false, fa.rejects?("? a b a"))
|
199
|
+
assert_equal(true, fa.rejects?("? z"), "rejects? on no state")
|
200
|
+
assert_equal(true, fa.rejects?("? b"), "rejects? on non accepting error state")
|
201
|
+
assert_equal(true, fa.rejects?("? a a"), "rejects? on accepting error state")
|
202
|
+
end
|
203
|
+
|
204
|
+
end # class WalkingTest
|
205
|
+
end # class Automaton
|
206
|
+
end # module Stamina
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stamina'
|
3
|
+
require 'stamina/induction/union_find'
|
4
|
+
require 'stamina/induction/commons'
|
5
|
+
module Stamina
|
6
|
+
module Induction
|
7
|
+
class InductionTest < Test::Unit::TestCase
|
8
|
+
include Stamina::Induction::Commons
|
9
|
+
|
10
|
+
# Asserts that two states are equivalent and recurse.
|
11
|
+
def equivalent_states!(s1, s2, equivalences)
|
12
|
+
return "#{s1.index} and #{s2.index} don't agree on flags" \
|
13
|
+
unless s1.initial? == s2.initial? \
|
14
|
+
and s1.accepting? == s2.accepting? \
|
15
|
+
and s1.error? == s2.error?
|
16
|
+
return "#{s1.index} and #{s2.index} don't agree on out symbols #{s1.out_symbols.inspect} #{s2.out_symbols.inspect}"\
|
17
|
+
unless s1.out_symbols.sort == s2.out_symbols.sort
|
18
|
+
equivalences[s1.index] = s2.index
|
19
|
+
s1.out_symbols.each do |symbol|
|
20
|
+
s1_target = s1.dfa_step(symbol)
|
21
|
+
s2_target = s2.dfa_step(symbol)
|
22
|
+
return false if (s1_target.nil? or s2_target.nil?)
|
23
|
+
if equivalences.has_key?(s1_target.index)
|
24
|
+
return "#{s1.index} and #{s2.index} don't agree on #{symbol}"\
|
25
|
+
unless equivalences[s1_target.index]==s2_target.index
|
26
|
+
else
|
27
|
+
return msg \
|
28
|
+
if msg=equivalent_states!(s1_target, s2_target, equivalences)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks if two DFAs are equivalent.
|
35
|
+
def equivalent?(dfa1, dfa2)
|
36
|
+
return "not same number of states" unless dfa1.state_count==dfa2.state_count
|
37
|
+
equivalent_states!(dfa1.initial_state, dfa2.initial_state, {})
|
38
|
+
end
|
39
|
+
|
40
|
+
# Puts a PTA under @pta
|
41
|
+
def setup
|
42
|
+
@sample = Stamina::ADL.parse_sample <<-EOF
|
43
|
+
+
|
44
|
+
- a
|
45
|
+
- a a
|
46
|
+
+ a b
|
47
|
+
- b a b a
|
48
|
+
+ b a b b
|
49
|
+
+ b b
|
50
|
+
EOF
|
51
|
+
@pta = sample2pta(@sample)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns index-th state of the PTA
|
55
|
+
def s(index)
|
56
|
+
@pta.ith_state(index)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Factors a UnionFind instance from the PTA under @pta.
|
60
|
+
def factor_ufds
|
61
|
+
pta2ufds(@pta)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Just to avoid a stupid ruby error on empty test units.
|
65
|
+
def test_empty
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end # module Induction
|
70
|
+
end # module Stamina
|
@@ -0,0 +1,64 @@
|
|
1
|
+
digraph G {
|
2
|
+
graph [rankdir="LR"];
|
3
|
+
0 [color="black" fillcolor="green" shape="circle" style="filled"];
|
4
|
+
1 [color="black" fillcolor="white" shape="doublecircle" style="filled"];
|
5
|
+
2 [color="black" fillcolor="white" shape="circle" style="filled"];
|
6
|
+
3 [color="black" fillcolor="white" shape="circle" style="filled"];
|
7
|
+
4 [color="black" fillcolor="white" shape="circle" style="filled"];
|
8
|
+
5 [color="black" fillcolor="white" shape="circle" style="filled"];
|
9
|
+
6 [color="black" fillcolor="white" shape="circle" style="filled"];
|
10
|
+
7 [color="black" fillcolor="white" shape="circle" style="filled"];
|
11
|
+
8 [color="black" fillcolor="white" shape="circle" style="filled"];
|
12
|
+
9 [color="black" fillcolor="white" shape="circle" style="filled"];
|
13
|
+
10 [color="black" fillcolor="white" shape="circle" style="filled"];
|
14
|
+
11 [color="black" fillcolor="white" shape="circle" style="filled"];
|
15
|
+
12 [color="black" fillcolor="red" shape="circle" style="filled"];
|
16
|
+
13 [color="black" fillcolor="white" shape="circle" style="filled"];
|
17
|
+
14 [color="black" fillcolor="white" shape="circle" style="filled"];
|
18
|
+
15 [color="black" fillcolor="red" shape="circle" style="filled"];
|
19
|
+
16 [color="black" fillcolor="red" shape="circle" style="filled"];
|
20
|
+
17 [color="black" fillcolor="white" shape="circle" style="filled"];
|
21
|
+
18 [color="black" fillcolor="red" shape="circle" style="filled"];
|
22
|
+
19 [color="black" fillcolor="white" shape="doublecircle" style="filled"];
|
23
|
+
20 [color="black" fillcolor="white" shape="circle" style="filled"];
|
24
|
+
21 [color="black" fillcolor="white" shape="circle" style="filled"];
|
25
|
+
22 [color="black" fillcolor="white" shape="doublecircle" style="filled"];
|
26
|
+
23 [color="black" fillcolor="white" shape="circle" style="filled"];
|
27
|
+
24 [color="black" fillcolor="white" shape="circle" style="filled"];
|
28
|
+
25 [color="black" fillcolor="white" shape="circle" style="filled"];
|
29
|
+
26 [color="black" fillcolor="white" shape="circle" style="filled"];
|
30
|
+
27 [color="black" fillcolor="white" shape="doublecircle" style="filled"];
|
31
|
+
28 [color="black" fillcolor="white" shape="circle" style="filled"];
|
32
|
+
29 [color="black" fillcolor="white" shape="circle" style="filled"];
|
33
|
+
30 [color="black" fillcolor="white" shape="doublecircle" style="filled"];
|
34
|
+
0 -> 2 [label="1"];
|
35
|
+
2 -> 4 [label="1"];
|
36
|
+
4 -> 7 [label="1"];
|
37
|
+
7 -> 11 [label="1"];
|
38
|
+
11 -> 15 [label="0"];
|
39
|
+
0 -> 1 [label="0"];
|
40
|
+
1 -> 3 [label="0"];
|
41
|
+
3 -> 6 [label="1"];
|
42
|
+
6 -> 10 [label="1"];
|
43
|
+
10 -> 14 [label="0"];
|
44
|
+
14 -> 18 [label="1"];
|
45
|
+
18 -> 20 [label="0"];
|
46
|
+
20 -> 22 [label="1"];
|
47
|
+
18 -> 21 [label="1"];
|
48
|
+
21 -> 23 [label="0"];
|
49
|
+
23 -> 24 [label="0"];
|
50
|
+
24 -> 26 [label="1"];
|
51
|
+
26 -> 28 [label="1"];
|
52
|
+
28 -> 29 [label="0"];
|
53
|
+
29 -> 30 [label="1"];
|
54
|
+
24 -> 25 [label="0"];
|
55
|
+
25 -> 27 [label="0"];
|
56
|
+
14 -> 17 [label="0"];
|
57
|
+
17 -> 19 [label="1"];
|
58
|
+
6 -> 9 [label="0"];
|
59
|
+
9 -> 13 [label="0"];
|
60
|
+
13 -> 16 [label="1"];
|
61
|
+
3 -> 5 [label="0"];
|
62
|
+
5 -> 8 [label="0"];
|
63
|
+
8 -> 12 [label="0"];
|
64
|
+
}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "induction_test")
|
2
|
+
module Stamina
|
3
|
+
module Induction
|
4
|
+
class RedBlueTest < Stamina::Induction::InductionTest
|
5
|
+
|
6
|
+
# Factors a ready to be tested RedBlue instance
|
7
|
+
def redblue(ufds)
|
8
|
+
redblue = Stamina::Induction::RedBlue.new(:verbose => false)
|
9
|
+
redblue.instance_eval do
|
10
|
+
@ufds = ufds
|
11
|
+
end
|
12
|
+
redblue
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_merge_and_determinize_score
|
16
|
+
redblue = redblue(factor_ufds)
|
17
|
+
assert_equal nil, redblue.merge_and_determinize_score(1, 0)
|
18
|
+
assert_equal 1, redblue.merge_and_determinize_score(1, 3)
|
19
|
+
assert_equal 1, redblue.merge_and_determinize_score(2, 0)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_main_whole_execution
|
23
|
+
ufds = factor_ufds
|
24
|
+
redblue = redblue(ufds)
|
25
|
+
assert_equal [0, 1, 0, 1, 0, 1, 0, 0, 1, 0], redblue.main(ufds).to_a
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_execute_whole_execution
|
29
|
+
expected = Stamina::ADL.parse_automaton <<-EOF
|
30
|
+
2 4
|
31
|
+
0 true true
|
32
|
+
1 false false
|
33
|
+
0 0 b
|
34
|
+
0 1 a
|
35
|
+
1 0 b
|
36
|
+
1 1 a
|
37
|
+
EOF
|
38
|
+
dfa = RedBlue.execute(@sample)
|
39
|
+
assert_equal true, @sample.correctly_classified_by?(dfa)
|
40
|
+
assert_equal @sample.signature, dfa.signature(@sample)
|
41
|
+
assert_nil equivalent?(expected, dfa)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_on_dedicated_examples
|
45
|
+
here = File.dirname(__FILE__)
|
46
|
+
Dir["#{here}/redblue_*_sample.adl"].each do |sample_file|
|
47
|
+
name = (/^redblue_(.*?)_sample.adl$/.match(File.basename(sample_file)))[1]
|
48
|
+
sample = Stamina::ADL.parse_sample_file(sample_file)
|
49
|
+
expected = Stamina::ADL.parse_automaton_file(File.join(here, "redblue_#{name}_expected.adl"))
|
50
|
+
assert sample.correctly_classified_by?(expected)
|
51
|
+
dfa = RedBlue.execute(sample)
|
52
|
+
assert sample.correctly_classified_by?(dfa)
|
53
|
+
assert_equal sample.signature, dfa.signature(sample)
|
54
|
+
assert_nil equivalent?(expected, dfa)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Tests on characteristic sample
|
59
|
+
def test_on_public_characteristic_example
|
60
|
+
example_folder = File.join(File.dirname(__FILE__), '..', '..', '..', 'example', 'basic')
|
61
|
+
sample = Stamina::ADL.parse_sample_file(File.join(example_folder, 'characteristic_sample.adl'))
|
62
|
+
redblued = Stamina::Induction::RedBlue.execute(sample)
|
63
|
+
assert_equal 4, redblued.state_count
|
64
|
+
s0, = redblued.initial_state
|
65
|
+
s1 = redblued.dfa_step(s0, 'b')
|
66
|
+
s2 = redblued.dfa_step(s0, 'a')
|
67
|
+
s3 = redblued.dfa_step(s2, 'b')
|
68
|
+
assert_equal true, s0.accepting?
|
69
|
+
assert_equal true, s3.accepting?
|
70
|
+
assert_equal false, s1.accepting?
|
71
|
+
assert_equal false, s2.accepting?
|
72
|
+
assert_equal s1, s1.dfa_step('a')
|
73
|
+
assert_equal s1, s1.dfa_step('b')
|
74
|
+
assert_equal s2, s2.dfa_step('a')
|
75
|
+
assert_equal s3, s2.dfa_step('b')
|
76
|
+
assert_equal s3, s3.dfa_step('b')
|
77
|
+
assert_equal s0, s3.dfa_step('a')
|
78
|
+
assert_equal sample.signature, redblued.signature(sample)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|