BotSharp/BotSharp.Algorithm/HiddenMarkovModel/MathUtils/Distribution/LogNormal.cs
2018-09-17 07:31:54 -05:00

174 lines
5.1 KiB
C#

/// \file LogNormal.cs
/// <summary>
/// Contains the class representing a random number generator based on LogNormal distribution
/// </summary>
using BotSharp.Algorithm.HiddenMarkovModel.MathUtils.SpecialFunctions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BotSharp.Algorithm.HiddenMarkovModel.MathUtils.Distribution
{
/// <summary>
/// Class representing a random number generator based on LogNormal distribution
/// x is log-normally distributed if its natural logarithm log(x) is normally distributed. That is, log(x) ~ N(mu, sigma)
/// </summary>
public class LogNormal : Gaussian
{
private double mu = 0;
private double sigma = 0;
public LogNormal(double mu, double sigma)
: base(mu, sigma)
{
}
public double GeometricMean
{
get { return System.Math.Exp(mMean); }
}
public double GeometricStdDev
{
get { return System.Math.Exp(mStdDev); }
}
public Gaussian ToNormal()
{
double mu = mMean;
double sigma = mStdDev;
double normal_mu = System.Math.Exp(mu + 0.5 * sigma * sigma);
double normal_sigma = normal_mu * System.Math.Sqrt(System.Math.Exp(sigma * sigma) - 1);
Gaussian normalDistribution = new Gaussian(normal_mu, normal_sigma);
return normalDistribution;
}
/// <summary>
/// Method that returns a randomly generated number from a LogNormal distribution
/// </summary>
/// <returns></returns>
public override double Next()
{
return System.Math.Exp(GetNormal() * sigma + mu);
}
public override DistributionModel Clone()
{
LogNormal clone = new LogNormal(mMean, mStdDev);
clone.mu = mu;
clone.sigma = sigma;
return clone;
}
/// <summary>
/// Return the log of the PDF(x)
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
public override double LogProbabilityFunction(double x)
{
double z = (System.Math.Log(x) - mu) / sigma;
return -System.Math.Log(Constants.Sqrt2PI * sigma) + (-z * z) * 0.5 - System.Math.Log(x);
}
public override double GetPDF(double x)
{
double lnx = System.Math.Log(x);
return System.Math.Exp(-(lnx - mu) * (lnx - mu) / (2 * sigma * sigma)) / (x * sigma * Constants.Sqrt2PI);
}
public override double GetCDF(double x)
{
return 0.5 + 0.5 * ErrorFunction.GetErf((System.Math.Log(x) - mu) / (Constants.Sqrt2 * sigma));
}
/// <summary>
/// Method that computes the mean \f$\mu\f$ and standard deviation \f$\sigma\f$ for the random number generator from a sample of sample
/// </summary>
/// <param name="sample">The sample of sample</param>
public override void Process(double[] values)
{
int count = values.Length;
if (count == 0)
{
mMean = 0;
mStdDev = 0;
return;
}
double[] logValues = new double[count];
for (int i = 0; i < count; ++i)
{
logValues[i] = System.Math.Log(values[i]);
}
mu = logValues.Average();
double c = 0;
double sqr_sum_log = 0;
for (int i = 0; i < count; ++i)
{
c = (logValues[i] - mu);
sqr_sum_log += (c * c);
}
sigma = System.Math.Sqrt(sqr_sum_log / count);
mMean = System.Math.Exp(mu + sigma * sigma / 2);
mStdDev = System.Math.Exp(2 * mu + sigma * sigma) * (System.Math.Exp(sigma * sigma) - 1);
}
public override void Process(double[] values, double[] weights)
{
int count = values.Length;
double[] logValues = new double[count];
for (int i = 0; i < count; ++i)
{
logValues[i] = System.Math.Log(values[i]);
}
double sum = 0;
for (int i = 0; i < count; ++i)
{
sum += (logValues[i] * weights[i]);
}
double weight_sum = 0;
for (int i = 0; i < count; ++i)
{
weight_sum += weights[i];
}
mu = sum / weight_sum;
double sqr_sum = 0;
double c = 0;
double w = 0;
double a = 0;
double b = 0;
for (int i = 0; i < count; ++i)
{
c = (logValues[i] - mu);
w = weights[i];
sqr_sum += (w * c * c);
b += w;
a += w * w;
}
sigma = System.Math.Sqrt(sqr_sum * (b / (b * b - a)));
mMean = System.Math.Exp(mu + sigma * sigma / 2);
mStdDev = System.Math.Exp(2 * mu + sigma * sigma) * (System.Math.Exp(sigma * sigma) - 1);
}
}
}