Module Math
In: lib/facets/standard/facets/math/mean.rb
lib/facets/standard/facets/math/log2.rb
lib/facets/standard/facets/math/sum.rb
lib/facets/standard/facets/math/acot.rb
lib/facets/standard/facets/math/sinc.rb
lib/facets/standard/facets/math/root.rb
lib/facets/standard/facets/math/acsch.rb
lib/facets/standard/facets/math/asech.rb
lib/facets/standard/facets/math/sech.rb
lib/facets/standard/facets/math/exp2.rb
lib/facets/standard/facets/math/beta.rb
lib/facets/standard/facets/math/acsc.rb
lib/facets/standard/facets/math/kldivergence.rb
lib/facets/standard/facets/math/gini_coefficient.rb
lib/facets/standard/facets/math/csch.rb
lib/facets/standard/facets/math/acoth.rb
lib/facets/standard/facets/math/exp10.rb
lib/facets/standard/facets/math/summed_sqdevs.rb
lib/facets/standard/facets/math/median.rb
lib/facets/standard/facets/math/lcm.rb
lib/facets/standard/facets/math/linsolve.rb
lib/facets/standard/facets/math/sqsolve.rb
lib/facets/standard/facets/math/pow.rb
lib/facets/standard/facets/math/cdf.rb
lib/facets/standard/facets/math/floor.rb
lib/facets/standard/facets/math/std.rb
lib/facets/standard/facets/math/amd.rb
lib/facets/standard/facets/math/gcd.rb
lib/facets/standard/facets/math/cot.rb
lib/facets/standard/facets/math/csc.rb
lib/facets/standard/facets/math/factorial.rb
lib/facets/standard/facets/math/sign.rb
lib/facets/standard/facets/math/gamma.rb
lib/facets/standard/facets/math/atkinson_index.rb
lib/facets/standard/facets/math/min.rb
lib/facets/standard/facets/math/asec.rb
lib/facets/standard/facets/math/approx_equal.rb
lib/facets/standard/facets/math/sqr.rb
lib/facets/standard/facets/math/sec.rb
lib/facets/standard/facets/math/abs.rb
lib/facets/standard/facets/math/variance.rb
lib/facets/standard/facets/math/ceil.rb
lib/facets/standard/facets/math/coth.rb
lib/facets/standard/facets/math/rmd.rb
lib/facets/standard/facets/math/theil_index.rb
lib/facets/standard/facets/math/epsilon.rb
lib/facets/standard/facets/math/delta.rb
lib/facets/standard/facets/math/lgamma.rb

Methods

abs   acot   acoth   acsc   acsch   amd   approx_equal   asec   asech   atkinson_index   beta   cdf   ceil   cot   coth   csc   csch   delta   epsilon   exp10   exp2   factorial   floor   gamma   gcd   gini_coefficient   kldivergence   lcm   lgamma   linsolve   log2   max   mean   median   min   pow   pstd   pvariance   rmd   root   sec   sech   sign   sinc   sqr   sqsolve   std   stderr   sum   summed_sqdevs   theil_index   variance   variance2  

Constants

INVERSE_LN_2 = 1.0 / ::Math.log(2.0)
FACTORIALS = [ 1, 1, 2, 6, 24, 120, 720, 5_040, 40_320, 362_880, 3_628_800, 39_916_800, 479_001_600, 6_227_020_800, 87_178_291_200, 1_307_674_368_000   First 16 factorials.
EPSILON = 0.000000001  

External Aliases

mean -> mean_average
std -> standard_deviation
amd -> absolute_mean_difference
rmd -> relative_mean_difference

Public Class methods

Absolute value of x.

[Source]

# File lib/facets/standard/facets/math/abs.rb, line 4
  def self.abs(x)
    x.abs
  end

Arcus cotangens of x

[Source]

# File lib/facets/standard/facets/math/acot.rb, line 4
  def self.acot(x)
    (PI * 0.5) - atan(x)
  end

Area cotangens hyperbolicus of x

[Source]

# File lib/facets/standard/facets/math/acoth.rb, line 4
  def self.acoth(x)
    0.5 * log((x + 1.0) / (x - 1.0))
  end

Arcus cosecans of x

[Source]

# File lib/facets/standard/facets/math/acsc.rb, line 4
  def self.acsc(x)
    asin(1.0 / x)
  end

The average absolute difference of two independent values drawn from the sample. Equal to the RMD * mean.

[Source]

# File lib/facets/standard/facets/math/amd.rb, line 8
  def self.amd(array)
          rmd(array) * mean(array)
  end

Approximately equal.

TODO: Use core extension Numeric#approx? instead (?)

[Source]

# File lib/facets/standard/facets/math/approx_equal.rb, line 9
  def self.approx_equal(a, b, epsilon=EPSILON)
          c = a - b
          c *= -1.0 if c < 0
    c < epsilon
  end

Arcus secans of x

[Source]

# File lib/facets/standard/facets/math/asec.rb, line 4
  def self.asec(x)
    acos(1.0 / x)
  end

Closely related to the Theil index and easily expressible in terms of it.

AI = 1-e^{theil_index}

en.wikipedia.org/wiki/Atkinson_index

[Source]

# File lib/facets/standard/facets/math/atkinson_index.rb, line 11
  def self.atkinson_index(array)
    t = theil_index(array)
    (t < 0) ? -1 : 1-Math::E**(-t)
  end

Beta function of x and y - beta(x, y) = tgamma(x) * tgamma(y) / tgamma(x + y)

[Source]

# File lib/facets/standard/facets/math/beta.rb, line 5
  def self.beta(x, y)
    exp(lgamma(x) + lgamma(y) - lgamma(x+y))
  end

Returns the Cumulative Density Function of this sample (normalised to a fraction of 1.0).

[Source]

# File lib/facets/standard/facets/math/cdf.rb, line 5
  def self.cdf(array, normalised=1.0)
    s = sum(array).to_f
    array.sort.inject([0.0]) { |c,d| c << c[-1] + normalised*d.to_f/s }
  end

Smallest integer not smaller than x.

[Source]

# File lib/facets/standard/facets/math/ceil.rb, line 4
  def self.ceil(x)
    x.ceil
  end

Cotangens of x

[Source]

# File lib/facets/standard/facets/math/cot.rb, line 4
  def self.cot(x)
    tan((PI * 0.5) - x)
  end

Cotangens hyperbolicus of x

[Source]

# File lib/facets/standard/facets/math/coth.rb, line 4
  def self.coth(x)
    1.0 / tanh(x)
  end

Cosecans of x

[Source]

# File lib/facets/standard/facets/math/csc.rb, line 4
  def self.csc(x)
    1.0 / sin(x)
  end

Cosecans hyperbolicus of x

[Source]

# File lib/facets/standard/facets/math/csch.rb, line 4
  def self.csch(x)
    1.0 / sinh(x)
  end

Kronecker symbol of i and j. Returns 1 if i and j are equal, 0 otherwise.

[Source]

# File lib/facets/standard/facets/math/delta.rb, line 5
  def self.delta(i, j)
    return Integer(i) == Integer(j) ? 1 : 0
  end

Levi-Civita symbol of i, j, and k - 1 if (i, j, k) is (1, 2, 3), (2, 3, 1), or (3, 1, 2), -1 if it is (1, 3, 2), (2, 1, 3), or (3, 2, 1), 0 as long as i, j, and k are all elements of {1, 2, 3}, otherwise returns nil.

[Source]

# File lib/facets/standard/facets/math/epsilon.rb, line 7
  def self.epsilon(i, j, k)
    i = Integer(i)
    return nil if i < 1 or i > 3
    j = Integer(j)
    return nil if j < 1 or j > 3
    k = Integer(k)
    return nil if k < 1 or k > 3
    case i * 16 + j * 4 + k
      when 27, 45, 54 then return  1
      when 30, 39, 57 then return -1
    end
    0
  end

10 to the power x

[Source]

# File lib/facets/standard/facets/math/exp10.rb, line 4
  def self.exp10(x)
    10.0 ** x
  end

2 to the power x

[Source]

# File lib/facets/standard/facets/math/exp2.rb, line 4
  def self.exp2(x)
    2.0 ** x
  end

1 * 2 * … * n, nil for negative numbers

[Source]

# File lib/facets/standard/facets/math/factorial.rb, line 24
  def self.factorial(n)
    n = Integer(n)
    if n < 0
      nil
    elsif FACTORIALS.length > n
      FACTORIALS[n]
    else
      h = FACTORIALS.last
      (FACTORIALS.length .. n).each { |i| FACTORIALS.push h *= i }
      h
    end
  end

Largest integer not larger than x.

[Source]

# File lib/facets/standard/facets/math/floor.rb, line 4
  def self.floor(x)
    x.floor
  end

[Source]

# File lib/facets/standard/facets/math/gamma.rb, line 7
    def self.gamma(x)
      exp(lgamma(x))
    end

Greatest common divisor of m and n, nil for non-positive numbers - gcd is computed by means of the Euclidian algorithm.

[Source]

# File lib/facets/standard/facets/math/gcd.rb, line 5
  def self.gcd(m, n)
    m = Integer(m)
    n = Integer(n)
    if m <= 0 || n <= 0
      return nil
    end
    loop {
      if m < n
        m, n = n, m
      end
      if (l = m % n) == 0
        break
      end
      m = l
    }
    n
  end

Calculates the Gini Coefficient (a measure of inequality of a distribution based on the area between the Lorenz curve and the uniform curve).

en.wikipedia.org/wiki/Gini_coefficient

This is a slightly cleaner way of calculating the Gini Coefficient then the previous implementationj.

  GC = \frac{\sum_{i=1}^N (2i-N-1)x_i}{N^2-\bar{x}}

[Source]

# File lib/facets/standard/facets/math/gini_coefficient.rb, line 15
  def self.gini_coefficient(array)
    return -1 if size <= 0 or any? { |x| x < 0 }
    return 0 if size < 2 or all? { |x| approx_equal(x,0) }
    s = 0
    sort.each_with_index { |li,i| s += (2*i+1-size)*li }
    s.to_f/(size**2*mean).to_f
  end

The Kullback-Leibler divergence from this array to that of q.

NB: You will possibly want to sort both P and Q before calling this depending on what you‘re actually trying to measure.

en.wikipedia.org/wiki/Kullback-Leibler_divergence

[Source]

# File lib/facets/standard/facets/math/kldivergence.rb, line 10
  def self.kldivergence(array, q)
    fail "Buggy."
    fail "Cannot compare differently sized arrays." unless size = q.size
    kld = 0
    each_with_index { |pi,i| kld += pi*Math::log(pi.to_f/q[i].to_f) }
    kld
  end

Least common multiple of m and n, computed by multiplying m and n and dividing the product by the gcd of m and n, nil for non-positive numbers.

[Source]

# File lib/facets/standard/facets/math/lcm.rb, line 6
  def self.lcm(m, n)
    m = Integer(m)
    n = Integer(n)
    if m <= 0 || n <= 0
      return nil
    end
    m / gcd(m, n) * n
  end

Logarithmus naturalis of gamma function of x

[Source]

# File lib/facets/standard/facets/math/lgamma.rb, line 6
    def self.lgamma(x)
      h  = x + 5.5
      h -= (x + 0.5) * log(h)
      sum  =  1.000_000_000_190_015
      sum += 76.180_091_729_471_46           / (x + 1.0)
      sum -= 86.505_320_329_416_77           / (x + 2.0)
      sum += 24.014_098_240_830_91           / (x + 3.0)
      sum -=  1.231_739_572_450_155          / (x + 4.0)
      sum +=  0.120_865_097_386_617_9e-2 / (x + 5.0)
      sum -=  0.539_523_938_495_3e-5     / (x + 6.0)
      -h + log(2.506_628_274_631_000_5 * sum / x)
    end

Returns real solution(s) of +a+x + b = c or nil if no or an infinite number of solutions exist. If c is missing it is assumed to be 0.

[Source]

# File lib/facets/standard/facets/math/linsolve.rb, line 6
  def self.linsolve(a, b, c = 0.0)
    a == 0 ? nil : (c - b) / a
  end

Logarithmus dualis of x.

[Source]

# File lib/facets/standard/facets/math/log2.rb, line 8
    def self.log2(x)
      Math.log(x) * INVERSE_LN_2
    end

[Source]

# File lib/facets/standard/facets/math/min.rb, line 20
  def self.max(array, block)
    if block_given?
      if max = find{|i| i}
        max = yield(max)
        each{|i|
          j = yield(i)
          max = j if max < j
        }
        max
      end
    else
      array.max
    end
  end

Mean average.

[Source]

# File lib/facets/standard/facets/math/mean.rb, line 6
  def self.mean(array, &blk)
    s = array.size
    return 0.0 if s == 0
    sum(array, &blk) / s
  end

[Source]

# File lib/facets/standard/facets/math/median.rb, line 4
  def self.median(array)
    return 0 if array.size == 0
    tmp = array.sort
    mid = tmp.size / 2
    if (tmp.size % 2) == 0
            (tmp[mid-1] + tmp[mid]).to_f / 2
    else
            tmp[mid]
    end
  end

[Source]

# File lib/facets/standard/facets/math/min.rb, line 4
  def self.min(array, &block)
    if block_given?
      if min = array.find{ |i| i }
        min = yield(min)
        array.each do |i|
          j = yield(i)
          min = j if min > j
        end
        min
      end
    else
      array.min
    end
  end

x to the power y

[Source]

# File lib/facets/standard/facets/math/pow.rb, line 4
  def self.pow(x, y)
    x ** y
  end

Standard deviation of a population.

[Source]

# File lib/facets/standard/facets/math/std.rb, line 17
  def self.pstd(array, &block)
    Math::sqrt(pvariance(array, &block))
  end

Variance of a population. Variance of 0 or 1 elements is 0.0.

[Source]

# File lib/facets/standard/facets/math/variance.rb, line 26
  def self.pvariance(array)
    return 0.0 if array.size < 2
    summed_sqdevs(array) / array.size
  end

Calculates the relative mean difference of this sample. Makes use of the fact that the Gini Coefficient is half the RMD.

[Source]

# File lib/facets/standard/facets/math/rmd.rb, line 7
  def self.rmd(array)
    return 0.0 if approx_equal(mean(array), 0.0)
    gini_coefficient(array) * 2
  end

The y root of x.

[Source]

# File lib/facets/standard/facets/math/root.rb, line 4
  def self.root(x, y)
    x ** (1.0 / y)
  end

Secans of x.

[Source]

# File lib/facets/standard/facets/math/sec.rb, line 4
  def self.sec(x)
    1.0 / cos(x)
  end

Secans hyperbolicus of x

[Source]

# File lib/facets/standard/facets/math/sech.rb, line 4
  def self.sech(x)
    1.0 / cosh(x)
  end

Sign of x. Returns -1 for negative x, +1 for positive x and zero for x = 0

[Source]

# File lib/facets/standard/facets/math/sign.rb, line 5
  def self.sign(x)
    (x > 0.0) ? 1.0 : ((x < 0.0) ? -1.0 : 0.0)
  end

Sinc function of x.

[Source]

# File lib/facets/standard/facets/math/sinc.rb, line 4
  def self.sinc(x)
    (x == 0.0) ? 1.0 : sin(x) / x
  end

Square of number.

[Source]

# File lib/facets/standard/facets/math/sqr.rb, line 4
  def self.sqr(x)
    x * x
  end

Returns array of real solution of ax**2 + bx + c = d or nil if no or an infinite number of solutions exist. If d is missing it is assumed to be 0.

Solving second order equations

In order to solve ax**2 + bx + c = d +Extmath.sqsolve+ identifies several cases:

  • a == 0: The equation to be solved is the linear equation bx + c = d. sqsolve> delegates the computation to linsolve>. If it results in nil, nil is returned (not [nil]!). Otherwise a one-element array containing result of linsolve is returned.
  • a != 0:
     The equation to be solved actually is a second order one.
     * <code>c == d</code>
       The equation to be solved is <code>ax**2 + bx = 0</code>. One solution of this equation obviously is
       <code>x = 0</code>, the second one solves <code>ax + b = 0</code>. The solution of the latter is
       delegated to +Extmath.linsolve+. An array containing both results in ascending order is returned.
     * <code>c != d</code>
       The equation cannot be separated into <code>x</code> times some factor.
       * <code>b == 0</code>
         The equation to be solved is <code>ax**2 + c = d</code>. This can be written as the linear equation
         <code>ay + c = d</code> with <code>y = x ** 2</code>. The solution of the linear equation is delegated
         to +Extmath.linsolve+. If the returned value for +y+ is +nil+, that becomes the overall return value.
         Otherwise an array containing the negative and positive squareroot of +y+ is returned
       * <code>b != 0 </code>
         The equation cannot be reduced to simpler cases. We now first have to compute what is called the
         discriminant <code>x = b**2 + 4a(d - c)</code> (that's what we need to compute the square root of).
         If the descriminant is negative no real solution exists and <code>nil</code> is returned. The ternary
         operator checking whether <code>b</code> is negative does ensure better numerical stability --only one
         of the two solutions is computed using the widely know formula for solving second order equations.
         The second one is computed from the fact that the product of both solutions is <code>(c - d) / a</code>.
         Take a look at a book on numerical mathematics if you don't understand why this should be done.
    

[Source]

# File lib/facets/standard/facets/math/sqsolve.rb, line 35
  def self.sqsolve(a, b, c, d = 0.0)
    if a == 0.0
      x = linsolve(b, c, d)
      return x.nil? ? nil: [ linsolve(b, c, d) ]
    else
      return [0.0, linsolve(a, b)].sort if c == d
      if b == 0.0
        x = Extmath.linsolve(a, c, d)
        x < 0.0 ? nil : [-Math.sqrt(x), Math.sqrt(x)]
      else
        x = b * b + 4.0 * a * (d - c)
        return nil if x < 0.0
        x = b < 0 ? b - Math.sqrt(x) : b + Math.sqrt(x)
        [-0.5 * x / a, 2.0 * (d - c) / x].sort
      end
    end
  end

Standard deviation of a sample.

[Source]

# File lib/facets/standard/facets/math/std.rb, line 7
  def self.std(array, &block)
    sqrt(variance(array, &block))
  end

Calculates the standard error of a sample.

[Source]

# File lib/facets/standard/facets/math/std.rb, line 22
  def self.stderr(array)
    return 0.0 if array.size < 2
    std(array) / sqrt(array.size)
  end

Returns sum. When a block is given, summation is taken over the each result of block evaluation.

[Source]

# File lib/facets/standard/facets/math/sum.rb, line 6
  def self.sum(array) #:yield:
    sum = 0.0
    if block_given?
      array.each{|i| sum += yield(i)}
    else
      array.each{|i| sum += i}
    end
    sum
  end

The sum of the squared deviations from the mean.

[Source]

# File lib/facets/standard/facets/math/summed_sqdevs.rb, line 8
  def self.summed_sqdevs(array)
    return 0 if array.size < 2
    m = mean(array)
    sum(array.map{ |x| (x - m) ** 2 })
  end

Calculates the Theil index (a statistic used to measure economic inequality).

TI = \sum_{i=1}^N \frac{x_i}{\sum_{j=1}^N x_j} ln \frac{x_i}{\bar{x}}

  http://en.wikipedia.org/wiki/Theil_index

[Source]

# File lib/facets/standard/facets/math/theil_index.rb, line 14
  def self.theil_index(array)
    return -1 if array.size <= 0 or any? { |x| x < 0 }
    return  0 if array.size <  2 or all? { |x| approx_equal(x, 0) }
    m = mean(array)
    s = sum(array).to_f
    inject(0) do |theil, xi|
            theil + ((xi > 0) ? (log(xi.to_f/m) * xi.to_f/s) : 0.0)
    end
  end

[Source]

# File lib/facets/standard/facets/math/variance.rb, line 6
  def self.variance(array, &block)
    sum2 = if block_given?
      sum(array){ |i| j = block[i]; j*j }
    else
      sum(array){ |i| i**2 }
    end
    sum2/array.size - mean(array, &block)**2
  end

Variance of the sample. Variance of 0 or 1 elements is 0.0.

TODO: Same as variance? Then choose one.

[Source]

# File lib/facets/standard/facets/math/variance.rb, line 19
  def self.variance2(array)
    return 0.0 if array.size < 2
    summed_sqdevs(array) / (array.size - 1)
  end

Public Instance methods

Area cosecans hyperbolicus of x

[Source]

# File lib/facets/standard/facets/math/acsch.rb, line 4
  def acsch(x)
    ::Math.log(1.0 / x + Math.sqrt(1.0 + 1.0 / (x * x)))
  end

Area secans hyperbolicus of x

[Source]

# File lib/facets/standard/facets/math/asech.rb, line 4
  def asech(x)
    log((1.0 + sqrt(1.0 - x * x)) / x)
  end

[Validate]