From cd875f52cdd34384bcab562580f67f82381320aa Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 6 Oct 2018 21:47:45 +0200 Subject: [PATCH] More distribution tests --- .../Distribution/LaplaceDistribution.php | 6 +- .../Distribution/NormalDistribution.php | 36 ++++++++++ .../Distribution/PoissonDistribution.php | 4 +- .../UniformDistributionDiscrete.php | 6 +- .../Distribution/LaplaceDistributionTest.php | 66 ++++++++++++++++- .../Distribution/NormalDistributionTest.php | 55 +++++++++++++- .../Distribution/PoissonDistributionTest.php | 72 ++++++++++++++++++- .../UniformDistributionContinuousTest.php | 68 +++++++++++++++++- .../UniformDistributionDiscreteTest.php | 70 +++++++++++++++++- 9 files changed, 365 insertions(+), 18 deletions(-) diff --git a/Math/Stochastic/Distribution/LaplaceDistribution.php b/Math/Stochastic/Distribution/LaplaceDistribution.php index fc292a359..e526f7eb4 100644 --- a/Math/Stochastic/Distribution/LaplaceDistribution.php +++ b/Math/Stochastic/Distribution/LaplaceDistribution.php @@ -121,14 +121,14 @@ class LaplaceDistribution * * @return float * - * @throws \Exception + * @throws \OutOfBoundsException * * @since 1.0.0 */ public static function getMgf(float $t, float $mu, float $b) : float { - if ($t >= 1 / $b) { - throw new \Exception('Out of bounds'); + if (\abs($t) >= 1 / $b) { + throw new \OutOfBoundsException('Out of bounds'); } return \exp($mu * $t) / (1 - $b ** 2 * $t ** 2); diff --git a/Math/Stochastic/Distribution/NormalDistribution.php b/Math/Stochastic/Distribution/NormalDistribution.php index 17faf49f9..62e5d9cae 100644 --- a/Math/Stochastic/Distribution/NormalDistribution.php +++ b/Math/Stochastic/Distribution/NormalDistribution.php @@ -41,6 +41,42 @@ class NormalDistribution return 1 / ($sig * \sqrt(2 * pi())) * \exp(-($x - $mu) ** 2 / (2 * $sig ** 2)); } + /** + * Get probability density function. + * + * @param float $x Value x + * @param float $mu Value mu + * @param float $sig Sigma + * + * @return float + * + * @since 1.0.0 + */ + public static function getCdf(float $x, float $mu, float $sig) : float + { + return 1 / 2 * (1 + self::erf(($x - $mu) / ($sig * \sqrt(2)))); + } + + /** + * Error function approximation + * + * @param float $x Value x + * + * @return float + * + * @since 1.0.0 + */ + private static function erf(float $x) : float + { + if ($x < 0) { + return -self::erf(-$x); + } + + $a = 8 * (pi() - 3) / (3 * pi() * (4 - pi())); + + return \sqrt(1 - \exp(-($x ** 2) * (4 / pi() + $a * $x ** 2) / (1 + $a * $x ** 2))); + } + /** * Get mode. * diff --git a/Math/Stochastic/Distribution/PoissonDistribution.php b/Math/Stochastic/Distribution/PoissonDistribution.php index eda760abb..7da9130b9 100644 --- a/Math/Stochastic/Distribution/PoissonDistribution.php +++ b/Math/Stochastic/Distribution/PoissonDistribution.php @@ -76,7 +76,7 @@ class PoissonDistribution */ public static function getMode(float $lambda) : float { - return floor($lambda); + return \floor($lambda); } /** @@ -104,7 +104,7 @@ class PoissonDistribution */ public static function getMedian(float $lambda) : float { - return floor($lambda + 1 / 3 - 0.02 / $lambda); + return \floor($lambda + 1 / 3 - 0.02 / $lambda); } /** diff --git a/Math/Stochastic/Distribution/UniformDistributionDiscrete.php b/Math/Stochastic/Distribution/UniformDistributionDiscrete.php index 3e374a108..744fd882e 100644 --- a/Math/Stochastic/Distribution/UniformDistributionDiscrete.php +++ b/Math/Stochastic/Distribution/UniformDistributionDiscrete.php @@ -43,20 +43,20 @@ class UniformDistributionDiscrete /** * Get cumulative distribution function. * - * @param float $k Value k + * @param float $k Value k element of [a, b] * @param float $a Value a * @param float $b Value b * * @return float * - * @throws \Exception + * @throws \OutOfBoundsException * * @since 1.0.0 */ public static function getCdf(float $k, float $a, float $b) : float { if ($k > $b || $k < $a) { - throw new \Exception('Out of bounds'); + throw new \OutOfBoundsException('Out of bounds'); } return (\floor($k) - $a + 1) / ($b - $a + 1); diff --git a/tests/Math/Stochastic/Distribution/LaplaceDistributionTest.php b/tests/Math/Stochastic/Distribution/LaplaceDistributionTest.php index b53616048..f96bc2413 100644 --- a/tests/Math/Stochastic/Distribution/LaplaceDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/LaplaceDistributionTest.php @@ -17,8 +17,70 @@ use phpOMS\Math\Stochastic\Distribution\LaplaceDistribution; class LaplaceDistributionTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testPdf() { - self::markTestIncomplete(); + $x = 2; + $m = 1; + $b = 0.7; + + self::assertEquals(0.17118, LaplaceDistribution::getPdf($x, $m, $b), '', 0.01); + } + + public function testCdf() + { + $x = 2; + $m = 1; + $b = 0.7; + + self::assertEquals(0.88017, LaplaceDistribution::getCdf($x, $m, $b), '', 0.01); + } + + public function testMode() + { + self::assertEquals(2, LaplaceDistribution::getMode(2)); + } + + public function testMean() + { + self::assertEquals(2, LaplaceDistribution::getMean(2)); + } + + public function testMedian() + { + self::assertEquals(2, LaplaceDistribution::getMedian(2)); + } + + public function testExKurtosis() + { + self::assertEquals(3, LaplaceDistribution::getExKurtosis()); + } + + public function testSkewness() + { + self::assertEquals(0, LaplaceDistribution::getSkewness()); + } + + public function testVariance() + { + $b = 3; + + self::assertEquals(2 * $b ** 2, LaplaceDistribution::getVariance($b)); + } + + public function testMgf() + { + $t = 2; + $b = 0.4; + $m = 2; + + self::assertEquals(\exp($m * $t) / (1 - $b ** 2 * $t ** 2), LaplaceDistribution::getMgf($t, $m, $b)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testMgfException() + { + LaplaceDistribution::getMgf(3, 2, 4); } } diff --git a/tests/Math/Stochastic/Distribution/NormalDistributionTest.php b/tests/Math/Stochastic/Distribution/NormalDistributionTest.php index 5345b9904..4f124b77b 100644 --- a/tests/Math/Stochastic/Distribution/NormalDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/NormalDistributionTest.php @@ -17,8 +17,59 @@ use phpOMS\Math\Stochastic\Distribution\NormalDistribution; class NormalDistributionTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testPdf() { - self::markTestIncomplete(); + $mean = 2; + $sig = 1; + $x = 3; + + self::assertEquals(0.24197, NormalDistribution::getPdf($x, $mean, $sig), '', 0.01); + } + + public function testCdf() + { + $mean = 2; + $sig = 1; + $x = 3; + + self::assertEquals(0.84134, NormalDistribution::getCdf($x, $mean, $sig), '', 0.01); + } + + public function testMean() + { + $mu = 4; + + self::assertEquals($mu, NormalDistribution::getMean($mu)); + } + + public function testMedian() + { + $mu = 4; + + self::assertEquals($mu, NormalDistribution::getMedian($mu)); + } + + public function testMode() + { + $mu = 4; + + self::assertEquals($mu, NormalDistribution::getMode($mu)); + } + + public function testSkewness() + { + self::assertEquals(0, NormalDistribution::getSkewness()); + } + + public function testExKurtosis() + { + self::assertEquals(0, NormalDistribution::getExKurtosis()); + } + + public function testVariance() + { + $sig = 0.8; + + self::assertEquals($sig ** 2, NormalDistribution::getVariance($sig)); } } diff --git a/tests/Math/Stochastic/Distribution/PoissonDistributionTest.php b/tests/Math/Stochastic/Distribution/PoissonDistributionTest.php index f2c1727eb..51fcbc4cc 100644 --- a/tests/Math/Stochastic/Distribution/PoissonDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/PoissonDistributionTest.php @@ -17,8 +17,76 @@ use phpOMS\Math\Stochastic\Distribution\PoissonDistribution; class PoissonDistributionTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testPmf() { - self::markTestIncomplete(); + $k = 4; + $l = 3; + + self::assertEquals(0.16803, PoissonDistribution::getPmf(4, 3), '', 0.01); + } + + public function testCdf() + { + $k = 4; + $l = 3; + + self::assertEquals(0.81526, PoissonDistribution::getCdf(4, 3), '', 0.01); + } + + public function testMode() + { + $l = 4.6; + + self::assertEquals(4, PoissonDistribution::getMode($l), '', 0.01); + } + + public function testMean() + { + $l = 4.6; + + self::assertEquals($l, PoissonDistribution::getMean($l)); + } + + public function testVariance() + { + $l = 4.6; + + self::assertEquals($l, PoissonDistribution::getVariance($l)); + } + + public function testSkewness() + { + $l = 4.6; + + self::assertEquals(1 / sqrt($l), PoissonDistribution::getSkewness($l)); + } + + public function testExKurtosis() + { + $l = 4.6; + + self::assertEquals(1 / $l, PoissonDistribution::getExKurtosis($l)); + } + + public function testMedian() + { + $l = 4.6; + + self::assertEquals(\floor($l + 1 / 3 - 0.02 / $l), PoissonDistribution::getMedian($l)); + } + + public function testFisherInformation() + { + $l = 4.6; + + self::assertEquals(1 / $l, PoissonDistribution::getFisherInformation($l)); + } + + public function testMgf() + { + $l = 4.6; + $t = 3; + + self::assertEquals(exp($l * (\exp($t) - 1)), PoissonDistribution::getMgf($l, $t)); } } diff --git a/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php b/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php index db594d109..5143ebb93 100644 --- a/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php +++ b/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php @@ -17,8 +17,72 @@ use phpOMS\Math\Stochastic\Distribution\UniformDistributionContinuous; class UniformDistributionContinuousTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testPdf() { - self::markTestIncomplete(); + $a = 1; + $b = 4; + + self::assertEquals(1 / ($b - $a), UniformDistributionContinuous::getPdf(3, $a, $b)); + self::assertEquals(0, UniformDistributionContinuous::getPdf(0, $a, $b)); + self::assertEquals(0, UniformDistributionContinuous::getPdf(5, $a, $b)); + } + + public function testCdf() + { + $a = 1; + $b = 4; + $x = 3; + + self::assertEquals(($x - $a) / ($b - $a), UniformDistributionContinuous::getCdf($x, $a, $b)); + self::assertEquals(0, UniformDistributionContinuous::getCdf(0, $a, $b)); + self::assertEquals(1, UniformDistributionContinuous::getCdf(5, $a, $b)); + } + + public function testMode() + { + $a = 1; + $b = 4; + + self::assertThat( + UniformDistributionContinuous::getMode($a, $b), + self::logicalAnd( + self::greaterThan($a), + self::lessThan($b) + ) + ); + } + + public function testMean() + { + $a = 1; + $b = 4; + + self::assertEquals(1 / 2 * ($b + $a), UniformDistributionContinuous::getMean($a, $b)); + } + + public function testMedian() + { + $a = 1; + $b = 4; + + self::assertEquals(1 / 2 * ($b + $a), UniformDistributionContinuous::getMedian($a, $b)); + } + + public function testVariance() + { + $a = 1; + $b = 4; + + self::assertEquals(1 / 12 * ($b - $a) ** 2, UniformDistributionContinuous::getVariance($a, $b)); + } + + public function testSkewness() + { + self::assertEquals(0, UniformDistributionContinuous::getSkewness()); + } + + public function testExKurtosis() + { + self::assertEquals(-6 / 5, UniformDistributionContinuous::getExKurtosis()); } } diff --git a/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php b/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php index 4ceab3935..65967610e 100644 --- a/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php +++ b/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php @@ -17,8 +17,74 @@ use phpOMS\Math\Stochastic\Distribution\UniformDistributionDiscrete; class UniformDistributionDiscreteTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testPmf() { - self::markTestIncomplete(); + $a = 1; + $b = 4; + + self::assertEquals(1 / ($b - $a + 1), UniformDistributionDiscrete::getPmf($a, $b)); + } + + public function testCdf() + { + $a = 1; + $b = 4; + $k = 3; + + self::assertEquals(($k - $a + 1) / ($b - $a + 1), UniformDistributionDiscrete::getCdf($k, $a, $b)); + } + + public function testSkewness() + { + self::assertEquals(0, UniformDistributionDiscrete::getSkewness()); + } + + public function testMean() + { + $a = 1; + $b = 4; + + self::assertEquals(1 / 2 * ($a + $b), UniformDistributionDiscrete::getMean($a, $b)); + } + + public function testMedian() + { + $a = 1; + $b = 4; + + self::assertEquals(1 / 2 * ($a + $b), UniformDistributionDiscrete::getMedian($a, $b)); + } + + public function testVariance() + { + $a = 1; + $b = 4; + + self::assertEquals((($b - $a + 1) ** 2 - 1) / 12, UniformDistributionDiscrete::getVariance($a, $b)); + } + + public function testExKurtosis() + { + $a = 1; + $b = 4; + $n = $b - $a + 1; + + self::assertEquals(-(6 * ($n ** 2 + 1)) / (5 * ($n ** 2 - 1)), UniformDistributionDiscrete::getExKurtosis($a, $b)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testCdfExceptionUpper() + { + UniformDistributionDiscrete::getCdf(5, 2, 4); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testCdfExceptionLower() + { + UniformDistributionDiscrete::getCdf(1, 2, 4); } }