Migrated StudentT distribution to shape fitter
This commit is contained in:
		
							parent
							
								
									3bf829d684
								
							
						
					
					
						commit
						b662d08c9c
					
				| @ -1,36 +0,0 @@ | ||||
| using System; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| namespace FastRng.Double.Distributions | ||||
| { | ||||
|     public sealed class StudentT : IDistribution | ||||
|     { | ||||
|         private static readonly IDistribution NORMAL_DISTRIBUTED = new Normal(); | ||||
|         private double degreesOfFreedom = 1.0; | ||||
|          | ||||
|         public IRandom Random { get; set; } | ||||
|          | ||||
|         public double DegreesOfFreedom | ||||
|         { | ||||
|             get => this.degreesOfFreedom; | ||||
|             set | ||||
|             { | ||||
|                 if(value <= 0.0) | ||||
|                     throw new ArgumentOutOfRangeException(message: "DegreesOfFreedom must be greater than 0", null); | ||||
|                  | ||||
|                 this.degreesOfFreedom = value; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         public async ValueTask<double> GetDistributedValue(CancellationToken token = default) | ||||
|         { | ||||
|             if (this.Random == null) | ||||
|                 return double.NaN; | ||||
| 
 | ||||
|             var normal = await this.Random.NextNumber(NORMAL_DISTRIBUTED, token); | ||||
|             var chiSquare = await this.Random.NextNumber(new ChiSquare {DegreesOfFreedom = this.DegreesOfFreedom}, token); | ||||
|             return normal / Math.Sqrt(chiSquare / this.DegreesOfFreedom); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										48
									
								
								FastRng/Double/Distributions/StudentTNu1.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								FastRng/Double/Distributions/StudentTNu1.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| using System; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| namespace FastRng.Double.Distributions | ||||
| { | ||||
|     public sealed class StudentTNu1 : IDistribution | ||||
|     { | ||||
|         private const double NU = 1.0; | ||||
|         private const double START = 0.0; | ||||
|         private const double COMPRESS = 1.0; | ||||
|         private const double CONSTANT = 3.14190548592729; | ||||
|          | ||||
|         private static readonly double DIVIDEND; | ||||
|         private static readonly double DIVISOR; | ||||
|         private static readonly double EXPONENT; | ||||
|          | ||||
|         private ShapeFitter fitter; | ||||
|         private IRandom random; | ||||
| 
 | ||||
|         static StudentTNu1() | ||||
|         { | ||||
|             DIVIDEND = MathTools.Gamma((NU + 1.0d) * 0.5d); | ||||
|             DIVISOR = Math.Sqrt(NU * Math.PI) * MathTools.Gamma(NU * 0.5d); | ||||
|             EXPONENT = -((NU + 1.0d) * 0.5d); | ||||
|         } | ||||
|          | ||||
|         public IRandom Random | ||||
|         { | ||||
|             get => this.random; | ||||
|             set | ||||
|             { | ||||
|                 this.random = value; | ||||
|                 this.fitter = new ShapeFitter(StudentTNu1.ShapeFunction, this.random, 100); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static double ShapeFunction(double x) => CONSTANT * Math.Pow((DIVIDEND / DIVISOR) * Math.Pow(1.0d + Math.Pow(START + x * COMPRESS, 2) / NU, EXPONENT), COMPRESS); | ||||
| 
 | ||||
|         public async ValueTask<double> GetDistributedValue(CancellationToken token = default) | ||||
|         { | ||||
|             if (this.Random == null) | ||||
|                 return double.NaN; | ||||
|              | ||||
|             return await this.fitter.NextNumber(token); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -8,30 +8,40 @@ using NUnit.Framework; | ||||
| namespace FastRngTests.Double.Distributions | ||||
| { | ||||
|     [ExcludeFromCodeCoverage] | ||||
|     public class StudentT | ||||
|     public class StudentTNu1 | ||||
|     { | ||||
|         [Test] | ||||
|         [Category(TestCategories.COVER)] | ||||
|         [Category(TestCategories.NORMAL)] | ||||
|         public async Task TestStudentTDistribution01() | ||||
|         { | ||||
|             const double DOF = 6; | ||||
|             const double MEAN = 0.0; | ||||
|             const double VARIANCE = DOF / (DOF - 2); | ||||
|              | ||||
|             var dist = new FastRng.Double.Distributions.StudentT{ DegreesOfFreedom = DOF }; | ||||
|             var stats = new RunningStatistics(); | ||||
|             var dist = new FastRng.Double.Distributions.StudentTNu1(); | ||||
|             var fra = new FrequencyAnalysis(); | ||||
|             var rng = new MultiThreadedRng(); | ||||
|              | ||||
|             for (var n = 0; n < 100_000; n++) | ||||
|                 stats.Push(await rng.NextNumber(dist)); | ||||
|                 fra.CountThis(await rng.NextNumber(dist)); | ||||
|              | ||||
|             rng.StopProducer(); | ||||
|             TestContext.WriteLine($"mean={MEAN} vs. {stats.Mean}"); | ||||
|             TestContext.WriteLine($"variance={VARIANCE} vs {stats.Variance}"); | ||||
|             var result = fra.NormalizeAndPlotEvents(TestContext.WriteLine); | ||||
| 
 | ||||
|             Assert.That(result[0], Is.EqualTo(1.000000000).Within(0.2)); | ||||
|             Assert.That(result[1], Is.EqualTo(0.999700120).Within(0.2)); | ||||
|             Assert.That(result[2], Is.EqualTo(0.999200719).Within(0.2)); | ||||
|              | ||||
|             Assert.That(stats.Mean, Is.EqualTo(MEAN).Within(0.1), "Mean is out of range"); | ||||
|             Assert.That(stats.Variance, Is.EqualTo(VARIANCE).Within(0.1), "Variance is out of range"); | ||||
|             Assert.That(result[21], Is.EqualTo(0.953929798).Within(0.2)); | ||||
|             Assert.That(result[22], Is.EqualTo(0.949852788).Within(0.2)); | ||||
|             Assert.That(result[23], Is.EqualTo(0.945631619).Within(0.2)); | ||||
|              | ||||
|             Assert.That(result[50], Is.EqualTo(0.793667169).Within(0.095)); | ||||
|              | ||||
|             Assert.That(result[75], Is.EqualTo(0.633937627).Within(0.09)); | ||||
|             Assert.That(result[85], Is.EqualTo(0.574902276).Within(0.09)); | ||||
|             Assert.That(result[90], Is.EqualTo(0.547070729).Within(0.09)); | ||||
|              | ||||
|             Assert.That(result[97], Is.EqualTo(0.510150990).Within(0.09)); | ||||
|             Assert.That(result[98], Is.EqualTo(0.505075501).Within(0.09)); | ||||
|             Assert.That(result[99], Is.EqualTo(0.500050000).Within(0.09)); | ||||
|         } | ||||
|          | ||||
|         [Test] | ||||
| @ -40,9 +50,10 @@ namespace FastRngTests.Double.Distributions | ||||
|         public async Task TestStudentTGeneratorWithRange01() | ||||
|         { | ||||
|             var rng = new MultiThreadedRng(); | ||||
|             var dist = new FastRng.Double.Distributions.StudentTNu1(); | ||||
|             var samples = new double[1_000]; | ||||
|             for (var n = 0; n < samples.Length; n++) | ||||
|                 samples[n] = await rng.NextNumber(-1.0, 1.0, new FastRng.Double.Distributions.StudentT()); | ||||
|                 samples[n] = await rng.NextNumber(-1.0, 1.0, dist); | ||||
|              | ||||
|             rng.StopProducer(); | ||||
|             Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(-1.0), "Min out of range"); | ||||
| @ -55,9 +66,10 @@ namespace FastRngTests.Double.Distributions | ||||
|         public async Task TestStudentTGeneratorWithRange02() | ||||
|         { | ||||
|             var rng = new MultiThreadedRng(); | ||||
|             var dist = new FastRng.Double.Distributions.StudentTNu1(); | ||||
|             var samples = new double[1_000]; | ||||
|             for (var n = 0; n < samples.Length; n++) | ||||
|                 samples[n] = await rng.NextNumber(0.0, 1.0, new FastRng.Double.Distributions.StudentT()); | ||||
|                 samples[n] = await rng.NextNumber(0.0, 1.0, dist); | ||||
|              | ||||
|             rng.StopProducer(); | ||||
|             Assert.That(samples.Min(), Is.GreaterThanOrEqualTo(0.0), "Min is out of range"); | ||||
| @ -70,7 +82,7 @@ namespace FastRngTests.Double.Distributions | ||||
|         public async Task TestStudentTGeneratorWithRange03() | ||||
|         { | ||||
|             var rng = new MultiThreadedRng(); | ||||
|             var dist = new FastRng.Double.Distributions.StudentT { Random = rng }; // Test default parameters | ||||
|             var dist = new FastRng.Double.Distributions.StudentTNu1 { Random = rng }; // Test default parameters | ||||
|              | ||||
|             var samples = new double[1_000]; | ||||
|             for (var n = 0; n < samples.Length; n++) | ||||
| @ -81,25 +93,12 @@ namespace FastRngTests.Double.Distributions | ||||
|             Assert.That(samples.Max(), Is.LessThanOrEqualTo(1.0), "Max is out of range"); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         [Category(TestCategories.COVER)] | ||||
|         [Category(TestCategories.NORMAL)] | ||||
|         public void ParameterTest01() | ||||
|         { | ||||
|             var dist = new FastRng.Double.Distributions.StudentT(); | ||||
|              | ||||
|             Assert.Throws<ArgumentOutOfRangeException>(() => dist.DegreesOfFreedom = 0); | ||||
|             Assert.Throws<ArgumentOutOfRangeException>(() => dist.DegreesOfFreedom = -78); | ||||
|             Assert.DoesNotThrow(() => dist.DegreesOfFreedom = 0.0001); | ||||
|             Assert.DoesNotThrow(() => dist.DegreesOfFreedom = 4); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         [Category(TestCategories.COVER)] | ||||
|         [Category(TestCategories.NORMAL)] | ||||
|         public async Task NoRandomNumberGenerator01() | ||||
|         { | ||||
|             var dist = new FastRng.Double.Distributions.StudentT(); | ||||
|             var dist = new FastRng.Double.Distributions.StudentTNu1(); | ||||
|             Assert.DoesNotThrowAsync(async () => await dist.GetDistributedValue()); | ||||
|             Assert.That(await dist.GetDistributedValue(), Is.NaN); | ||||
|         } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user