@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2010 Math.NET
// Copyright (c) 2009-2013 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -28,11 +28,12 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.Properties ;
using System.Collections.Generic ;
namespace MathNet.Numerics.Distributions
{
using System ;
using System.Collections.Generic ;
using Properties ;
/// <summary>
/// This class implements functionality for the Hypergeometric distribution. This distribution is
@ -50,19 +51,19 @@ namespace MathNet.Numerics.Distributions
public class Hypergeometric : IDiscreteDistribution
{
/// <summary>
/// The size of the population.
/// The size of the population (N) .
/// </summary>
int _ populationSize ;
int _ population ;
/// <summary>
/// The m parameter of the distribution .
/// The number successes within the population (K, M) .
/// </summary>
int _ m ;
int _ success ;
/// <summary>
/// The n parameter (number to draw) of the distribution .
/// The number of draws without replacement (n) .
/// </summary>
int _ n ;
int _d raws ;
/// <summary>
/// The distribution's random number generator.
@ -72,61 +73,61 @@ namespace MathNet.Numerics.Distributions
/// <summary>
/// Initializes a new instance of the Hypergeometric class.
/// </summary>
/// <param name="populationSize">The population size .</param>
/// <param name="m">The m parameter of the distribution .</param>
/// <param name="n">The n parameter of the distribution .</param>
public Hypergeometric ( int populationSize , int m , int n )
/// <param name="population">The size of the population (N) .</param>
/// <param name="success">The number successes within the population (K, M) .</param>
/// <param name="draws">The number of draws without replacement (n) .</param>
public Hypergeometric ( int population , int success , int draws )
{
_ random = new Random ( ) ;
SetParameters ( populationSize , m , n ) ;
SetParameters ( population , success , draws ) ;
}
/// <summary>
/// Initializes a new instance of the Hypergeometric class.
/// </summary>
/// <param name="populationSize">The population size .</param>
/// <param name="m">The m parameter of the distribution .</param>
/// <param name="n">The n parameter of the distribution .</param>
/// <param name="population">The size of the population (N) .</param>
/// <param name="success">The number successes within the population (K, M) .</param>
/// <param name="draws">The number of draws without replacement (n) .</param>
/// <param name="randomSource">The random number generator which is used to draw random samples.</param>
public Hypergeometric ( int populationSize , int m , int n , Random randomSource )
public Hypergeometric ( int population , int success , int draws , Random randomSource )
{
_ random = randomSource ? ? new Random ( ) ;
SetParameters ( populationSize , m , n ) ;
SetParameters ( population , success , draws ) ;
}
/// <summary>
/// Sets the parameters of the distribution after checking their validity.
/// </summary>
/// <param name="total">The Total parameter of the distribution .</param>
/// <param name="m">The m parameter of the distribution .</param>
/// <param name="n">The n parameter of the distribution .</param>
void SetParameters ( int total , int m , int n )
/// <param name="population">The size of the population (N) .</param>
/// <param name="success">The number successes within the population (K, M) .</param>
/// <param name="draws">The number of draws without replacement (n) .</param>
void SetParameters ( int population , int success , int draws )
{
if ( Control . CheckDistributionParameters & & ! IsValidParameterSet ( total , m , n ) )
if ( Control . CheckDistributionParameters & & ! IsValidParameterSet ( population , success , draws ) )
{
throw new ArgumentOutOfRangeException ( Resources . InvalidDistributionParameters ) ;
}
_ populationSize = total ;
_ m = m ;
_ n = n ;
_ population = population ;
_ success = success ;
_d raws = draws ;
}
/// <summary>
/// Checks whether the parameters of the distribution are valid.
/// </summary>
/// <param name="total">The Total parameter of the distribution .</param>
/// <param name="m">The m parameter of the distribution .</param>
/// <param name="n">The n parameter of the distribution .</param>
/// <param name="population">The size of the population (N) .</param>
/// <param name="success">The number successes within the population (K, M) .</param>
/// <param name="draws">The number of draws without replacement (n) .</param>
/// <returns><c>true</c> when the parameters are valid, <c>false</c> otherwise.</returns>
static bool IsValidParameterSet ( int total , int m , int n )
static bool IsValidParameterSet ( int population , int success , int draws )
{
if ( total < 0 | | m < 0 | | n < 0 )
if ( population < 0 | | success < 0 | | draws < 0 )
{
return false ;
}
if ( m > total | | n > total )
if ( success > population | | draws > population )
{
return false ;
}
@ -135,30 +136,60 @@ namespace MathNet.Numerics.Distributions
}
/// <summary>
/// Gets or sets the population size.
/// Gets or sets the size of the population (N).
/// </summary>
public int Population
{
get { return _ population ; }
set { SetParameters ( value , _ success , _d raws ) ; }
}
/// <summary>
/// Gets or sets the number of draws without replacement (n).
/// </summary>
public int Draws
{
get { return _d raws ; }
set { SetParameters ( _ population , value , _d raws ) ; }
}
/// <summary>
/// Gets or sets the number successes within the population (K, M).
/// </summary>
public int Success
{
get { return _ success ; }
set { SetParameters ( _ population , _ success , value ) ; }
}
/// <summary>
/// Gets or sets the size of the population (N).
/// </summary>
[Obsolete("Use Population instead. Scheduled for removal in v3.0.")]
public int PopulationSize
{
get { return _ populationSize ; }
set { SetParameters ( value , _ m , _ n ) ; }
get { return _ population ; }
set { SetParameters ( value , _ success , _d raws ) ; }
}
/// <summary>
/// Gets or sets the n parameter of the distribution.
/// Gets or sets the number of draws without replacement (n) .
/// </summary>
[Obsolete("Use Draws instead. Scheduled for removal in v3.0.")]
public int N
{
get { return _ n ; }
set { SetParameters ( _ populationSize , value , _ n ) ; }
get { return _d raws ; }
set { SetParameters ( _ population , value , _d raws ) ; }
}
/// <summary>
/// Gets or sets the m parameter of the distribution.
/// Gets or sets the number successes within the population (K, M) .
/// </summary>
[Obsolete("Use Success instead. Scheduled for removal in v3.0.")]
public int M
{
get { return _ m ; }
set { SetParameters ( _ populationSize , _ m , value ) ; }
get { return _ success ; }
set { SetParameters ( _ population , _ success , value ) ; }
}
/// <summary>
@ -169,11 +200,9 @@ namespace MathNet.Numerics.Distributions
/// </returns>
public override string ToString ( )
{
return "Hypergeometric(N = " + _ populationSize + ", m = " + _ m + ", n = " + _ n + ")" ;
return "Hypergeometric(N = " + _ population + ", M = " + _ success + ", n = " + _d raws + ")" ;
}
#region IDistribution Members
/// <summary>
/// Gets or sets the random number generator which is used to draw random samples.
/// </summary>
@ -196,7 +225,7 @@ namespace MathNet.Numerics.Distributions
/// </summary>
public double Mean
{
get { return ( double ) _ m * _ n / _ populationSize ; }
get { return ( double ) _ success * _d raws / _ population ; }
}
/// <summary>
@ -204,7 +233,7 @@ namespace MathNet.Numerics.Distributions
/// </summary>
public double Variance
{
get { return _ n * _ m * ( _ populationSize - _ n ) * ( _ populationSize - _ m ) / ( _ populationSize * _ populationSize * ( _ populationSize - 1.0 ) ) ; }
get { return _d raws * _ success * ( _ population - _d raws ) * ( _ population - _ success ) / ( _ population * _ population * ( _ population - 1.0 ) ) ; }
}
/// <summary>
@ -228,48 +257,15 @@ namespace MathNet.Numerics.Distributions
/// </summary>
public double Skewness
{
get { return ( Math . Sqrt ( _ populationSize - 1.0 ) * ( _ populationSize - ( 2 * _ n ) ) * ( _ populationSize - ( 2 * _ m ) ) ) / ( Math . Sqrt ( _ n * _ m * ( _ populationSize - _ m ) * ( _ populationSize - _ n ) ) * ( _ populationSize - 2.0 ) ) ; }
}
/// <summary>
/// Computes the cumulative distribution function of the distribution.
/// </summary>
/// <param name="x">The location at which to compute the cumulative density.</param>
/// <returns>the cumulative density at <paramref name="x"/>.</returns>
public double CumulativeDistribution ( double x )
{
int alpha = Minimum ;
int beta = Maximum ;
if ( x < = alpha )
{
return 0.0 ;
}
if ( x > beta )
{
return 1.0 ;
}
var sum = 0.0 ;
var k = ( int ) Math . Ceiling ( x - alpha ) - 1 ;
for ( var i = alpha ; i < = alpha + k ; i + + )
{
sum + = SpecialFunctions . Binomial ( _ m , i ) * SpecialFunctions . Binomial ( _ populationSize - _ m , _ n - i ) ;
}
return sum / SpecialFunctions . Binomial ( _ populationSize , _ n ) ;
get { return ( Math . Sqrt ( _ population - 1.0 ) * ( _ population - ( 2 * _d raws ) ) * ( _ population - ( 2 * _ success ) ) ) / ( Math . Sqrt ( _d raws * _ success * ( _ population - _ success ) * ( _ population - _d raws ) ) * ( _ population - 2.0 ) ) ; }
}
#endregion
#region IDiscreteDistribution Members
/// <summary>
/// Gets the mode of the distribution.
/// </summary>
public int Mode
{
get { return ( _ n + 1 ) * ( _ m + 1 ) / ( _ populationSize + 2 ) ; }
get { return ( _d raws + 1 ) * ( _ success + 1 ) / ( _ population + 2 ) ; }
}
/// <summary>
@ -285,7 +281,7 @@ namespace MathNet.Numerics.Distributions
/// </summary>
public int Minimum
{
get { return Math . Max ( 0 , _ n + _ m - _ populationSize ) ; }
get { return Math . Max ( 0 , _d raws + _ success - _ population ) ; }
}
/// <summary>
@ -293,11 +289,11 @@ namespace MathNet.Numerics.Distributions
/// </summary>
public int Maximum
{
get { return Math . Min ( _ m , _ n ) ; }
get { return Math . Min ( _ success , _d raws ) ; }
}
/// <summary>
/// Computes values of the probability mass function.
/// Computes values of the probability mass function (PMF), i.e. P(X = x) .
/// </summary>
/// <param name="k">The location in the domain where we want to evaluate the probability mass function.</param>
/// <returns>
@ -305,11 +301,11 @@ namespace MathNet.Numerics.Distributions
/// </returns>
public double Probability ( int k )
{
return SpecialFunctions . Binomial ( _ m , k ) * SpecialFunctions . Binomial ( _ populationSize - _ m , _ n - k ) / SpecialFunctions . Binomial ( _ populationSize , _ n ) ;
return SpecialFunctions . Binomial ( _ success , k ) * SpecialFunctions . Binomial ( _ population - _ success , _d raws - k ) / SpecialFunctions . Binomial ( _ population , _d raws ) ;
}
/// <summary>
/// Computes values of the log probability mass function.
/// Computes values of the log probability mass function (lnPMF), i.e. ln(P(X = x)) .
/// </summary>
/// <param name="k">The location in the domain where we want to evaluate the log probability mass function.</param>
/// <returns>
@ -320,33 +316,57 @@ namespace MathNet.Numerics.Distributions
return Math . Log ( Probability ( k ) ) ;
}
#endregion
/// <summary>
/// Computes the cumulative distribution function (CDF) of the distribution, i.e. P(X <= x).
/// </summary>
/// <param name="x">The location at which to compute the cumulative density.</param>
/// <returns>the cumulative density at <paramref name="x"/>.</returns>
public double CumulativeDistribution ( double x )
{
if ( x < Minimum )
{
return 0.0 ;
}
if ( x > = Maximum )
{
return 1.0 ;
}
var k = ( int ) Math . Floor ( x ) ;
var denominatorLn = SpecialFunctions . BinomialLn ( _ population , _d raws ) ;
var sum = 0.0 ;
for ( var i = 0 ; i < = k ; i + + )
{
sum + = Math . Exp ( SpecialFunctions . BinomialLn ( _ success , i ) + SpecialFunctions . BinomialLn ( _ population - _ success , _d raws - i ) - denominatorLn ) ;
}
return sum ;
}
/// <summary>
/// Generates a sample from the Hypergeometric distribution without doing parameter checking.
/// </summary>
/// <param name="rnd">The random number generator to use.</param>
/// <param name="size">The Total parameter of the distribution.</param>
/// <param name="m">The m parameter of the distribution.</param>
/// <param name="n">The n parameter of the distribution.</param>
/// <param name="population">The size of the population (N) .</param>
/// <param name="success">The number successes within the population (K, M) .</param>
/// <param name="draws ">The n parameter of the distribution.</param>
/// <returns>a random number from the Hypergeometric distribution.</returns>
internal static int SampleUnchecked ( Random rnd , int size , int m , int n )
internal static int SampleUnchecked ( Random rnd , int population , int success , int draws )
{
var x = 0 ;
do
{
var p = ( double ) m / size ;
var p = ( double ) success / population ;
var r = rnd . NextDouble ( ) ;
if ( r < p )
{
x + + ;
m - - ;
success - - ;
}
size - - ;
n - - ;
} while ( 0 < n ) ;
population - - ;
draws - - ;
} while ( 0 < draws ) ;
return x ;
}
@ -357,7 +377,7 @@ namespace MathNet.Numerics.Distributions
/// <returns>The number of successes in n trials.</returns>
public int Sample ( )
{
return SampleUnchecked ( RandomSource , _ populationSize , _ m , _ n ) ;
return SampleUnchecked ( RandomSource , _ population , _ success , _d raws ) ;
}
/// <summary>
@ -368,7 +388,7 @@ namespace MathNet.Numerics.Distributions
{
while ( true )
{
yield return SampleUnchecked ( RandomSource , _ populationSize , _ m , _ n ) ;
yield return SampleUnchecked ( RandomSource , _ population , _ success , _d raws ) ;
}
}
@ -376,36 +396,36 @@ namespace MathNet.Numerics.Distributions
/// Samples a random variable.
/// </summary>
/// <param name="rnd">The random number generator to use.</param>
/// <param name="populationSize">The population size .</param>
/// <param name="m">The m parameter of the distribution .</param>
/// <param name="n">The n parameter of the distribution .</param>
public static int Sample ( Random rnd , int populationSize , int m , int n )
/// <param name="population">The size of the population (N) .</param>
/// <param name="success">The number successes within the population (K, M) .</param>
/// <param name="draws">The number of draws without replacement (n) .</param>
public static int Sample ( Random rnd , int population , int success , int draws )
{
if ( Control . CheckDistributionParameters & & ! IsValidParameterSet ( populationSize , m , n ) )
if ( Control . CheckDistributionParameters & & ! IsValidParameterSet ( population , success , draws ) )
{
throw new ArgumentOutOfRangeException ( Resources . InvalidDistributionParameters ) ;
}
return SampleUnchecked ( rnd , populationSize , m , n ) ;
return SampleUnchecked ( rnd , population , success , draws ) ;
}
/// <summary>
/// Samples a sequence of this random variable.
/// </summary>
/// <param name="rnd">The random number generator to use.</param>
/// <param name="populationSize">The population size .</param>
/// <param name="m">The m parameter of the distribution .</param>
/// <param name="n">The n parameter of the distribution .</param>
public static IEnumerable < int > Samples ( Random rnd , int populationSize , int m , int n )
/// <param name="population">The size of the population (N) .</param>
/// <param name="success">The number successes within the population (K, M) .</param>
/// <param name="draws">The number of draws without replacement (n) .</param>
public static IEnumerable < int > Samples ( Random rnd , int population , int success , int draws )
{
if ( Control . CheckDistributionParameters & & ! IsValidParameterSet ( populationSize , m , n ) )
if ( Control . CheckDistributionParameters & & ! IsValidParameterSet ( population , success , draws ) )
{
throw new ArgumentOutOfRangeException ( Resources . InvalidDistributionParameters ) ;
}
while ( true )
{
yield return SampleUnchecked ( rnd , populationSize , m , n ) ;
yield return SampleUnchecked ( rnd , population , success , draws ) ;
}
}
}