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

137 lines
4.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BotSharp.Algorithm.HiddenMarkovModel.MathUtils.Distribution
{
public class ChiSquare
{
private static double logSqrtPi = System.Math.Log(System.Math.Sqrt(System.Math.PI));
private static double rezSqrtPi = 1 / System.Math.Sqrt(System.Math.PI);
private static double bigx = 20.0;
public const double EPSILON = .0000000001;
/// <summary>
/// Return the probability density function of a F-distribution
/// </summary>
/// <param name="F">reference value for the variable x following the F-distribution</param>
/// <param name="df">degrees of freedom</param>
/// <param name="deltaF"></param>
/// <returns>The probability densitiy function</returns>
public static double GetPDF(double F, int df, double deltaF = 0.0001)
{
double F1 = F - deltaF / 2;
double F2 = F + deltaF / 2;
if (F1 <= EPSILON)
{
F1 = F;
deltaF = deltaF / 2;
}
double p1 = GetPercentile(F1, df);
double p2 = GetPercentile(F2, df);
double areaP = p2 - p1;
return areaP / deltaF;
}
/// <summary>
/// Return the critical value F for p = P(x <= F), where p is the percentile
///
/// The implementation here is adapted from http://www.cs.umb.edu/~rickb/files/disc_proj/disc/weka/weka-3-2-3/weka/core/Statistics.java
/// </summary>
/// <param name="p">percentile P(x <= F)</param>
/// <param name="df">degrees of freedom of numerator</param>
/// <returns>The critical value F for p = P(x <= F)</returns>
public static double GetQuantile(double p, int df)
{
double fval;
double maxf = 99999.0;
double minf = .000001;
if (p <= 0.0 || p >= 1.0)
return (0.0);
fval = 1.0 / p; // initial value for guess fval, the smaller the p, the larger the F
while (System.Math.Abs(maxf - minf) > .000001)
{
if (GetPercentile(fval, df) > p) // F too large
maxf = fval;
else // F too small
minf = fval;
fval = (maxf + minf) * 0.5;
}
return (fval);
}
/// <summary>
/// Return the P(y < x) where y follows the Chi^2 distribution
/// </summary>
/// <param name="x">reference value for y which follows the Chi^2 distribution</param>
/// <param name="df">degrees of freedom</param>
/// <returns>The cumulative probability P(y < x)</returns>
public static double GetPercentile(double x, int df)
{
return 1 - ChiSquaredProbability(x, df);
}
/// <summary>
/// Return the P(y > x) where y follows the Chi^2 distribution
///
/// The implementation here is adapted from http://www.cs.umb.edu/~rickb/files/disc_proj/disc/weka/weka-3-2-3/weka/core/Statistics.java
/// </summary>
/// <param name="x">reference value for y which follows the Chi^2 distribution</param>
/// <param name="df">degrees of freedom</param>
/// <returns>The probability P(y > x)</returns>
private static double ChiSquaredProbability(double x, int df)
{
double a, y = 0, s, e, c, z, val;
bool even;
if (x <= 0 || df < 1)
return (1);
a = 0.5 * x;
even = (((int)(2 * (df / 2))) == df);
if (df > 1)
y = System.Math.Exp(-a); //((-a < -bigx) ? 0.0 : Math.exp (-a));
s = (even ? y : (2.0 * Gaussian.GetPercentile(-System.Math.Sqrt(x))));
if (df > 2)
{
x = 0.5 * (df - 1.0);
z = (even ? 1.0 : 0.5);
if (a > bigx)
{
e = (even ? 0.0 : logSqrtPi);
c = System.Math.Log(a);
while (z <= x)
{
e = System.Math.Log(z) + e;
val = c * z - a - e;
s += System.Math.Exp(val); //((val < -bigx) ? 0.0 : Math.exp (val));
z += 1.0;
}
return (s);
}
else
{
e = (even ? 1.0 : (rezSqrtPi / System.Math.Sqrt(a)));
c = 0.0;
while (z <= x)
{
e = e * (a / z);
c = c + e;
z += 1.0;
}
return (c * y + s);
}
}
else
{
return (s);
}
}
}
}