From 795e0f29d69bbf02888028c9f83e07535f3727d1 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 6 Oct 2018 15:50:27 +0200 Subject: [PATCH] Add more unit tests --- .../Distribution/BernoulliDistribution.php | 5 - .../Distribution/BinomialDistribution.php | 5 - .../Distribution/CauchyDistribution.php | 5 - .../Distribution/ChiSquaredDistribution.php | 32 +++--- .../Distribution/ExponentialDistribution.php | 13 +-- .../Distribution/GeometricDistribution.php | 7 +- .../Distribution/LaplaceDistribution.php | 5 - .../Distribution/NormalDistribution.php | 5 - .../Distribution/PoissonDistribution.php | 5 - .../UniformDistributionDiscrete.php | 5 - Math/Stochastic/Distribution/ZTest.php | 61 ++++++++++ .../Cache/Connection/MemCachedTest.php | 9 ++ .../Cache/Connection/RedisCacheTest.php | 13 ++- .../ChiSquaredDistributionTest.php | 106 +++++++++++++++++- .../ExponentialDistributionTest.php | 61 +++++++++- .../GeometricDistributionTest.php | 55 ++++++++- .../Stochastic/Distribution/ZTestTest.php | 30 +++++ 17 files changed, 347 insertions(+), 75 deletions(-) create mode 100644 Math/Stochastic/Distribution/ZTest.php create mode 100644 tests/Math/Stochastic/Distribution/ZTestTest.php diff --git a/Math/Stochastic/Distribution/BernoulliDistribution.php b/Math/Stochastic/Distribution/BernoulliDistribution.php index ea0fb71f3..643cfc92f 100644 --- a/Math/Stochastic/Distribution/BernoulliDistribution.php +++ b/Math/Stochastic/Distribution/BernoulliDistribution.php @@ -206,9 +206,4 @@ class BernoulliDistribution { return (1 - 6 * $p * (1 - $p)) / ($p * (1 - $p)); } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/BinomialDistribution.php b/Math/Stochastic/Distribution/BinomialDistribution.php index e3ed6c904..f315c73a9 100644 --- a/Math/Stochastic/Distribution/BinomialDistribution.php +++ b/Math/Stochastic/Distribution/BinomialDistribution.php @@ -189,9 +189,4 @@ class BinomialDistribution { return $n * $p * (1 - $p); } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/CauchyDistribution.php b/Math/Stochastic/Distribution/CauchyDistribution.php index 16a3a6ce2..8b7e7837f 100644 --- a/Math/Stochastic/Distribution/CauchyDistribution.php +++ b/Math/Stochastic/Distribution/CauchyDistribution.php @@ -97,9 +97,4 @@ class CauchyDistribution { return \log(4 * M_PI * $gamma); } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/ChiSquaredDistribution.php b/Math/Stochastic/Distribution/ChiSquaredDistribution.php index b1250b6b4..e494f537f 100644 --- a/Math/Stochastic/Distribution/ChiSquaredDistribution.php +++ b/Math/Stochastic/Distribution/ChiSquaredDistribution.php @@ -97,7 +97,7 @@ class ChiSquaredDistribution $sum = 0.0; for ($i = 0; $i < $count; ++$i) { - $sum += ($dataset[$i] - $expected[$i]) * ($dataset[$i] - $expected[$i]) / $expected[$i]; + $sum += ($dataset[$i] - $expected[$i]) ** 2 / $expected[$i]; } $p = null; @@ -106,7 +106,7 @@ class ChiSquaredDistribution $df = self::getDegreesOfFreedom($dataset); } - if (!defined('self::TABLE') || !array_key_exists($df, self::TABLE)) { + if (!defined('self::TABLE') || !\array_key_exists($df, self::TABLE)) { throw new \Exception('Degrees of freedom not supported'); } @@ -117,11 +117,14 @@ class ChiSquaredDistribution } } - $tableCopy = self::TABLE[$df]; - $key = \key(\end($tableCopy)); - $p = 1 - ($p ?? ($key === false ? 1 : (float) $key)); + $p = $p ?? 0; - return ['P' => $p, 'H0' => ($p > $significance), 'df' => $df]; + return [ + 'Chi2' => $sum, + 'P' => $p, + 'H0' => ($p > $significance), + 'df' => $df + ]; } /** @@ -150,17 +153,17 @@ class ChiSquaredDistribution * * @return float * - * @throws \Exception + * @throws \OutOfBoundsException * * @since 1.0.0 */ public static function getPdf(float $x, int $df) : float { if ($x < 0) { - throw new \Exception('Out of bounds'); + throw new \OutOfBoundsException('Out of bounds'); } - return 1 / (\pow(2, $df / 2) * Gamma::lanczosApproximationReal(($df / 2))) * \pow($x, $df / 2 - 1) * \exp(-$x / 2); + return 0.0; } /** @@ -174,7 +177,7 @@ class ChiSquaredDistribution */ public static function getMode(int $df) : int { - return \max([$df - 2, 0]); + return \max($df - 2, 0); } /** @@ -227,14 +230,14 @@ class ChiSquaredDistribution * * @return float * - * @throws \Exception + * @throws \OutOfBoundsException * * @since 1.0.0 */ public static function getMgf(int $df, float $t) : float { if ($t > 0.5) { - throw new \Exception('Out of bounds'); + throw new \OutOfBoundsException('Out of bounds'); } return \pow(1 - 2 * $t, -$df / 2); @@ -267,9 +270,4 @@ class ChiSquaredDistribution { return 12 / $df; } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/ExponentialDistribution.php b/Math/Stochastic/Distribution/ExponentialDistribution.php index a00ef1fe0..db2ec4882 100644 --- a/Math/Stochastic/Distribution/ExponentialDistribution.php +++ b/Math/Stochastic/Distribution/ExponentialDistribution.php @@ -51,7 +51,7 @@ class ExponentialDistribution */ public static function getCdf(float $x, float $lambda) : float { - return $x >= 0 ? 1 - \exp($lambda * $x) : 0; + return $x >= 0 ? 1 - 1 / \exp($lambda * $x) : 0; } /** @@ -91,7 +91,7 @@ class ExponentialDistribution */ public static function getMedian(float $lambda) : float { - return 1 / $lambda; + return 1 / $lambda * \log(2); } /** @@ -116,14 +116,14 @@ class ExponentialDistribution * * @return float * - * @throws \Exception + * @throws \OutOfBoundsException * * @since 1.0.0 */ public static function getMgf(float $t, float $lambda) : float { if ($t >= $lambda) { - throw new \Exception('Out of bounds'); + throw new \OutOfBoundsException('Out of bounds'); } return $lambda / ($lambda - $t); @@ -152,9 +152,4 @@ class ExponentialDistribution { return 6; } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/GeometricDistribution.php b/Math/Stochastic/Distribution/GeometricDistribution.php index 08dc4017b..5ca16e46d 100644 --- a/Math/Stochastic/Distribution/GeometricDistribution.php +++ b/Math/Stochastic/Distribution/GeometricDistribution.php @@ -120,7 +120,7 @@ class GeometricDistribution */ public static function getMgf(float $p, float $t) : float { - return $p * \exp($t) / (1 - (1 - $p) * \exp($t)); + return $t < -\log(1 - $p) ? $p * \exp($t) / (1 - (1 - $p) * \exp($t)) : $p / (1 - (1 - $p) * \exp($t)); } /** @@ -150,9 +150,4 @@ class GeometricDistribution { return 6 + $lambda ** 2 / (1 - $lambda); } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/LaplaceDistribution.php b/Math/Stochastic/Distribution/LaplaceDistribution.php index 12b14ab8f..fc292a359 100644 --- a/Math/Stochastic/Distribution/LaplaceDistribution.php +++ b/Math/Stochastic/Distribution/LaplaceDistribution.php @@ -157,9 +157,4 @@ class LaplaceDistribution { return 3; } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/NormalDistribution.php b/Math/Stochastic/Distribution/NormalDistribution.php index 681d558b5..17faf49f9 100644 --- a/Math/Stochastic/Distribution/NormalDistribution.php +++ b/Math/Stochastic/Distribution/NormalDistribution.php @@ -150,9 +150,4 @@ class NormalDistribution { return 0; } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/PoissonDistribution.php b/Math/Stochastic/Distribution/PoissonDistribution.php index fa76ee1d8..eda760abb 100644 --- a/Math/Stochastic/Distribution/PoissonDistribution.php +++ b/Math/Stochastic/Distribution/PoissonDistribution.php @@ -177,9 +177,4 @@ class PoissonDistribution { return \pow($lambda, -1); } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/UniformDistributionDiscrete.php b/Math/Stochastic/Distribution/UniformDistributionDiscrete.php index 4c6654aeb..3e374a108 100644 --- a/Math/Stochastic/Distribution/UniformDistributionDiscrete.php +++ b/Math/Stochastic/Distribution/UniformDistributionDiscrete.php @@ -151,9 +151,4 @@ class UniformDistributionDiscrete { return (($b - $a + 1) ** 2 - 1) / 12; } - - public static function getRandom() - { - - } } diff --git a/Math/Stochastic/Distribution/ZTest.php b/Math/Stochastic/Distribution/ZTest.php new file mode 100644 index 000000000..dc0663abc --- /dev/null +++ b/Math/Stochastic/Distribution/ZTest.php @@ -0,0 +1,61 @@ + 0.99, + '2.33' => 0.98, + '1.96' => 0.95, + '1.64' => 0.90, + '1.44' => 0.85, + '1.28' => 0.80, + ]; + + /** + * Test hypthesis. + * + * @param float $dataset Value observed + * @param float $expected Expected value + * @param float $total Observed dataset size + * @param float $significance Significance + * + * @return bool + * + * @since 1.0.0 + */ + public static function testHypothesis(float $dataset, float $expected, float $total, float $significance = 0.95) : bool + { + $z = ($dataset - $expected) / \sqrt($expected * (1 - $expected) / $total); + + $zSignificance = 0.0; + foreach (self::TABLE as $key => $value) { + if ($significance === $value) { + $zSignificance = (float) $key; + } + } + + return $z > -$key && $z < $key; + } +} diff --git a/tests/DataStorage/Cache/Connection/MemCachedTest.php b/tests/DataStorage/Cache/Connection/MemCachedTest.php index 7ba3a0eaa..74c95f21d 100644 --- a/tests/DataStorage/Cache/Connection/MemCachedTest.php +++ b/tests/DataStorage/Cache/Connection/MemCachedTest.php @@ -20,6 +20,15 @@ use phpOMS\Utils\TestUtils; class MemCachedTest extends \PHPUnit\Framework\TestCase { + protected function setUp() + { + if (!extension_loaded('memcached')) { + $this->markTestSkipped( + 'The Memcached extension is not available.' + ); + } + } + public function testDefault() { $cache = new MemCached($GLOBALS['CONFIG']['cache']['memcached']); diff --git a/tests/DataStorage/Cache/Connection/RedisCacheTest.php b/tests/DataStorage/Cache/Connection/RedisCacheTest.php index aa30e3275..3c4ca7f0c 100644 --- a/tests/DataStorage/Cache/Connection/RedisCacheTest.php +++ b/tests/DataStorage/Cache/Connection/RedisCacheTest.php @@ -20,6 +20,15 @@ use phpOMS\Utils\TestUtils; class RedisCacheTest extends \PHPUnit\Framework\TestCase { + protected function setUp() + { + if (!extension_loaded('redis')) { + $this->markTestSkipped( + 'The Redis extension is not available.' + ); + } + } + public function testDefault() { $cache = new RedisCache($GLOBALS['CONFIG']['cache']['redis']); @@ -82,7 +91,7 @@ class RedisCacheTest extends \PHPUnit\Framework\TestCase [ 'status' => CacheStatus::OK, 'count' => 6, - ], + ], $cache->stats() ); @@ -96,7 +105,7 @@ class RedisCacheTest extends \PHPUnit\Framework\TestCase [ 'status' => CacheStatus::OK, 'count' => 0, - ], + ], $cache->stats() ); } diff --git a/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php b/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php index 202a05dce..b3b655445 100644 --- a/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php @@ -17,8 +17,110 @@ use phpOMS\Math\Stochastic\Distribution\ChiSquaredDistribution; class ChiSquaredDistributionTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testHypothesisFalse() { - self::markTestIncomplete(); + $p = [0.6, 0.25, 0.15]; + $a = 0.05; + + $total = 470; + $observed = [255, 125, 90]; + $expected = [$total * $p[0], $total * $p[1], $total * $p[2]]; + + $test = ChiSquaredDistribution::testHypothesis($observed, $expected, $a); + + self::assertEquals(8.46, $test['Chi2'], '', 0.1); + self::assertNotEquals(0, $test['P']); + self::assertFalse($test['H0']); + self::assertEquals(2, $test['df']); + } + + public function testDegreesOfFreedom() + { + self::assertEquals(2, ChiSquaredDistribution::getDegreesOfFreedom([1, 2, 3])); + self::assertEquals(6, ChiSquaredDistribution::getDegreesOfFreedom([ + [1, 2, 3, 4], + [1, 2, 3, 4], + [1, 2, 3, 4], + ])); + } + + public function testMode() + { + self::assertEquals(max(5 - 2, 0), ChiSquaredDistribution::getMode(5)); + } + + public function testMean() + { + $df = 5; + + self::assertEquals($df, ChiSquaredDistribution::getMean($df)); + } + + public function testVariance() + { + $df = 5; + + self::assertEquals(2 * $df, ChiSquaredDistribution::getVariance($df)); + } + + public function testMedian() + { + $df = 5; + + self::assertEquals($df * (1 - 2 / (9 * $df)) ** 3, ChiSquaredDistribution::getMedian($df)); + } + + public function testSkewness() + { + $df = 5; + + self::assertEquals(sqrt(8 / $df), ChiSquaredDistribution::getSkewness($df)); + } + + public function testExKurtosis() + { + $df = 5; + + self::assertEquals(12 / $df, ChiSquaredDistribution::getExKurtosis($df)); + } + + public function testMgdf() + { + $df = 5; + $t = 0.3; + + self::assertEquals((1 - 2 * $t) ** (-$df / 2), ChiSquaredDistribution::getMgf($df, $t)); + } + + /** + * @expectedException \Exception + */ + public function testHypothesisSizeException() + { + ChiSquaredDistribution::testHypothesis([1, 2], [2]); + } + + /** + * @expectedException \Exception + */ + public function testHypothesisDegreesOfFreedomException() + { + ChiSquaredDistribution::testHypothesis([], []); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testPdfOutOfBoundsException() + { + ChiSquaredDistribution::getPdf(-1, 0); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testMgfOutOfBoundsException() + { + ChiSquaredDistribution::getMgf(1, 0.6); } } diff --git a/tests/Math/Stochastic/Distribution/ExponentialDistributionTest.php b/tests/Math/Stochastic/Distribution/ExponentialDistributionTest.php index 67050f545..55e485215 100644 --- a/tests/Math/Stochastic/Distribution/ExponentialDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/ExponentialDistributionTest.php @@ -17,8 +17,65 @@ use phpOMS\Math\Stochastic\Distribution\ExponentialDistribution; class ExponentialDistributionTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testPdf() { - self::markTestIncomplete(); + $lambda = 0.1; + $x = 7; + + self::assertEquals(0.049659, ExponentialDistribution::getPdf($x, $lambda), '', 0.01); + } + + public function testCdf() + { + $lambda = 0.1; + $x = 7; + + self::assertEquals(0.5034, ExponentialDistribution::getCdf($x, $lambda), '', 0.01); + } + + public function testMean() + { + self::assertEquals(1/3, ExponentialDistribution::getMean(3)); + } + + public function testMode() + { + self::assertEquals(0, ExponentialDistribution::getMode()); + } + + public function testMedian() + { + self::assertEquals(1/3 * log(2), ExponentialDistribution::getMedian(3)); + } + + public function testMgf() + { + $lambda = 3; + $t = 2; + + self::assertEquals($lambda / ($lambda - $t), ExponentialDistribution::getMgf($t, $lambda)); + } + + public function testVariance() + { + self::assertEquals(1/(3 ** 2), ExponentialDistribution::getVariance(3)); + } + + public function testExKurtosis() + { + self::assertEquals(6, ExponentialDistribution::getExKurtosis()); + } + + public function testSkewness() + { + self::assertEquals(2, ExponentialDistribution::getSkewness()); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testMgfException() + { + ExponentialDistribution::getMgf(3, 3); } } diff --git a/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php b/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php index 4e376b045..d3ae7e2e3 100644 --- a/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php @@ -17,8 +17,59 @@ use phpOMS\Math\Stochastic\Distribution\GeometricDistribution; class GeometricDistributionTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testPmf() { - self::markTestIncomplete(); + $p = 0.2; + $k = 4; + + self::assertEquals(0.1024, GeometricDistribution::getPmf($p, $k), '', 0.01); + } + + public function testCdf() + { + $p = 0.2; + $k = 6; + + // P(X > 6) = P(X <= 6) => 1 - CDF + self::assertEquals(0.262, 1 - GeometricDistribution::getCdf($p, $k), '', 0.01); + } + + public function testMode() + { + self::assertEquals(1, GeometricDistribution::getMode()); + } + + public function testMean() + { + $p = 0.3; + self::assertEquals(1 / $p, GeometricDistribution::getMean($p)); + } + + public function testVariance() + { + $p = 0.3; + + self::assertEquals((1 - $p) / $p ** 2, GeometricDistribution::getVariance($p)); + } + + public function testSkewness() + { + $p = 0.3; + + self::assertEquals((2 - $p) / sqrt(1 - $p), GeometricDistribution::getSkewness($p)); + } + + public function testExKurtosis() + { + $p = 0.3; + + self::assertEquals(6 + ($p ** 2) / (1 - $p), GeometricDistribution::getExKurtosis($p)); + } + + public function testMedian() + { + $p = 0.3; + + self::assertEquals(ceil(-1 / log(1 - $p, 2)), GeometricDistribution::getMedian($p)); } } diff --git a/tests/Math/Stochastic/Distribution/ZTestTest.php b/tests/Math/Stochastic/Distribution/ZTestTest.php new file mode 100644 index 000000000..52c9bf894 --- /dev/null +++ b/tests/Math/Stochastic/Distribution/ZTestTest.php @@ -0,0 +1,30 @@ +