vaibhav-y/statistical

View on GitHub
lib/statistical/distribution/weibull.rb

Summary

Maintainability
A
0 mins
Test Coverage
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 [Float] scale The distribution's scale parameter
    # @attr_reader [Float] shape The distribution's shape parameter
    class Weibull
      attr_reader :scale, :shape, :support

      # Returns a new `Statistical::Distribution::Weibull` instance
      #
      # @param [Numeric] scale The distribution's scale parameter
      # @param [Numeric] shape The distribution's shape parameter
      # @return `Statistical::Distribution::Weibull` instance
      def initialize(scale = 1, shape = 1)
        @scale = scale.to_f
        @shape = shape.to_f
        @support = Domain[0.0, Float::INFINITY, :right_open]
        self
      end

      # Returns value of probability density function at a point. Calculated
      #   using some technique that you might want to name
      #
      # @param [Numeric] x A real valued point
      # @return
      def pdf(x)
        return [(@shape / @scale) * ((x / @scale)**(@shape - 1)) *
                Math.exp(-((x / @scale)**@shape)),
                0.0,
                0.0][@support <=> x]
      end

      # Returns value of cumulative density function at a point. Calculated
      #   using some technique that you might want to name
      #
      # @param [Numeric] x A real valued point
      # @return
      def cdf(x)
        return [1 - Math.exp(-((x / @scale)**@shape)),
                1.0,
                0.0][@support <=> x]
      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 @scale * ((-Math.log(1 - p))**(1 / @shape))
      end

      # Returns the expected value of mean for the calling instance.
      #
      # @return Mean of the distribution
      def mean
        return @scale * Math.gamma(1 + 1 / @shape)
      end

      # Returns the expected value of variance for the calling instance.
      #
      # @return Variance of the distribution
      def variance
        m = mean
        (@scale * @scale) * Math.gamma(1 + 2 / @shape) - (m * m)
      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 other.is_a?(self.class) &&
               other.shape == @shape &&
               other.scale == @scale
      end

      alias :== :eql?
      alias :p_value :quantile

      private :eql?
    end
  end
end