# Statistics

module

A collection of statistics functions for various `Symphony` systems. Special thanks to Justin Z. Smith <justin@statisticool.com> for the maths. Good luck with your search for economic collapse in applesauce!

### Constants

DEFAULT_SAMPLE_SIZE

The default number of samples to keep

### Attributes

sample_size[RW]

The number of samples to keep for analysis, and required before trending is performed.

samples[R]

Samples of the number of pending jobs

### Public Class Methods

anchor
new( * )

Set up some instance variables for tracking statistical info when the object is created.

``````# File lib/symphony/statistics.rb, line 18
def initialize( * )
super
@samples = []
@sample_size = DEFAULT_SAMPLE_SIZE
@counter = 0
end``````

### Public Instance Methods

anchor

Add the specified `value` as a sample for the current time.

``````# File lib/symphony/statistics.rb, line 36
@samples << [ Time.now.to_f, value ]
@samples.shift( @samples.size - self.sample_size ) if @samples.size > self.sample_size
@counter = ( @counter + 1 ) % 3
end``````
anchor
calculate_trend()

Predict the likelihood that an upward trend will continue based on linear regression analysis of the given samples. If the value returned is >= 3.0, the values are statistically trending upwards, which in Symphony's case means that the workers are not handling the incoming work.

``````# File lib/symphony/statistics.rb, line 66
def calculate_trend
return 0 unless self.samples.size >= self.sample_size
# Loggability[ Symphony ].debug "%d samples of required %d" % [ self.samples.size, self.sample_size ]

x_vec, y_vec = self.samples.transpose

y_avg = y_vec.inject( :+ ).to_f / y_vec.size
x_avg = x_vec.inject( :+ ).to_f / x_vec.size

# Find slope and y-intercept.
#
n = d = 0
samples.each do |x, y_val|
xv = x - x_avg
n  = n + ( xv * ( y_val - y_avg ) )
d  = d + ( xv ** 2 )
end

slope = n/d
y_intercept = y_avg - ( slope * x_avg )

# Find stderr.
#
r = s = 0
samples.each do |x, y_val|
yv = ( slope * x ) + y_intercept
r  = r + ( (y_val - yv) ** 2 )
s  = s + ( (x - x_avg) ** 2 )
end

stde = Math.sqrt( (r / ( samples.size - 2 )) / s )

# Loggability[ Symphony ].debug "  job sampling trend is: %f" %  [ slope / stde ] if
#     @counter.zero?

return slope / stde
end``````
anchor
mean_jobcount()

Return the mean of the job count samples.

``````# File lib/symphony/statistics.rb, line 56
def mean_jobcount
return 0 unless self.samples.size >= self.sample_size
return @samples.map( &:last ).reduce( :+ ) / @samples.length.to_f
end``````
anchor
sample_values_decreasing?()

Returns `true` if the samples gathered so far indicate a downwards trend.

``````# File lib/symphony/statistics.rb, line 50
def sample_values_decreasing?
return self.calculate_trend < -3
end``````
anchor
sample_values_increasing?()

Returns `true` if the samples gathered so far indicate an upwards trend.

``````# File lib/symphony/statistics.rb, line 44
def sample_values_increasing?
return self.calculate_trend > 3
end``````