lib/statistical/distribution/laplace.rb
require 'statistical/helpers'
module Statistical
module Distribution
# Say something useful about this class.
#
# @note Any caveats you want to talk about go here...
#
# @author Vaibhav Yenamandra
# @attr_reader [Numeric] scale Scale parameter of the Laplace distribution.
# @attr_reader [Numeric] location Location parameter to determine where the
# distribution is centered / where the mean lies at
class Laplace
attr_reader :scale, :location, :support
# Returns a new instance of the Laplace distribution; also known as
# the two-sided exponential distribution
#
# @param [Numeric] scale Scale parameter of the Laplace distribution.
# @param [Numeric] location Location parameter to determine where the
# distribution is centered / where the mean lies at
# @return `Statistical::Distribution::Laplace` instance
def initialize(location = 0, scale = 1)
@scale = scale
@location = location
@support = Domain[-Float::INFINITY, Float::INFINITY, :full_open]
self
end
# Returns value of probability density function at a point.
#
# @param [Numeric] x A real valued point
# @return [Float] Probility density function evaluated at x
def pdf(x)
x_ = (x - @location).abs.fdiv(@scale)
return Math.exp(- x_).fdiv(2 * @scale)
end
# Returns value of cumulative density function at a point.
#
# @param [Numeric] x A real valued point
# @return [Float] Cumulative density function evaluated at x
def cdf(x)
return [0.5,
1.0 - 0.5 * Math.exp((@location - x).fdiv(@scale)),
0.5 * Math.exp((x - @location).fdiv(@scale))][x <=> @location]
end
# Returns value of inverse CDF for a given probability
#
# @see #p_value
#
# @param [Numeric] p a value within [0, 1]
# @return Inverse CDF for valid p
# @raise [RangeError] if p > 1 or p < 0
def quantile(p)
raise RangeError, "`p` must be in [0, 1], found: #{p}" if p < 0 || p > 1
return [@location,
@location - @scale * Math.log(2 * (1.0 - p)),
@scale * Math.log(2 * p) + @location][p <=> 0.5]
end
# Returns the expected mean value for the calling instance.
#
# @return Mean of the distribution
def mean
return @location
end
# Returns the expected value of variance for the calling instance.
#
# @return Variance of the distribution
def variance
return 2 * @scale * @scale
end
# Compares two distribution instances and returns a boolean outcome
# Available publicly as #==
#
# @private
#
# @param other A distribution object (preferred)
# @return [Boolean] true if-and-only-if two instances are of the same
# class and have the same parameters.
def eql?(other)
return false unless other.is_a?(self.class) &&
other.scale == @scale &&
other.location == @location
return true
end
alias :== :eql?
alias :p_value :quantile
private :eql?
end
end
end