@@ -9,37 +9,29 @@ module Oracle
9
9
# We use a cursor and modulo to pick where to insert.
10
10
# The last 5 chars are not BBAAA but AAABB.
11
11
class Ring
12
- attr_reader :count , :cursor , :storage
12
+ attr_reader :limit , :cursor , :storage
13
13
14
- def initialize ( count = 5 )
15
- @count = count
14
+ def initialize ( limit = 5 )
15
+ @limit = limit
16
16
@cursor = 0
17
- @storage = Array . new
17
+ @storage = Array . new ( @limit , '' )
18
18
end
19
19
20
20
def update ( val )
21
- @storage [ @cursor % @count ] = val
21
+ @storage [ @cursor % @limit ] = val
22
22
@cursor += 1
23
23
self
24
24
end
25
25
26
26
def to_s
27
- if @cursor < @count
28
- @storage
29
- else
30
- cursor = @cursor % @count
31
- @storage [ cursor , @count - cursor ] + @storage [ 0 , cursor ]
32
- end . join
27
+ cursor = @cursor % @limit
28
+ # steep:ignore:start
29
+ ( @storage [ cursor , @limit - cursor ] + @storage [ 0 , cursor ] ) . join
30
+ # steep:ignore:end
33
31
end
34
32
35
33
def full?
36
- if @storage . count < @count
37
- false
38
- elsif @storage . count == @count
39
- true
40
- else
41
- raise ( "@storage.count too large: #{ @storage . inspect } " )
42
- end
34
+ @cursor >= @limit
43
35
end
44
36
end
45
37
@@ -50,7 +42,7 @@ class Model
50
42
def self . summarize ( hsh )
51
43
best_key = nil
52
44
best_val = 0
53
- best_pct = 0
45
+ best_pct = 0.0
54
46
55
47
total = hsh . values . sum
56
48
pct = { }
@@ -72,36 +64,48 @@ def self.summarize(hsh)
72
64
73
65
attr_reader :ring , :freq , :pred
74
66
75
- def initialize ( count = 5 )
76
- @ring = Ring . new ( count )
67
+ def initialize ( limit = 5 )
68
+ @ring = Ring . new ( limit )
77
69
@freq = Hash . new
78
70
@pred = Hash . new ( 0 )
79
71
end
80
72
81
73
def to_s
82
- format ( "%s\t %s" , @ring , self . prediction )
74
+ format ( "%s\t %.1f%%" , @ring , self . percentage )
75
+ end
76
+
77
+ # Rational 0..1, correct / total
78
+ def ratio
79
+ return 1 r if @pred . empty?
80
+ Rational ( @pred [ :correct ] , @pred [ :correct ] + @pred [ :incorrect ] )
81
+ end
82
+
83
+ # Float 0.0..100.0 based on ratio
84
+ def percentage
85
+ ( self . ratio * 100.0 ) . round ( 1 ) . to_f # convince steep it's a Float
83
86
end
84
87
85
- # [0..1]
86
- def correct_pct
87
- return 1 if @pred . empty?
88
- @pred [ :correct ] / ( @pred [ :correct ] + @pred [ :incorrect ] ) . to_f
88
+ def prediction
89
+ h = @freq [ @ring . to_s ] and Model . summarize ( h )
89
90
end
90
91
91
92
def update ( val )
93
+ # only make predictions once the ring is full
92
94
if @ring . full?
93
- key = @ring . to_s
94
- @freq [ key ] ||= Hash . new ( 0 )
95
- @freq [ key ] [ val ] += 1
96
- end
97
- pred = self . prediction
98
- if pred
99
- if val == pred [ :best_key ]
100
- @pred [ :correct ] += 1
101
- else
102
- @pred [ :incorrect ] += 1
95
+ buf = @ring . to_s
96
+
97
+ # update @pred if we've seen this sequence before
98
+ if ( h = @freq [ buf ] )
99
+ pred = Model . summarize ( h )
100
+ @pred [ ( val == pred [ :best_key ] ) ? :correct : :incorrect ] += 1
103
101
end
102
+
103
+ # update @freq
104
+ @freq [ buf ] ||= Hash . new ( 0 )
105
+ @freq [ buf ] [ val ] += 1
104
106
end
107
+
108
+ # update @ring
105
109
@ring . update ( val )
106
110
self
107
111
end
@@ -111,13 +115,6 @@ def accept(str)
111
115
str . each_char { |c | self . update ( c ) }
112
116
self
113
117
end
114
-
115
- def prediction
116
- if @ring . full?
117
- h = @freq [ @ring . to_s ]
118
- Model . summarize ( h ) if h and !h . empty?
119
- end
120
- end
121
118
end
122
119
end
123
120
end
0 commit comments