Jldrill Git C0 Coverage Information - RCov

lib/jldrill/model/Quiz/Statistics.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
lib/jldrill/model/Quiz/Statistics.rb 316 225
93.04%
90.22%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 require 'jldrill/model/Item'
2 require 'jldrill/model/ItemStatus'
3 require 'jldrill/model/Quiz/Timer'
4 require 'jldrill/model/Quiz/LevelStats'
5 require 'jldrill/model/Quiz/Counter'
6 
7 module JLDrill
8 
9     # Statistics for a quiz session
10     class Statistics
11     
12         attr_reader :estimate, :lastTen, :confidence, :levels, 
13                         :timesInTargetZone, :learned, :reviewed
14     
15         attr_writer :learned, :reviewed
16         
17         MINIMUM_CONFIDENCE = 0.009
18         SECONDS_PER_DAY = 60 * 60 * 24
19         
20         def initialize(quiz)
21             @quiz = quiz
22             @estimate = 0
23             @correct = 0
24             @incorrect = 0
25             @lastTen = []
26             @inTargetZone = false
27             @timesInTargetZone = 0
28             @levels = []
29             1.upto(8) do
30                 @levels.push(LevelStats.new)
31             end
32             @learned = 0
33             @reviewed = 0
34             @reviewRateSum = 0
35             @reviewTimer = Timer.new
36             @learnTimer = Timer.new
37             @currentTimer = nil
38             resetConfidence 
39         end
40         
41         def record(bool)
42             @lastTen.push(bool)
43             while @lastTen.size > 10
44                 @lastTen.delete_at(0)
45             end
46             if inTargetZone?
47                 @timesInTargetZone += 1
48             else
49                 @timesInTargetZone = 0
50             end
51         end
52         
53         def recentAccuracy
54             retVal = 0
55             if @lastTen.size > 0
56                 0.upto(@lastTen.size) do |i|
57                     if @lastTen[i]
58                         retVal += 1
59                     end
60                 end
61                 retVal = (retVal * 100 / @lastTen.size).to_i
62             end
63             retVal
64         end
65         
66         def inTargetZone?
67             # Don't start the countdown until we have reviewed
68             # at least 10 item.
69             if @reviewed <= 10
70                 return false
71             end
72             if !@inTargetZone
73                 if recentAccuracy >= 90
74                     @inTargetZone = true
75                 end
76             else
77                 if (recentAccuracy < 90) && (@confidence < 90)
78                     @inTargetZone = false
79                 end
80             end
81             return @inTargetZone
82         end
83 
84         # Get the appropriate LevelStat object for this item
85         def getLevel(item)
86             return @levels[Counter.getLevel(item)]
87         end
88 
89         def recordReviewRate(item)
90             @reviewRateSum += item.schedule.reviewRate
91         end
92 
93         def reviewBin
94             return @quiz.contents.bins[4]
95         end
96 
97         def size
98             return reviewBin.length
99         end
100 
101         def averageReviewRate
102             retVal = 1.0
103             if @reviewed != 0
104                 retVal = ((@reviewRateSum * 10).round / @reviewed).to_f / 10 
105             end
106             return retVal
107         end
108 
109         def currentReviewRate
110             retVal = 1.0
111             if size > 0
112                 rate = reviewBin[0].schedule.reviewRate
113                retVal = ((rate * 100).round).to_f / 100
114             end
115             retVal
116         end
117 
118         def statsTable
119             dCounter = DurationCounter.new
120 
121             reviewBin.each do |item|
122                 dCounter.count(item)
123             end
124             return dCounter
125         end
126         
127         def correct(item)
128             # currently only level 4 items are reviewed
129             if item.bin != 4
130                 return
131             end
132             @correct += 1
133             @reviewed += 1
134             recordReviewRate(item)
135             level = getLevel(item)
136             if !level.nil?
137                 level.correct
138             end
139             record(true)
140             reEstimate
141             calculateConfidence(true)
142         end
143 
144         def incorrect(item)
145             # currently only level 4 items are reviewed
146             if item.bin != 4
147                 return
148             end
149             @incorrect += 1
150             @reviewed += 1
151             recordReviewRate(item)
152             level = getLevel(item)
153             if !level.nil?
154                 level.incorrect
155             end
156             record(false)
157             reEstimate
158             calculateConfidence(false)
159         end
160         
161         def correct=(value)
162             @correct = value
163             reEstimate
164         end
165         
166         def incorrect=(value)
167             @incorrect = value
168             reEstimate
169         end
170 
171         # Returns the actual % accuracy of the quiz in an integer 
172         def accuracy
173             retVal = 0
174             if @incorrect == 0
175                 if @correct != 0
176                     retVal = 100
177                 end
178             else
179                 retVal = ((@correct * 100) / total).to_i
180             end
181             retVal
182         end
183         
184         def total
185             @correct + @incorrect
186         end
187         
188         # Generates an estimate of the % accuracy in an integer
189         def reEstimate
190             hop = ((recentAccuracy - @estimate) * 0.3).to_i
191             retVal = @estimate + hop
192             if (retVal > 100) then retVal = 100 end
193             if (retVal < 0) then retVal = 0 end
194             @estimate = retVal
195         end
196 
197         # Calculates a Bayesian estimate (I think!) of the confidence that
198         # the items seen to this point were known to an accuracy of at
199         # least 90%.
200         #
201         # How this is calculated:
202         #    According to Bayes law, P(H|E) = P(E|H) * P(H) / P(E)
203         #    Where:
204         #       P(H|E) is the probability that the hypothesis is correct
205         #              given the evidence.  
206         #       P(E|H) is the probability that the evididence would be
207         #              shown if the hypothesis were correct.
208         #       P(H)   is the probability that the hypothesis is correct
209         #              given any evidence.
210         #       P(E)   is the probability that the evidence would be seen
211         #              in all cases.
212         #
213         #   This value is calculated incrementally in the following fashion:
214         #       P[n] = P(E|H) * P[n-1] / P(E)
215         #   i.e., the nth value of P is dependent on the n-1th value of P
216         #
217         #   In our case, I will assume that the distribution of the 
218         #   probabilities is uniform (probably wrong!) and say that
219         #   if we got the question right
220         #        P(E|H) = 0.95 
221         #             that is, our probability of getting it right is
222         #             somewhere between 90 and 100%.  I assume uniform
223         #             distribution, therefore the average is in the middle.
224         #   or if we got the question wrong
225         #        P(E|H) = 0.05
226         #             obviously, the probability of getting it wrong given
227         #             the hypothesis is 1 minus the probability of getting
228         #             it right.
229         #        P(E) = sum(probabilities for all the hypotheses)
230         #             = P(chance < 90) + P(chance is 90+%)
231         #        P(chance < 90) = 0.45(1 - P[n-1])
232         #             that is, it's equal to 1/2 the range between 0 and 90
233         #             times the probability that hypothesis is wrong.
234         #        P(chance > 90) = 0.95P[n-1]
235         #             that is, it's equal to 1/2 the range between 90 and 100
236         #             times the probability that the hypothesis is right.
237         #             So...
238         #        P(E) = 0.45(1 - P[n-1]) + 0.95P[n-1]
239         #
240         #    Giving a final answer of
241         #        P[n] = P(E|H) * P[n-1] / (0.45(1 - P[n-1]) + 0.95P[n-1])
242         #
243         #    I fully expect this is completely wrong due to my lack of
244         #    ability in math and statistics.  But on the other hand, I won't
245         #    care much as long as appears from the user's point of view to
246         #    be working.
247         def calculateConfidence(wasCorrect)
248             if wasCorrect
249                 pEH = 0.95
250             else
251                 pEH = 0.05
252             end
253             pE = (0.45 * (1.0 - @confidence)) + (0.95 * @confidence)
254             @confidence = (pEH * @confidence) / pE
255             if @confidence < MINIMUM_CONFIDENCE
256                 @confidence = MINIMUM_CONFIDENCE
257             end
258         end
259         
260         def resetConfidence
261             @confidence = MINIMUM_CONFIDENCE
262         end
263 
264         def startTimer(isReview)
265             if !@currentTimer.nil?
266                 @currentTimer.stop
267             end
268             if isReview
269                 @currentTimer = @reviewTimer
270             else
271                 @currentTimer = @learnTimer
272             end
273             @currentTimer.start
274         end
275 
276         def learnTime
277             @learnTimer.total
278         end
279         
280         def reviewTime
281             @reviewTimer.total
282         end
283         
284         def roundToOneDecimal(value)
285             value = value * 10.0
286             value = value.round
287             value = value.to_f / 10.0
288             value
289         end
290 
291         def learnPace
292             if @learned > 0
293                 roundToOneDecimal(learnTime / @learned)
294             else
295                 0.0
296             end
297         end
298 
299         def reviewPace
300             if @reviewed > 0
301                 roundToOneDecimal(reviewTime / @reviewed)
302             else
303                 0.0
304             end
305         end
306         
307         def learnTimePercent
308             total = learnPace + reviewPace
309             if total > 0
310                 ((learnPace * 100) / total).to_i
311             else
312                 0
313             end
314         end
315     end
316 end

Generated on Mon May 23 16:17:46 +0900 2011 with rcov 0.9.8