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,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,3 @@
1
+ # This file is only used in the test, to check that some parsing method do not
2
+ # execute ruby code. If not the case, a SystemExit will be raised
3
+ + Kernel.exit(-1)
@@ -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,19 @@
1
+ 6 12
2
+ 0 true false
3
+ 1 false true
4
+ 2 false false
5
+ 3 false false
6
+ 4 false false
7
+ 5 false false
8
+ 0 1 0
9
+ 0 1 1
10
+ 1 2 0
11
+ 1 1 1
12
+ 2 0 0
13
+ 2 3 1
14
+ 3 4 0
15
+ 3 4 1
16
+ 4 5 0
17
+ 4 1 1
18
+ 5 0 0
19
+ 5 2 1
@@ -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,9 @@
1
+ - 1 1 1 1 0
2
+ + 0
3
+ - 0 0 1 1 0 1
4
+ + 0 0 1 1 0 1 0 1
5
+ + 0 0 1 1 0 1 1 0 0 1 1 0 1
6
+ + 0 0 1 1 0 1 1 0 0 0 0
7
+ + 0 0 1 1 0 0 1
8
+ - 0 0 1 0 0 1
9
+ - 0 0 0 0 0
@@ -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