using System; namespace Amphora.UnitTests { public class KumaraswamyCurveTests : UnitTestSharp.TestFixture { public static readonly double[] QuantileA = { 2, 2, 2, 0.5, 5, 3, 10, 1.5, 0.1, 100, 2, 1000, 2 }; public static readonly double[] QuantileB = { 3, 3, 3, 2, 0.5, 3, 10, 30, 0.1, 100, 0.001, 2, 3 }; public static readonly double[] QuantileProbability = { 0.5, 0.25, 0.75, 0.75, 0.25, 0.9375, 0.5, 0.125, 0.5, 0.5, 0.5, 0.5, 0.0000152587890625, }; public static readonly double[] QuantileExpected = { 0.4542020189474065, 0.30238998591873073, 0.6083087004577227, 0.25, 0.8476091015362177, 0.8449059741592636, 0.7631081465177699, 0.02701866996881778, 0.9902771787762996, 0.9514658644461612, 1.0, 0.998772806441336, 0.002255280224522921, }; public static readonly double[] ShapeMode = { 0.3, 0.5, 0.9, 0.01, 0.5 }; public static readonly double[] ShapeTightness = { 4, 10, 100, 1000, 1000 }; public static readonly double[] ShapeA = { 2.2, 6.0, 91.0, 11.0, 501.0 }; public static readonly double[] ShapeB = { 8.165209918420558, 53.5, 14425.573536022344, 9.090909090909091e+21, 6.533713788215852e+150, }; public class QuantileTests : UnitTestSharp.TestFixture { public void ReferenceValues_AreWithinAFewUlps() { for (int i = 0; i < QuantileA.Length; i++) { double actual = KumaraswamyCurve.Quantile(QuantileA[i], QuantileB[i], QuantileProbability[i]); CheckLess(PortableMathTests.UlpsApart(QuantileExpected[i], actual), 9L); } } public void ProbabilityOfZero_IsZero() { CheckEqual(0.0, KumaraswamyCurve.Quantile(2.0, 3.0, 0.0)); } public void ProbabilityOfOne_IsOne() { CheckEqual(1.0, KumaraswamyCurve.Quantile(2.0, 3.0, 1.0)); } public void ShapesOfOne_AreFlat() { foreach (double probability in new[] { 0.1, 0.5, 0.9 }) { double actual = KumaraswamyCurve.Quantile(1.0, 1.0, probability); CheckLess(PortableMathTests.UlpsApart(probability, actual), 5L); } } public void RisesWithTheProbability() { double previous = 0.0; for (int step = 1; step <= 64; step++) { double current = KumaraswamyCurve.Quantile(2.5, 4.0, step / 64.0); CheckTrue(current >= previous); previous = current; } } public void ShapeOfZero_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KumaraswamyCurve.Quantile(0.0, 1.0, 0.5); } public void NegativeShape_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KumaraswamyCurve.Quantile(1.0, -1.0, 0.5); } public void InfiniteShape_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KumaraswamyCurve.Quantile(double.PositiveInfinity, 1.0, 0.5); } public void NotANumberShape_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KumaraswamyCurve.Quantile(1.0, double.NaN, 0.5); } public void ProbabilityBelowZero_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KumaraswamyCurve.Quantile(1.0, 1.0, -0.1); } public void ProbabilityAboveOne_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KumaraswamyCurve.Quantile(1.0, 1.0, 1.1); } public void NotANumberProbability_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KumaraswamyCurve.Quantile(1.0, 1.0, double.NaN); } } public class ShapeForTests : UnitTestSharp.TestFixture { public void ReferenceValues_AreCloseToTheirRelativeTrillionth() { for (int i = 0; i < ShapeMode.Length; i++) { double a; double b; KumaraswamyCurve.ShapeFor(ShapeMode[i], ShapeTightness[i], out a, out b); CheckLess(PortableMathTests.RelativeError(ShapeA[i], a), 1e-13); CheckLess(PortableMathTests.RelativeError(ShapeB[i], b), 1e-13); } } public void ZeroTightness_IsFlatWhereverTheMode() { foreach (double mode in new[] { 0.0, 0.3, 1.0 }) { double a; double b; KumaraswamyCurve.ShapeFor(mode, 0.0, out a, out b); CheckEqual(1.0, a); CheckEqual(1.0, b); } } public void ModeAtTheStart_FallsAwayFromIt() { double a; double b; KumaraswamyCurve.ShapeFor(0.0, 4.0, out a, out b); CheckEqual(1.0, a); CheckEqual(5.0, b); } public void ModeAtTheEnd_RisesToIt() { double a; double b; KumaraswamyCurve.ShapeFor(1.0, 4.0, out a, out b); CheckEqual(5.0, a); CheckEqual(1.0, b); } public void PeakIsWhereAskedFor() { foreach (double mode in new[] { 0.1, 0.3, 0.5, 0.9 }) { foreach (double tightness in new[] { 1.0, 4.0, 10.0, 100.0 }) { double a; double b; KumaraswamyCurve.ShapeFor(mode, tightness, out a, out b); double peak = Math.Pow((a - 1.0) / (a * b - 1.0), 1.0 / a); CheckLess(Math.Abs(peak - mode), 1e-12); } } } public void MostTightness_StaysFinite() { double a; double b; KumaraswamyCurve.ShapeFor(0.5, KumaraswamyCurve.MostTightness, out a, out b); CheckTrue(!double.IsInfinity(b) && !double.IsNaN(b)); } public void ModeBelowZero_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); double a; double b; KumaraswamyCurve.ShapeFor(-0.1, 4.0, out a, out b); } public void ModeAboveOne_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); double a; double b; KumaraswamyCurve.ShapeFor(1.1, 4.0, out a, out b); } public void NotANumberMode_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); double a; double b; KumaraswamyCurve.ShapeFor(double.NaN, 4.0, out a, out b); } public void NegativeTightness_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); double a; double b; KumaraswamyCurve.ShapeFor(0.5, -1.0, out a, out b); } public void TightnessPastTheMost_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); double a; double b; KumaraswamyCurve.ShapeFor(0.5, KumaraswamyCurve.MostTightness * 1.001, out a, out b); } public void NotANumberTightness_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); double a; double b; KumaraswamyCurve.ShapeFor(0.5, double.NaN, out a, out b); } } } }