/// \file Erlang.cs /// /// Contains the class representing a random number generator based on Erlang distribution Erlang(\f$k\f$, \f$\lambda\f$). /// using BotSharp.Algorithm.HiddenMarkovModel.MathHelpers; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BotSharp.Algorithm.HiddenMarkovModel.MathUtils.Distribution { /// /// Class representing a random number generator based on Erlang distribution Erlang(\f$k\f$, \f$\lambda\f$). /// \f$k\f$ represents the shape parameter of the Erlang distribution and \f$\lambda\f$ represents the rate parameter of the Erlang distribution ///
    ///
  1. The mean is \f$\mu = \frac{k}{\lambda}\f$
  2. ///
  3. The Variance is \f$\sigma^2 = \frac{k}{\lambda^2}\f$
  4. ///
  5. The skewness is \f$\frac{2}{\sqrt{k}}\f$
  6. ///
///
public class Erlang : DistributionModel { private double mLnConstant; /// /// Constructor with \f$k\f$ and \f$\lambda\f$ /// /// \f$k\f$ for Erlang(\f$k\f$, \f$\lambda\f$) /// \f$\lambda\f$ for Erlang(\f$k\f$, \f$\lambda\f$) public Erlang(int _k, double _lambda) { m_k = _k; m_lambda = _lambda; if (m_lambda != 0) { mMean = m_k / m_lambda; mStdDev = System.Math.Sqrt(m_k / (m_lambda * m_lambda)); } double theta = 1 / m_lambda; mLnConstant = -(m_k * System.Math.Log(theta) + Gamma.Log(m_k)); } /// /// Constructor /// public Erlang() { } public override double LogProbabilityFunction(double x) { double theta = 1 / m_lambda; return mLnConstant + (m_k - 1) * System.Math.Log(x) - x / theta; } public override double GetPDF(double x) { return System.Math.Exp(LogProbabilityFunction(x)); } public override double GetCDF(double x) { double sum = 0; for (int n = 0; n < m_k; ++n) { sum += System.Math.Exp(-m_lambda * x) * System.Math.Pow(m_lambda * x, n) / Factorial.GetFactorial(n); } return 1 - sum; } public override DistributionModel Clone() { return new Erlang(m_k, m_lambda); } /// /// Member variable representing the shape parameter of the Erlang distribution /// private int m_k; /// /// Property representing the shape parameter of the Erlang distribution /// public int k { get { return m_k; } set { m_k = value; } } /// /// Member variable representing the rate parameter of the Erlang distribution /// private double m_lambda; /// /// Member variable representing the rate parameter of the Erlang distribution /// public double lambda { get { return m_lambda; } set { m_lambda = value; } } /// /// Method that returns a double value randomly generated from the Erlang distribution Erlang(\f$k\f$, \f$\lambda\f$) /// /// A double value randomly generated from the Erlang distribution public override double Next() { double product = 1.0; for (int i = 0; i < k; i++) { product *= GetUniform(); } // Subtract product from 1.0 to avoid Math.Log(0.0) double r = -1.0 / lambda * System.Math.Log(product); return r; } public override void Process(double[] values) { double lnsum = 0; int count = values.Length; for (int i = 0; i < count; ++i) { lnsum += System.Math.Log(values[i]); } double mean = values.Average(); double s = System.Math.Log(mean) - lnsum / count; double newK = (3 - s + System.Math.Sqrt((s - 3) * (s - 3) + 24 * s)) / (12 * s); double oldK; do { oldK = newK; newK = oldK - (System.Math.Log(newK) - Gamma.Digamma(newK) - s) / ((1 / newK) - Gamma.Trigamma(newK)); } while (System.Math.Abs(oldK - newK) / System.Math.Abs(oldK) < double.Epsilon); double theta = mean / newK; m_lambda = 1 / theta; m_k = (int)newK; mLnConstant = -(m_k * System.Math.Log(theta) + Gamma.Log(m_k)); mMean = mean; mStdDev = System.Math.Sqrt(m_k) / m_lambda; } public override void Process(double[] values, double[] weights) { Process(values); } } }