Class: UU::OS::Util::Histogram

Inherits:
Object
  • Object
show all
Defined in:
uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb

Overview

Simple implementation of histogram.

Instance Method Summary (collapse)

Constructor Details

- (Histogram) initialize(min, max, samples, logaritmic = true)

Creates new histogram.

Parameters:

  • min (Numeric)

    Minimum expected value (must be greater or equal to 1). In case lower value is received it is not forgotten but stored in lower threshold bin.

  • max (Numeric)

    Maximum expected value (must be greater than 1). In case higher value is received it is not forgotten but stored in upper threshold bin.

  • samples (Fixnum)

    Number of bins to be used (must be greater than 1). Higher number means higher precision, but also higher memory consumption and decreased performance (of both storing new values and reading results).

  • logaritmic (Boolean) (defaults to: true)

    Flag whether bins should use logarithmic distribution (toward lower values). Defaults to true.

Raises:

  • (ArgumentError)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb', line 18

def initialize(min, max, samples, logaritmic = true)
  raise ArgumentError, "min value must be greater or equal to 1" if min < 1
  raise ArgumentError, "max value must be greater than 1" if max <= 1
  raise ArgumentError, "max value must be greater than min value" if max <= min
  raise ArgumentError, "sample count must be greater of equal to 1" if samples < 1
  @samples = []
  @samples << {rng: min..min, sum: 0, cnt: 0}
  step = logaritmic ? (max.to_f / min.to_f) ** (1.0 / samples) :  (max - min).to_f / samples
  from, to = min, logaritmic ? min * step : min + step
  while from < max do
    from = from.round(3)
    to = to.round(3)
    to = max if to > max # may happen due to inaccurate round
    @samples << {rng: (from..to), sum: 0, cnt: 0}
    from, to = to, logaritmic ? to * step : to + step
  end
  @samples << {rng: max..max, sum: 0, cnt: 0}
  @cnt = 0
  @threshold_cnt = 0
  @min = nil
  @threshold_min = nil
  @max = nil
  @threshold_max = nil
end

Instance Method Details

- (Numeric) average(include_threshold = false)

Returns average from recorded values.

Parameters:

  • include_threshold (Boolean) (defaults to: false)

    Flag whether only values from within expected range should be used (false, default), or all values (including lower threshold bin and upper threshold bin) should be used.

Returns:

  • (Numeric)

    Average value.



104
105
106
107
108
109
110
111
112
# File 'uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb', line 104

def average(include_threshold = false)
  sum = 0
  cnt = 0
  (include_threshold ? @samples : @samples[1..-2]).each do |sample|
    sum += sample[:sum]
    cnt += sample[:cnt]
  end
  return cnt == 0 ? 0 : (sum.to_f / cnt.to_f).round(3)
end

- (Numeric) max(include_threshold = false)

Returns maximum recorded value (or nil if no value was recorded).

Parameters:

  • include_threshold (Boolean) (defaults to: false)

    Flag whether maximum value should be returned only from values within expected range (false, default) or values from lower threshold bin should be included.

Returns:

  • (Numeric)

    Maximum recorded value.



94
95
96
# File 'uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb', line 94

def max(include_threshold = false)
  return include_threshold ? @threshold_max || @max : @max
end

- (Numeric) median(include_threshold = false)

Returns median of recorded values.

Parameters:

  • include_threshold (Boolean) (defaults to: false)

    Flag whether only values from within expected range should be used (false, default), or all values (including lower threshold bin and upper threshold bin) should be used.

Returns:

  • (Numeric)

    Median.



120
121
122
# File 'uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb', line 120

def median(include_threshold = false)
  percentile(50, include_threshold)
end

- (Numeric) min(include_threshold = false)

Returns minimum recorded value (or nil if no value was recorded).

Parameters:

  • include_threshold (Boolean) (defaults to: false)

    Flag whether minimum value should be returned only from values within expected range (false, default) or values from lower threshold bin should be included.

Returns:

  • (Numeric)

    Minimum recorded value.



85
86
87
# File 'uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb', line 85

def min(include_threshold = false)
  return include_threshold ? @threshold_min || @min : @min
end

- (Numeric) percentile(val, include_threshold = false)

Returns specified percentile of recorded values.

Parameters:

  • val (Fixnum)

    Requested percentile (between 0 and 100)

  • include_threshold (Boolean) (defaults to: false)

    Flag whether only values from within expected range should be used (false, default), or all values (including lower threshold bin and upper threshold bin) should be used.

Returns:

  • (Numeric)

    Percentile

Raises:

  • (ArgumentError)


131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb', line 131

def percentile(val, include_threshold = false)
  raise ArgumentError, "value must be between 0 and 100" unless (0..100).include?(val)
  total = include_threshold ? @cnt + @threshold_cnt : @cnt
  limit = ((total.to_f / 100) * val).round
  count = 0
  value = 0
  (include_threshold ? @samples : @samples[1..-2]).each do |sample|
    if count < limit && sample[:cnt] > 0
      value = sample[:rng].max
    elsif count >= limit
      break
    end
    count += sample[:cnt]
  end
  return value
end

- (void) record(val)

This method returns an undefined value.

Records new value to histogram. Negative values are ignored.

Parameters:

  • val (Numeric)

    Value to be recorded.



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
# File 'uu_os_commons-1.5.0/lib/uu/os/util/histogram.rb', line 47

def record(val)
  return if val < 0
  if val < (sample = @samples[0])[:rng].max
    sample[:sum] += val
    sample[:cnt] += 1
    @threshold_cnt += 1
    if !@threshold_min || val < sample[:rng].min
      @threshold_min = val
      sample[:rng] = val..sample[:rng].max
    end
  elsif val > (sample = @samples[-1])[:rng].min
    sample[:sum] += val
    sample[:cnt] += 1
    @threshold_cnt += 1
    if !@threshold_max || val > sample[:rng].max
      @threshold_max = val
      sample[:rng] = sample[:rng].min..val
    end
    @threshold_max = val if !@threshold_max || val < @threshold_max
  else
    @samples[1..-2].each do |sample|
      next unless sample[:rng].include?(val)
      sample[:sum] += val
      sample[:cnt] += 1
      @cnt += 1
      @min = val if !@min || val < @min
      @max = val if !@max || val > @max
      break
    end
  end
  return
end