stamina 0.3.0 → 0.3.1
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/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/lib/stamina.rb +2 -0
- data/lib/stamina/automaton.rb +2 -1
- data/lib/stamina/automaton/metrics.rb +71 -0
- data/lib/stamina/classifier.rb +16 -1
- data/lib/stamina/scoring.rb +176 -0
- data/lib/stamina/utils.rb +1 -0
- data/lib/stamina/utils/decorate.rb +81 -0
- data/lib/stamina/version.rb +1 -1
- data/stamina.noespec +1 -1
- data/test/stamina/{automaton_classifier_test.rb → automaton/classifier_test.rb} +105 -1
- data/test/stamina/automaton/metrics_test.rb +36 -0
- data/test/stamina/{automaton_to_dot_test.rb → automaton/to_dot_test.rb} +0 -0
- data/test/stamina/{automaton_walking_test.rb → automaton/walking_test.rb} +0 -0
- data/test/stamina/sample_test.rb +203 -206
- data/test/stamina/scoring_test.rb +63 -0
- data/test/stamina/utils/decorate_test.rb +65 -0
- metadata +19 -9
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
# 0.3.1 / 2011-03-24
|
2
|
+
|
3
|
+
* Major Enhancements
|
4
|
+
|
5
|
+
* Implemented the decoration algorithm of Damas10, allowing to decorate states
|
6
|
+
with information propagated from states to states until a fixpoint is reached.
|
7
|
+
* Added Automaton::Metrics module, automatically included, with useful metrics
|
8
|
+
like automaton depth, accepting ratio and so on.
|
9
|
+
* Added Scoring module and Classifier#classification_scoring(sample) method
|
10
|
+
with common measures from information retrieval.
|
11
|
+
|
12
|
+
* On the devel side
|
13
|
+
|
14
|
+
* Moved specific automaton tests under test/stamina/automaton/...
|
15
|
+
|
1
16
|
# 0.3.0 / 2011-03-24
|
2
17
|
|
3
18
|
* On the devel side
|
data/Gemfile.lock
CHANGED
data/lib/stamina.rb
CHANGED
@@ -13,6 +13,8 @@ require 'stamina/sample'
|
|
13
13
|
require 'stamina/input_string'
|
14
14
|
require 'stamina/classifier'
|
15
15
|
require 'stamina/automaton'
|
16
|
+
require 'stamina/scoring'
|
17
|
+
require 'stamina/utils'
|
16
18
|
require 'stamina/induction/union_find'
|
17
19
|
require 'stamina/induction/commons'
|
18
20
|
require "stamina/induction/rpni"
|
data/lib/stamina/automaton.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'stamina/utils/decorate'
|
2
|
+
module Stamina
|
3
|
+
class Automaton
|
4
|
+
#
|
5
|
+
# Provides useful metric methods on automata.
|
6
|
+
#
|
7
|
+
# This module is automatically included by Automaton and is not intended
|
8
|
+
# to be used directly.
|
9
|
+
#
|
10
|
+
module Metrics
|
11
|
+
|
12
|
+
#
|
13
|
+
# Returns the number of letters of the alphabet.
|
14
|
+
#
|
15
|
+
def alphabet_size
|
16
|
+
alphabet.size
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Returns the average degree of states, that is,
|
21
|
+
# <code>edge_count/state_count</code>
|
22
|
+
#
|
23
|
+
def avg_degree
|
24
|
+
edge_count.to_f/state_count.to_f
|
25
|
+
end
|
26
|
+
alias :avg_out_degree :avg_degree
|
27
|
+
alias :avg_in_degree :avg_degree
|
28
|
+
|
29
|
+
#
|
30
|
+
# Number of accepting states over all states
|
31
|
+
#
|
32
|
+
def accepting_ratio
|
33
|
+
states.select{|s|s.accepting?}.size.to_f/state_count.to_f
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Number of error states over all states
|
38
|
+
#
|
39
|
+
def error_ratio
|
40
|
+
states.select{|s|s.error?}.size.to_f/state_count.to_f
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Computes the depth of the automaton.
|
45
|
+
#
|
46
|
+
# The depth of an automaton is defined as the length of the longest shortest
|
47
|
+
# path from the initial state to a state.
|
48
|
+
#
|
49
|
+
# This method has a side effect on state marks, as it keeps the depth of
|
50
|
+
# each state as a mark under _key_, which defaults to :depth.
|
51
|
+
#
|
52
|
+
def depth(key = :depth)
|
53
|
+
algo = Stamina::Utils::Decorate.new(key)
|
54
|
+
algo.set_suppremum do |d0,d1|
|
55
|
+
if d0.nil?
|
56
|
+
d1
|
57
|
+
elsif d1.nil?
|
58
|
+
d0
|
59
|
+
else
|
60
|
+
(d0 <= d1 ? d0 : d1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
algo.set_propagate {|d,e| d+1 }
|
64
|
+
algo.execute(self, nil, 0)
|
65
|
+
states.max{|s0,s1| s0[:depth] <=> s1[:depth]}[:depth]
|
66
|
+
end
|
67
|
+
|
68
|
+
end # module Metrics
|
69
|
+
include Metrics
|
70
|
+
end # class Automaton
|
71
|
+
end # module Stamina
|
data/lib/stamina/classifier.rb
CHANGED
@@ -20,6 +20,21 @@ module Stamina
|
|
20
20
|
end
|
21
21
|
signature
|
22
22
|
end
|
23
|
+
alias :classification_signature :signature
|
24
|
+
|
25
|
+
#
|
26
|
+
# Classifies a sample then compute the classification scoring that is obtained
|
27
|
+
# by comparing the signature obtained by classification and the one of the sample
|
28
|
+
# itself. Returns an object responding to methods defined in Scoring module.
|
29
|
+
#
|
30
|
+
# This method is actually a convenient shortcut for:
|
31
|
+
#
|
32
|
+
# Stamina::Scoring.scoring(signature(sample), sample.signature)
|
33
|
+
#
|
34
|
+
def scoring(sample)
|
35
|
+
Stamina::Scoring.scoring(signature(sample), sample.signature)
|
36
|
+
end
|
37
|
+
alias :classification_scoring :scoring
|
23
38
|
|
24
39
|
#
|
25
40
|
# Checks if a labeled sample is correctly classified by the classifier.
|
@@ -34,4 +49,4 @@ module Stamina
|
|
34
49
|
end
|
35
50
|
|
36
51
|
end # module Classifier
|
37
|
-
end # module Stamina
|
52
|
+
end # module Stamina
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module Stamina
|
2
|
+
#
|
3
|
+
# Provides utility methods for scoring binary classifiers from signatures
|
4
|
+
#
|
5
|
+
module Scoring
|
6
|
+
|
7
|
+
#
|
8
|
+
# From the signatures of a learned model and a actual, returns an object
|
9
|
+
# responding to all instance methods defined in the Scoring module.
|
10
|
+
#
|
11
|
+
def self.scoring(learned, actual, max_size=nil)
|
12
|
+
unless learned.size==actual.size
|
13
|
+
raise ArgumentError, "Signatures must be of same size (#{learned.size} vs. #{actual.size})"
|
14
|
+
end
|
15
|
+
max_size ||= learned.size
|
16
|
+
max_size = learned.size if max_size > learned.size
|
17
|
+
tp, fn, fp, tn = 0, 0, 0, 0
|
18
|
+
(0...max_size).each do |i|
|
19
|
+
positive, labeled_as = actual[i..i]=='1', learned[i..i]=='1'
|
20
|
+
if positive==labeled_as
|
21
|
+
positive ? (tp += 1) : (tn += 1)
|
22
|
+
else
|
23
|
+
positive ? (fn += 1) : (fp += 1)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
measures = { :true_positive => tp,
|
27
|
+
:true_negative => tn,
|
28
|
+
:false_positive => fp,
|
29
|
+
:false_negative => fn }
|
30
|
+
measures.extend(Scoring)
|
31
|
+
measures
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Returns the number of positive strings correctly labeled as positive
|
36
|
+
#
|
37
|
+
def true_positive
|
38
|
+
self[:true_positive]
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Returns the number of negative strings correctly labeled as negative.
|
43
|
+
#
|
44
|
+
def true_negative
|
45
|
+
self[:true_negative]
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Returns the number of negative strings incorrectly labeled as positive.
|
50
|
+
#
|
51
|
+
def false_positive
|
52
|
+
self[:false_positive]
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Returns the number of positive strings incorrectly labeled as negative.
|
57
|
+
#
|
58
|
+
def false_negative
|
59
|
+
self[:false_negative]
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Returns the percentage of positive predictions that are correct
|
64
|
+
#
|
65
|
+
def precision
|
66
|
+
true_positive.to_f/(true_positive + false_positive)
|
67
|
+
end
|
68
|
+
alias :positive_predictive_value :precision
|
69
|
+
|
70
|
+
#
|
71
|
+
# Returns the percentage of true negative over all negative
|
72
|
+
#
|
73
|
+
def negative_predictive_value
|
74
|
+
true_negative.to_f / (true_negative + false_negative)
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Returns the percentage of positive strings that were predicted as being
|
79
|
+
# positive
|
80
|
+
#
|
81
|
+
def recall
|
82
|
+
true_positive.to_f / (true_positive + false_negative)
|
83
|
+
end
|
84
|
+
alias :sensitivity :recall
|
85
|
+
alias :true_positive_rate :recall
|
86
|
+
|
87
|
+
#
|
88
|
+
# Returns the percentage of negative strings that were predicted as being
|
89
|
+
# negative
|
90
|
+
#
|
91
|
+
def specificity
|
92
|
+
true_negative.to_f / (true_negative + false_positive)
|
93
|
+
end
|
94
|
+
alias :true_negative_rate :specificity
|
95
|
+
|
96
|
+
#
|
97
|
+
# Returns the percentage of false positives
|
98
|
+
#
|
99
|
+
def false_positive_rate
|
100
|
+
false_positive.to_f / (false_positive + true_negative)
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Returns the percentage of false negatives
|
105
|
+
#
|
106
|
+
def false_negative_rate
|
107
|
+
false_negative.to_f / (true_positive + false_negative)
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Returns the likelihood that a predicted positive is an actual positive
|
112
|
+
#
|
113
|
+
def positive_likelihood
|
114
|
+
sensitivity / (1.0 - specificity)
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# Returns the likelihood that a predicted negative is an actual negative
|
119
|
+
#
|
120
|
+
def negative_likelihood
|
121
|
+
(1.0 - sensitivity) / specificity
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Returns the percentage of predictions that are correct
|
126
|
+
#
|
127
|
+
def accuracy
|
128
|
+
num = (true_positive + true_negative).to_f
|
129
|
+
den = (true_positive + true_negative + false_positive + false_negative)
|
130
|
+
num / den
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Returns the error rate
|
135
|
+
#
|
136
|
+
def error_rate
|
137
|
+
num = (false_positive + false_negative).to_f
|
138
|
+
den = (true_positive + true_negative + false_positive + false_negative)
|
139
|
+
num / den
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Returns the harmonic mean between precision and recall
|
144
|
+
#
|
145
|
+
def f_measure
|
146
|
+
2.0 * (precision * recall) / (precision + recall)
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# Returns the balanced classification rate (arithmetic mean between
|
151
|
+
# sensitivity and specificity)
|
152
|
+
#
|
153
|
+
def balanced_classification_rate
|
154
|
+
0.5 * (sensitivity + specificity)
|
155
|
+
end
|
156
|
+
alias :bcr :balanced_classification_rate
|
157
|
+
|
158
|
+
#
|
159
|
+
# Returns the balanced error rate (1 - bcr)
|
160
|
+
#
|
161
|
+
def balanced_error_rate
|
162
|
+
1.0 - balanced_classification_rate
|
163
|
+
end
|
164
|
+
alias :ber :balanced_error_rate
|
165
|
+
|
166
|
+
#
|
167
|
+
# Returns the harmonic mean between sensitivity and specificity
|
168
|
+
#
|
169
|
+
def harmonic_balanced_classification_rate
|
170
|
+
2.0 * (sensitivity * specificity) / (sensitivity + specificity)
|
171
|
+
end
|
172
|
+
alias :hbcr :harmonic_balanced_classification_rate
|
173
|
+
alias :harmonic_bcr :harmonic_balanced_classification_rate
|
174
|
+
|
175
|
+
end # module Scoring
|
176
|
+
end # module Stamina
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'stamina/utils/decorate'
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Stamina
|
2
|
+
module Utils
|
3
|
+
#
|
4
|
+
# Decorates states of an automaton by applying a propagation rule
|
5
|
+
# until a fix point is reached.
|
6
|
+
#
|
7
|
+
class Decorate
|
8
|
+
|
9
|
+
# The key to use to maintain the decoration on states (:invariant
|
10
|
+
# is used by default)
|
11
|
+
attr_writer :decoration_key
|
12
|
+
|
13
|
+
# Creates a decoration algorithm instance
|
14
|
+
def initialize(decoration_key = :invariant)
|
15
|
+
@decoration_key = decoration_key
|
16
|
+
@suppremum = nil
|
17
|
+
@propagate = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Installs a suppremum function through a block.
|
21
|
+
def set_suppremum(&block)
|
22
|
+
raise ArgumentError, 'Suppremum expected through a block' if block.nil?
|
23
|
+
raise ArgumentError, 'Block of arity 2 expected' unless block.arity==2
|
24
|
+
@suppremum = block
|
25
|
+
end
|
26
|
+
|
27
|
+
# Installs a propagate function through a block.
|
28
|
+
def set_propagate(&block)
|
29
|
+
raise ArgumentError, 'Propagate expected through a block' if block.nil?
|
30
|
+
raise ArgumentError, 'Block of arity 2 expected' unless block.arity==2
|
31
|
+
@propagate = block
|
32
|
+
end
|
33
|
+
|
34
|
+
# Computes the suppremum between two decorations. By default, this method
|
35
|
+
# looks for a suppremum function installed with set_suppremum. If not found,
|
36
|
+
# it tries calling a suppremum method on d0. If not found it raises an error.
|
37
|
+
# This method may be overriden.
|
38
|
+
def suppremum(d0, d1)
|
39
|
+
return @suppremum.call(d0, d1) if @suppremum
|
40
|
+
return d0.suppremum(d1) if d0.respond_to?(:suppremum)
|
41
|
+
raise "No suppremum function installed or implemented by decorations"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Computes the propagation rule. By default, this method looks for a propagate
|
45
|
+
# function installed with set_propagate. If not found, it tries calling a +
|
46
|
+
# method on deco. If not found it raises an error.
|
47
|
+
# This method may be overriden.
|
48
|
+
def propagate(deco, edge)
|
49
|
+
return @propagate.call(deco, edge) if @propagate
|
50
|
+
return deco.+(edge) if deco.respond_to?(:+)
|
51
|
+
raise "No propagate function installed or implemented by decorations"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Executes the propagation algorithm on a given automaton.
|
55
|
+
def execute(fa, bottom, d0)
|
56
|
+
# install initial decoration
|
57
|
+
fa.states.each do |s|
|
58
|
+
s[@decoration_key] = (s.initial? ? d0 : bottom)
|
59
|
+
end
|
60
|
+
|
61
|
+
# fix-point loop starting with initial states
|
62
|
+
to_explore = fa.initial_states
|
63
|
+
until to_explore.empty?
|
64
|
+
source = to_explore.pop
|
65
|
+
source.out_edges.each do |edge|
|
66
|
+
target = edge.target
|
67
|
+
p_decor = propagate(source[@decoration_key], edge)
|
68
|
+
p_decor = suppremum(target[@decoration_key], p_decor)
|
69
|
+
unless p_decor == target[@decoration_key]
|
70
|
+
target[@decoration_key] = p_decor
|
71
|
+
to_explore << target unless to_explore.include?(target)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
fa
|
77
|
+
end
|
78
|
+
|
79
|
+
end # class Decorate
|
80
|
+
end # module Utils
|
81
|
+
end # module Stamina
|
data/lib/stamina/version.rb
CHANGED
data/stamina.noespec
CHANGED
@@ -150,6 +150,110 @@ module Stamina
|
|
150
150
|
assert_equal(false, @small_nfa.correctly_classify?(sample))
|
151
151
|
end
|
152
152
|
|
153
|
+
def test_scoring_on_valid_sample
|
154
|
+
sample = ADL::parse_sample <<-SAMPLE
|
155
|
+
-
|
156
|
+
+ b
|
157
|
+
+ b c
|
158
|
+
- b c a
|
159
|
+
- b c a c
|
160
|
+
- b c a c a
|
161
|
+
- b c a a
|
162
|
+
+ b c a b
|
163
|
+
+ b c a b c a c b
|
164
|
+
- z
|
165
|
+
- b z
|
166
|
+
SAMPLE
|
167
|
+
measures = @small_dfa.scoring(sample)
|
168
|
+
assert_equal(sample.positive_count, measures.true_positive)
|
169
|
+
assert_equal(0, measures.false_positive)
|
170
|
+
assert_equal(sample.negative_count, measures.true_negative)
|
171
|
+
assert_equal(0, measures.false_negative)
|
172
|
+
assert_equal(1.0, measures.precision)
|
173
|
+
assert_equal(1.0, measures.recall)
|
174
|
+
assert_equal(1.0, measures.sensitivity)
|
175
|
+
assert_equal(1.0, measures.specificity)
|
176
|
+
assert_equal(1.0, measures.accuracy)
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_scoring_on_invalid_sample
|
180
|
+
sample = ADL::parse_sample <<-SAMPLE
|
181
|
+
+
|
182
|
+
- b
|
183
|
+
- b c
|
184
|
+
+ b c a
|
185
|
+
+ b c a c
|
186
|
+
+ b c a c a
|
187
|
+
+ b c a a
|
188
|
+
- b c a b
|
189
|
+
- b c a b c a c b
|
190
|
+
+ z
|
191
|
+
+ b z
|
192
|
+
SAMPLE
|
193
|
+
measures = @small_dfa.scoring(sample)
|
194
|
+
assert_equal(0.0, measures.true_positive)
|
195
|
+
assert_equal(sample.negative_count, measures.false_positive)
|
196
|
+
assert_equal(0.0, measures.true_negative)
|
197
|
+
assert_equal(sample.positive_count, measures.false_negative)
|
198
|
+
assert_equal(0.0, measures.precision)
|
199
|
+
assert_equal(0.0, measures.recall)
|
200
|
+
assert_equal(0.0, measures.sensitivity)
|
201
|
+
assert_equal(0.0, measures.specificity)
|
202
|
+
assert_equal(0.0, measures.accuracy)
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_scoring_with_positive_only
|
206
|
+
sample = ADL::parse_sample <<-SAMPLE
|
207
|
+
+
|
208
|
+
+ b
|
209
|
+
+ b c
|
210
|
+
+ b c a
|
211
|
+
+ b c a c
|
212
|
+
+ b c a c a
|
213
|
+
+ b c a a
|
214
|
+
+ b c a b
|
215
|
+
+ b c a b c a c b
|
216
|
+
+ z
|
217
|
+
+ b z
|
218
|
+
SAMPLE
|
219
|
+
measures = @small_dfa.scoring(sample)
|
220
|
+
assert_equal(4.0, measures.true_positive)
|
221
|
+
assert_equal(sample.size-sample.positive_count, measures.false_positive)
|
222
|
+
assert_equal(0, measures.true_negative)
|
223
|
+
assert_equal(sample.size-4.0, measures.false_negative)
|
224
|
+
assert_equal(1.0, measures.precision)
|
225
|
+
assert_equal(4.0/sample.size, measures.recall)
|
226
|
+
assert_equal(4.0/sample.size, measures.sensitivity)
|
227
|
+
#assert_equal(0.0/0.0, measures.specificity)
|
228
|
+
assert_equal(4.0/sample.size, measures.accuracy)
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_scoring_with_negative_only
|
232
|
+
sample = ADL::parse_sample <<-SAMPLE
|
233
|
+
-
|
234
|
+
- b
|
235
|
+
- b c
|
236
|
+
- b c a
|
237
|
+
- b c a c
|
238
|
+
- b c a c a
|
239
|
+
- b c a a
|
240
|
+
- b c a b
|
241
|
+
- b c a b c a c b
|
242
|
+
- z
|
243
|
+
- b z
|
244
|
+
SAMPLE
|
245
|
+
measures = @small_dfa.scoring(sample)
|
246
|
+
assert_equal(0.0, measures.true_positive)
|
247
|
+
assert_equal(4.0, measures.false_positive)
|
248
|
+
assert_equal(sample.size-4.0, measures.true_negative)
|
249
|
+
assert_equal(0.0, measures.false_negative)
|
250
|
+
assert_equal(0.0, measures.precision)
|
251
|
+
#assert_equal(0.0, measures.recall)
|
252
|
+
#assert_equal(0.0, measures.sensitivity)
|
253
|
+
assert_equal((sample.size-4.0)/sample.size, measures.specificity)
|
254
|
+
assert_equal((sample.size-4.0)/sample.size, measures.accuracy)
|
255
|
+
end
|
256
|
+
|
153
257
|
end # class ClassifierTest
|
154
258
|
end # class Automaton
|
155
|
-
end # module Stamina
|
259
|
+
end # module Stamina
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stamina/adl'
|
3
|
+
require 'stamina/stamina_test'
|
4
|
+
module Stamina
|
5
|
+
class Automaton
|
6
|
+
class MetricsTest < StaminaTest
|
7
|
+
|
8
|
+
def test_alphabet_size
|
9
|
+
assert_equal 3, @small_dfa.alphabet_size
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_avg_degree
|
13
|
+
assert_equal 6.to_f/4, @small_dfa.avg_degree
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_avg_out_degree
|
17
|
+
assert_equal 6.to_f/4, @small_dfa.avg_out_degree
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_avg_in_degree
|
21
|
+
assert_equal 6.to_f/4, @small_dfa.avg_in_degree
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_accepting_ratio
|
25
|
+
assert_equal 0.5, @small_dfa.accepting_ratio
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_depth
|
29
|
+
assert_equal 3, @small_dfa.depth
|
30
|
+
assert_equal 2, @small_nfa.depth
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
File without changes
|
File without changes
|
data/test/stamina/sample_test.rb
CHANGED
@@ -3,216 +3,213 @@ require 'stamina/errors'
|
|
3
3
|
require 'stamina/stamina_test'
|
4
4
|
require 'stamina/sample'
|
5
5
|
module Stamina
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
s << Sample['+ a b a b a b', '-']
|
84
|
-
assert_equal(expected,s)
|
85
|
-
end
|
86
|
-
|
87
|
-
# Tests that Sample#<< detects inconsistencies
|
88
|
-
# def test_append_detects_inconsistency
|
89
|
-
# s = Sample.new
|
90
|
-
# s << '+ a b'
|
91
|
-
# s << '+ a b a b'
|
92
|
-
# assert_raise InconsistencyError do
|
93
|
-
# s << '- a b a b'
|
94
|
-
# end
|
95
|
-
# end
|
96
|
-
|
97
|
-
# Tests that Sample#<< detects inconsistencies
|
98
|
-
def test_append_detects_real_inconsistencies_only
|
99
|
-
s = Sample.new
|
100
|
-
s << '+ a b'
|
101
|
-
s << '+ a b a b'
|
102
|
-
assert_nothing_raised do
|
103
|
-
s << '- b'
|
104
|
-
s << '- a'
|
105
|
-
s << '- a b a'
|
6
|
+
class SampleTest < StaminaTest
|
7
|
+
|
8
|
+
# Converts a String to an InputString
|
9
|
+
def s(str)
|
10
|
+
Stamina::ADL::parse_string(str)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Tests Sample#empty?
|
14
|
+
def test_empty
|
15
|
+
assert_equal(true, Sample.new.empty?)
|
16
|
+
assert_equal(true, Sample[].empty?)
|
17
|
+
assert_equal(false, Sample['?'].empty?)
|
18
|
+
assert_equal(false, Sample['-'].empty?)
|
19
|
+
assert_equal(false, Sample['+'].empty?)
|
20
|
+
assert_equal(false, Sample['+ a b'].empty?)
|
21
|
+
assert_equal(false, Sample['+ a b', '- a'].empty?)
|
22
|
+
assert_equal(false, Sample['- a b'].empty?)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Tests Sample#size
|
26
|
+
def test_size_and_counts
|
27
|
+
s = Sample.new
|
28
|
+
assert_equal(0, s.size)
|
29
|
+
assert_equal(0, s.positive_count)
|
30
|
+
assert_equal(0, s.negative_count)
|
31
|
+
s << '+ a b'
|
32
|
+
assert_equal(1, s.size)
|
33
|
+
assert_equal(1, s.positive_count)
|
34
|
+
assert_equal(0, s.negative_count)
|
35
|
+
s << '+ a b'
|
36
|
+
assert_equal(2, s.size)
|
37
|
+
assert_equal(2, s.positive_count)
|
38
|
+
assert_equal(0, s.negative_count)
|
39
|
+
s << '+ a'
|
40
|
+
assert_equal(3, s.size)
|
41
|
+
assert_equal(3, s.positive_count)
|
42
|
+
assert_equal(0, s.negative_count)
|
43
|
+
s << '- a b c'
|
44
|
+
assert_equal(4, s.size)
|
45
|
+
assert_equal(3, s.positive_count)
|
46
|
+
assert_equal(1, s.negative_count)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_same_string_can_be_added_many_times
|
50
|
+
s = Sample.new
|
51
|
+
10.times {|i| s << "+ a b"}
|
52
|
+
assert_equal(10, s.size)
|
53
|
+
assert_equal(10, s.positive_count)
|
54
|
+
assert_equal(0, s.negative_count)
|
55
|
+
strings = s.collect{|s| s}
|
56
|
+
assert_equal 10, strings.size
|
57
|
+
end
|
58
|
+
|
59
|
+
# Tests Sample#<<
|
60
|
+
def test_append
|
61
|
+
s = Sample.new
|
62
|
+
assert_equal(s,s << '+',"Accepts empty string")
|
63
|
+
assert_equal(s,s << '+ a b a b a',"Accepts positive string")
|
64
|
+
assert_equal(s,s << '- a',"Accepts negative string")
|
65
|
+
assert_equal(s,s << '? a',"Accepts unlabeled string")
|
66
|
+
end
|
67
|
+
|
68
|
+
# Tests Sample#include? on every kind of arguments it announce
|
69
|
+
def test_append_accepts_arguments_it_annouce
|
70
|
+
expected = Sample[
|
71
|
+
'+ a b a b',
|
72
|
+
'+ a b',
|
73
|
+
'-',
|
74
|
+
'- a',
|
75
|
+
'+ a b a b a b'
|
76
|
+
]
|
77
|
+
s = Sample.new
|
78
|
+
s << '+ a b a b'
|
79
|
+
s << ['+ a b', '-']
|
80
|
+
s << InputString.new('a', false)
|
81
|
+
s << Sample['+ a b a b a b', '-']
|
82
|
+
assert_equal(expected,s)
|
106
83
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
84
|
+
|
85
|
+
# Tests that Sample#<< detects inconsistencies
|
86
|
+
# def test_append_detects_inconsistency
|
87
|
+
# s = Sample.new
|
88
|
+
# s << '+ a b'
|
89
|
+
# s << '+ a b a b'
|
90
|
+
# assert_raise InconsistencyError do
|
91
|
+
# s << '- a b a b'
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
|
95
|
+
# Tests that Sample#<< detects inconsistencies
|
96
|
+
def test_append_detects_real_inconsistencies_only
|
97
|
+
s = Sample.new
|
98
|
+
s << '+ a b'
|
99
|
+
s << '+ a b a b'
|
100
|
+
assert_nothing_raised do
|
101
|
+
s << '- b'
|
102
|
+
s << '- a'
|
103
|
+
s << '- a b a'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Tests each
|
108
|
+
def test_each
|
109
|
+
strings = ['+ a b a b', '+ a b', '+ a b', '- a', '+']
|
110
|
+
strings = strings.collect{|s| ADL::parse_string(s)}
|
111
|
+
s = Sample.new << strings
|
112
|
+
count = 0
|
113
|
+
s.each do |str|
|
114
|
+
assert_equal(true, strings.include?(str))
|
115
|
+
count += 1
|
116
|
+
end
|
117
|
+
assert_equal(strings.size, count)
|
118
118
|
end
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
119
|
+
|
120
|
+
# Tests each_positive
|
121
|
+
def test_each_positive
|
122
|
+
sample = Sample[
|
123
|
+
'+',
|
124
|
+
'- b',
|
125
|
+
'+ a b a b',
|
126
|
+
'- a b a a'
|
127
|
+
]
|
128
|
+
count = 0
|
129
|
+
sample.each_positive do |str|
|
130
|
+
assert str.positive?
|
131
|
+
count += 1
|
132
|
+
end
|
133
|
+
assert_equal 2, count
|
134
|
+
positives = sample.positive_enumerator.collect{|s| s}
|
135
|
+
assert_equal 2, positives.size
|
136
|
+
[s('+'), s('+ a b a b')].each do |str|
|
137
|
+
assert positives.include?(str)
|
138
|
+
end
|
134
139
|
end
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
+
|
141
|
+
# Tests each_negative
|
142
|
+
def test_each_negative
|
143
|
+
sample = Sample[
|
144
|
+
'+',
|
145
|
+
'- b',
|
146
|
+
'+ a b a b',
|
147
|
+
'- a b a a'
|
148
|
+
]
|
149
|
+
count = 0
|
150
|
+
sample.each_negative do |str|
|
151
|
+
assert str.negative?
|
152
|
+
count += 1
|
153
|
+
end
|
154
|
+
assert_equal 2, count
|
155
|
+
negatives = sample.negative_enumerator.collect{|s| s}
|
156
|
+
assert_equal 2, negatives.size
|
157
|
+
[s('- b'), s('- a b a a')].each do |str|
|
158
|
+
assert negatives.include?(str)
|
159
|
+
end
|
140
160
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
count += 1
|
161
|
+
|
162
|
+
# Tests Sample#include?
|
163
|
+
def test_include
|
164
|
+
strings = ['+ a b a b', '+ a b', '- a', '+']
|
165
|
+
s = Sample.new << strings
|
166
|
+
strings.each do |str|
|
167
|
+
assert_equal(true, s.include?(str))
|
168
|
+
end
|
169
|
+
assert_equal(true, s.include?(strings))
|
170
|
+
assert_equal(true, s.include?(s))
|
171
|
+
assert_equal(false, s.include?('+ a'))
|
172
|
+
assert_equal(false, s.include?('-'))
|
173
|
+
assert_equal(false, s.include?('+ a b a'))
|
155
174
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
175
|
+
|
176
|
+
# Tests Sample#include? on every kind of arguments it announce
|
177
|
+
def test_include_accepts_arguments_it_annouce
|
178
|
+
s = Sample.new << ['+ a b a b', '+ a b', '- a', '+']
|
179
|
+
assert_equal true, s.include?('+ a b a b')
|
180
|
+
assert_equal true, s.include?(InputString.new('a b a b',true))
|
181
|
+
assert_equal true, s.include?(ADL::parse_string('+ a b a b'))
|
182
|
+
assert_equal true, s.include?(['+ a b a b', '+ a b'])
|
183
|
+
assert_equal true, s.include?(s)
|
161
184
|
end
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
assert_equal(
|
185
|
+
|
186
|
+
# Tests Sample#==
|
187
|
+
def test_equal
|
188
|
+
s1 = Sample['+ a b a b', '+', '- a']
|
189
|
+
s2 = Sample['+ a b a b', '+', '+ a']
|
190
|
+
assert_equal(true, s1==s1)
|
191
|
+
assert_equal(true, s2==s2)
|
192
|
+
assert_equal(false, s1==s2)
|
193
|
+
assert_equal(false, s1==Sample.new)
|
194
|
+
assert_equal(false, s2==Sample.new)
|
170
195
|
end
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
s2 = Sample['+ a b a b', '+', '+ a']
|
192
|
-
assert_equal(true, s1==s1)
|
193
|
-
assert_equal(true, s2==s2)
|
194
|
-
assert_equal(false, s1==s2)
|
195
|
-
assert_equal(false, s1==Sample.new)
|
196
|
-
assert_equal(false, s2==Sample.new)
|
197
|
-
end
|
198
|
-
|
199
|
-
# Test the signature
|
200
|
-
def test_signature
|
201
|
-
s = Sample.new
|
202
|
-
assert_equal '', s.signature
|
203
|
-
s = Sample.new << ['+ a b a b', '+ a b', '- a', '+']
|
204
|
-
assert_equal '1101', s.signature
|
205
|
-
s = Sample.new << ['+ a b a b', '+ a b', '- a', '?']
|
206
|
-
assert_equal '110?', s.signature
|
207
|
-
s = Stamina::ADL.parse_sample <<-SAMPLE
|
208
|
-
+
|
209
|
-
+ a b
|
210
|
-
- a c
|
211
|
-
? a d
|
212
|
-
SAMPLE
|
213
|
-
assert_equal '110?', s.signature
|
214
|
-
end
|
215
|
-
|
216
|
-
end # class SampleTest
|
217
|
-
|
218
|
-
end # module Stamina
|
196
|
+
|
197
|
+
# Test the signature
|
198
|
+
def test_signature
|
199
|
+
s = Sample.new
|
200
|
+
assert_equal '', s.signature
|
201
|
+
s = Sample.new << ['+ a b a b', '+ a b', '- a', '+']
|
202
|
+
assert_equal '1101', s.signature
|
203
|
+
s = Sample.new << ['+ a b a b', '+ a b', '- a', '?']
|
204
|
+
assert_equal '110?', s.signature
|
205
|
+
s = Stamina::ADL.parse_sample <<-SAMPLE
|
206
|
+
+
|
207
|
+
+ a b
|
208
|
+
- a c
|
209
|
+
? a d
|
210
|
+
SAMPLE
|
211
|
+
assert_equal '110?', s.signature
|
212
|
+
end
|
213
|
+
|
214
|
+
end # class SampleTest
|
215
|
+
end # module Stamina
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stamina/errors'
|
3
|
+
require 'stamina/stamina_test'
|
4
|
+
require 'stamina/scoring'
|
5
|
+
module Stamina
|
6
|
+
class ScoringTest < StaminaTest
|
7
|
+
|
8
|
+
def assert_almost_equal(x, y)
|
9
|
+
assert (x.to_f - y.to_f).abs <= 0.0001
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_scoring_on_exact
|
13
|
+
learned, reference = "11010", "11010"
|
14
|
+
scoring = Scoring.scoring(learned, reference)
|
15
|
+
|
16
|
+
# It looks like a Scoring object
|
17
|
+
assert scoring.respond_to?(:false_positive)
|
18
|
+
assert scoring.respond_to?(:recall)
|
19
|
+
|
20
|
+
# four measures are ok
|
21
|
+
assert_equal 3, scoring.true_positive
|
22
|
+
assert_equal 2, scoring.true_negative
|
23
|
+
assert_equal 0, scoring.false_positive
|
24
|
+
assert_equal 0, scoring.false_negative
|
25
|
+
|
26
|
+
# precision and recall are ok
|
27
|
+
assert_equal (3.0 / (3.0 + 0.0)), scoring.precision
|
28
|
+
assert_equal (3.0 / (3.0 + 0.0)), scoring.recall
|
29
|
+
|
30
|
+
# sensitivity and specificity are ok
|
31
|
+
assert_equal (3.0 / (3.0 + 0.0)), scoring.sensitivity
|
32
|
+
assert_equal (3.0 / (3.0 + 0.0)), scoring.specificity
|
33
|
+
|
34
|
+
#
|
35
|
+
assert_equal 1.0, scoring.accuracy
|
36
|
+
assert_equal 1.0, scoring.bcr
|
37
|
+
assert_equal 1.0, scoring.f_measure
|
38
|
+
assert_equal 1.0, scoring.hbcr
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_on_wikipedia_example
|
42
|
+
hash = {
|
43
|
+
:true_positive => 2,
|
44
|
+
:false_positive => 18,
|
45
|
+
:true_negative => 182,
|
46
|
+
:false_negative => 1
|
47
|
+
}
|
48
|
+
hash.extend(Scoring)
|
49
|
+
assert_equal (2.0 / (2 + 18)), hash.positive_predictive_value
|
50
|
+
assert_equal (182.0 / (1 + 182)), hash.negative_predictive_value
|
51
|
+
assert_equal (2.0 / (2 + 1)), hash.sensitivity
|
52
|
+
assert_equal (182.0 / (18 + 182)), hash.specificity
|
53
|
+
assert_equal (18.0 / (18 + 182)), hash.false_positive_rate
|
54
|
+
assert_equal (1.0 / (2 + 1)), hash.false_negative_rate
|
55
|
+
#
|
56
|
+
assert_almost_equal (1.0 - hash.specificity), hash.false_positive_rate
|
57
|
+
assert_almost_equal (1.0 - hash.sensitivity), hash.false_negative_rate
|
58
|
+
assert_almost_equal hash.sensitivity / (1.0 - hash.specificity), hash.positive_likelihood
|
59
|
+
assert_almost_equal (1.0 - hash.sensitivity) / hash.specificity, hash.negative_likelihood
|
60
|
+
end
|
61
|
+
|
62
|
+
end # class ScoringTest
|
63
|
+
end # module Stamina
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'stamina'
|
2
|
+
require 'stamina/utils/decorate'
|
3
|
+
require 'stamina/stamina_test'
|
4
|
+
require 'test/unit'
|
5
|
+
module Stamina
|
6
|
+
module Utils
|
7
|
+
class DecorateTest < ::Stamina::StaminaTest
|
8
|
+
|
9
|
+
module Reachability
|
10
|
+
def suppremum(d0, d1) d0 || d1; end
|
11
|
+
def propagate(deco, edge) deco; end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Depth
|
15
|
+
def suppremum(d0, d1) (d0 < d1 ? d0 : d1) end
|
16
|
+
def propagate(deco, edge) deco+1; end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ShortPrefix
|
20
|
+
def suppremum(d0, d1)
|
21
|
+
return d0 if d1.nil?
|
22
|
+
return d1 if d0.nil?
|
23
|
+
d0.size <= d1.size ? d0 : d1
|
24
|
+
end
|
25
|
+
def propagate(deco, edge)
|
26
|
+
deco.dup << edge.symbol
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_reachability_on_small_dfa
|
31
|
+
algo = Stamina::Utils::Decorate.new(:reachable)
|
32
|
+
algo.set_suppremum {|d0,d1| d0 || d1 }
|
33
|
+
algo.set_propagate {|deco,edge| deco }
|
34
|
+
algo.execute(@small_dfa, false, true)
|
35
|
+
assert_equal @small_dfa.states.select {|s| s[:reachable]==true}, @small_dfa.states
|
36
|
+
|
37
|
+
algo = Stamina::Utils::Decorate.new(:reachable)
|
38
|
+
algo.extend(Reachability)
|
39
|
+
algo.execute(@small_dfa, false, true)
|
40
|
+
assert_equal @small_dfa.states.select {|s| s[:reachable]==true}, @small_dfa.states
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_depth_on_small_dfa
|
44
|
+
algo = Stamina::Utils::Decorate.new(:depth)
|
45
|
+
algo.extend(Depth)
|
46
|
+
algo.execute(@small_dfa, 1000000, 0)
|
47
|
+
assert_equal 0, @small_dfa.ith_state(3)[:depth]
|
48
|
+
assert_equal 1, @small_dfa.ith_state(2)[:depth]
|
49
|
+
assert_equal 2, @small_dfa.ith_state(0)[:depth]
|
50
|
+
assert_equal 3, @small_dfa.ith_state(1)[:depth]
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_depth_on_small_dfa
|
54
|
+
algo = Stamina::Utils::Decorate.new(:short_prefix)
|
55
|
+
algo.extend(ShortPrefix)
|
56
|
+
algo.execute(@small_dfa, nil, [])
|
57
|
+
assert_equal [], @small_dfa.ith_state(3)[:short_prefix]
|
58
|
+
assert_equal ['b'], @small_dfa.ith_state(2)[:short_prefix]
|
59
|
+
assert_equal ['b', 'c'], @small_dfa.ith_state(0)[:short_prefix]
|
60
|
+
assert_equal ['b', 'c', 'a'], @small_dfa.ith_state(1)[:short_prefix]
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stamina
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 1
|
10
|
+
version: 0.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bernard Lambeau
|
@@ -144,6 +144,7 @@ files:
|
|
144
144
|
- lib/stamina/adl.rb
|
145
145
|
- lib/stamina/automaton.rb
|
146
146
|
- lib/stamina/automaton/walking.rb
|
147
|
+
- lib/stamina/automaton/metrics.rb
|
147
148
|
- lib/stamina/classifier.rb
|
148
149
|
- lib/stamina/command/adl2dot_command.rb
|
149
150
|
- lib/stamina/command/classify_command.rb
|
@@ -160,6 +161,9 @@ files:
|
|
160
161
|
- lib/stamina/sample.rb
|
161
162
|
- lib/stamina/version.rb
|
162
163
|
- lib/stamina/loader.rb
|
164
|
+
- lib/stamina/scoring.rb
|
165
|
+
- lib/stamina/utils/decorate.rb
|
166
|
+
- lib/stamina/utils.rb
|
163
167
|
- tasks/yard.rake
|
164
168
|
- tasks/debug_mail.txt
|
165
169
|
- tasks/gem.rake
|
@@ -168,10 +172,8 @@ files:
|
|
168
172
|
- tasks/spec_test.rake
|
169
173
|
- test/stamina/adl_test.rb
|
170
174
|
- test/stamina/automaton_additional_test.rb
|
171
|
-
- test/stamina/automaton_classifier_test.rb
|
172
175
|
- test/stamina/automaton_test.rb
|
173
|
-
- test/stamina/
|
174
|
-
- test/stamina/automaton_walking_test.rb
|
176
|
+
- test/stamina/scoring_test.rb
|
175
177
|
- test/stamina/exit.rb
|
176
178
|
- test/stamina/induction/induction_test.rb
|
177
179
|
- test/stamina/induction/redblue_mergesamestatebug_expected.adl
|
@@ -198,6 +200,11 @@ files:
|
|
198
200
|
- test/stamina/small_nfa.dot
|
199
201
|
- test/stamina/small_nfa.gif
|
200
202
|
- test/stamina/stamina_test.rb
|
203
|
+
- test/stamina/utils/decorate_test.rb
|
204
|
+
- test/stamina/automaton/classifier_test.rb
|
205
|
+
- test/stamina/automaton/walking_test.rb
|
206
|
+
- test/stamina/automaton/to_dot_test.rb
|
207
|
+
- test/stamina/automaton/metrics_test.rb
|
201
208
|
- test/test_all.rb
|
202
209
|
- .gemtest
|
203
210
|
- CHANGELOG.md
|
@@ -246,10 +253,8 @@ summary: Automaton and Regular Inference Toolkit
|
|
246
253
|
test_files:
|
247
254
|
- test/stamina/adl_test.rb
|
248
255
|
- test/stamina/automaton_additional_test.rb
|
249
|
-
- test/stamina/automaton_classifier_test.rb
|
250
256
|
- test/stamina/automaton_test.rb
|
251
|
-
- test/stamina/
|
252
|
-
- test/stamina/automaton_walking_test.rb
|
257
|
+
- test/stamina/scoring_test.rb
|
253
258
|
- test/stamina/exit.rb
|
254
259
|
- test/stamina/induction/induction_test.rb
|
255
260
|
- test/stamina/induction/redblue_mergesamestatebug_expected.adl
|
@@ -276,4 +281,9 @@ test_files:
|
|
276
281
|
- test/stamina/small_nfa.dot
|
277
282
|
- test/stamina/small_nfa.gif
|
278
283
|
- test/stamina/stamina_test.rb
|
284
|
+
- test/stamina/utils/decorate_test.rb
|
285
|
+
- test/stamina/automaton/classifier_test.rb
|
286
|
+
- test/stamina/automaton/walking_test.rb
|
287
|
+
- test/stamina/automaton/to_dot_test.rb
|
288
|
+
- test/stamina/automaton/metrics_test.rb
|
279
289
|
- test/test_all.rb
|