diff --git a/Ai/Ocr/BasicOcr.php b/Ai/Ocr/BasicOcr.php index da406231f..44a6563ab 100644 --- a/Ai/Ocr/BasicOcr.php +++ b/Ai/Ocr/BasicOcr.php @@ -161,7 +161,7 @@ final class BasicOcr $labels = []; for ($i = 0; $i < $numberOfLabels; ++$i) { - $read = \fread($fp, 4); + $read = \fread($fp, 1); if (!$read) { return []; } diff --git a/DataStorage/Cache/Connection/ConnectionAbstract.php b/DataStorage/Cache/Connection/ConnectionAbstract.php index 4e30758f1..942267532 100644 --- a/DataStorage/Cache/Connection/ConnectionAbstract.php +++ b/DataStorage/Cache/Connection/ConnectionAbstract.php @@ -113,7 +113,7 @@ abstract class ConnectionAbstract implements ConnectionInterface */ public function getPort() : int { - return (int) $this->dbdata['port'] ?? 0; + return (int) ($this->dbdata['port'] ?? 0); } /** diff --git a/DataStorage/Cache/Connection/MemCached.php b/DataStorage/Cache/Connection/MemCached.php index 90e0129cf..b66c950a9 100644 --- a/DataStorage/Cache/Connection/MemCached.php +++ b/DataStorage/Cache/Connection/MemCached.php @@ -144,13 +144,7 @@ final class MemCached extends ConnectionAbstract */ public function flush(int $expire = 0) : bool { - if ($this->status !== CacheStatus::OK) { - return false; - } - - $this->con->flush(); - - return true; + return $this->flushAll(); } /** diff --git a/DataStorage/Cache/Connection/RedisCache.php b/DataStorage/Cache/Connection/RedisCache.php index 346c439b3..d9dcbf23a 100644 --- a/DataStorage/Cache/Connection/RedisCache.php +++ b/DataStorage/Cache/Connection/RedisCache.php @@ -172,13 +172,7 @@ final class RedisCache extends ConnectionAbstract */ public function flush(int $expire = 0) : bool { - if ($this->status !== CacheStatus::OK) { - return false; - } - - $this->con->flushDb(); - - return true; + return $this->flushAll(); } /** diff --git a/DataStorage/Session/ConsoleSession.php b/DataStorage/Session/FileSession.php similarity index 86% rename from DataStorage/Session/ConsoleSession.php rename to DataStorage/Session/FileSession.php index 96f497e78..25a2057c8 100644 --- a/DataStorage/Session/ConsoleSession.php +++ b/DataStorage/Session/FileSession.php @@ -17,7 +17,7 @@ namespace phpOMS\DataStorage\Session; use phpOMS\DataStorage\LockException; /** - * Console session class. + * File session class. * * @package phpOMS\DataStorage\Session * @license OMS License 1.0 @@ -26,7 +26,7 @@ use phpOMS\DataStorage\LockException; * * @SuppressWarnings(PHPMD.Superglobals) */ -class ConsoleSession implements SessionInterface +class FileSession implements SessionInterface { /** * Is session locked/already set. @@ -83,12 +83,16 @@ class ConsoleSession implements SessionInterface $this->inactivityInterval = $inactivityInterval; - if (\session_status() !== \PHP_SESSION_ACTIVE) { - \session_set_cookie_params($liftetime, '/', '', false, true); // @codeCoverageIgnore - \session_start(); // @codeCoverageIgnore + if (\session_status() !== \PHP_SESSION_ACTIVE && !\headers_sent()) { + // @codeCoverageIgnoreStart + \session_set_cookie_params($liftetime, '/', '', false, true); + \session_start(); + // @codeCoverageIgnoreEnd } - if ($this->inactivityInterval > 0 && ($this->inactivityInterval + ($_SESSION['lastActivity'] ?? 0) < \time())) { + if ($this->inactivityInterval > 0 + && ($this->inactivityInterval + ($_SESSION['lastActivity'] ?? 0) < \time()) + ) { $this->destroy(); // @codeCoverageIgnore } @@ -143,12 +147,16 @@ class ConsoleSession implements SessionInterface /** * {@inheritdoc} */ - public function save() : void + public function save() : bool { - if (!$this->isLocked) { - $_SESSION = $this->sessionData; - \session_write_close(); + if ($this->isLocked) { + return false; } + + $_SESSION = $this->sessionData; + \session_write_close(); + + return true; } /** @@ -202,6 +210,7 @@ class ConsoleSession implements SessionInterface * Destruct session. * * @since 1.0.0 + * @codeCoverageIgnore */ public function __destruct() { diff --git a/DataStorage/Session/ConsoleSessionHandler.php b/DataStorage/Session/FileSessionHandler.php similarity index 91% rename from DataStorage/Session/ConsoleSessionHandler.php rename to DataStorage/Session/FileSessionHandler.php index 329983223..647cb6813 100644 --- a/DataStorage/Session/ConsoleSessionHandler.php +++ b/DataStorage/Session/FileSessionHandler.php @@ -15,7 +15,7 @@ declare(strict_types=1); namespace phpOMS\DataStorage\Session; /** - * Console session handler. + * File session handler. * * @package phpOMS\DataStorage\Session * @license OMS License 1.0 @@ -24,7 +24,7 @@ namespace phpOMS\DataStorage\Session; * * @SuppressWarnings(PHPMD.Superglobals) */ -final class ConsoleSessionHandler implements \SessionHandlerInterface, \SessionIdInterface +final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdInterface { /** * File path for session @@ -44,6 +44,10 @@ final class ConsoleSessionHandler implements \SessionHandlerInterface, \SessionI public function __construct(string $path) { $this->savePath = $path; + + if (\realpath($path) === false) { + \mkdir($path, 0755, true); + } } /** @@ -55,7 +59,7 @@ final class ConsoleSessionHandler implements \SessionHandlerInterface, \SessionI */ public function create_sid() : string { - return \session_create_id('console-'); + return \session_create_id('s-'); } /** @@ -71,11 +75,8 @@ final class ConsoleSessionHandler implements \SessionHandlerInterface, \SessionI public function open($savePath, $sessionName) { $this->savePath = $savePath; - if (!\is_dir($this->savePath)) { - \mkdir($this->savePath, 0755); - } - return true; + return \is_dir($this->savePath); } /** diff --git a/DataStorage/Session/HttpSession.php b/DataStorage/Session/HttpSession.php index cb53de120..7994a5cd8 100644 --- a/DataStorage/Session/HttpSession.php +++ b/DataStorage/Session/HttpSession.php @@ -79,12 +79,13 @@ final class HttpSession implements SessionInterface } if ($sid !== '') { - \session_id((string) $sid); + \session_id((string) $sid); // @codeCoverageIgnore } $this->inactivityInterval = $inactivityInterval; if (\session_status() !== \PHP_SESSION_ACTIVE && !\headers_sent()) { + // @codeCoverageIgnoreStart \session_set_cookie_params([ 'lifetime' => $liftetime, 'path' => '/', @@ -92,8 +93,9 @@ final class HttpSession implements SessionInterface 'secure' => false, 'httponly' => true, 'samesite' => 'Strict', - ]); // @codeCoverageIgnore - \session_start(); // @codeCoverageIgnore + ]); + \session_start(); + // @codeCoverageIgnoreEnd } if ($this->inactivityInterval > 0 && ($this->inactivityInterval + ($_SESSION['lastActivity'] ?? 0) < \time())) { @@ -172,12 +174,16 @@ final class HttpSession implements SessionInterface /** * {@inheritdoc} */ - public function save() : void + public function save() : bool { - if (!$this->isLocked) { - $_SESSION = $this->sessionData; - \session_write_close(); + if ($this->isLocked) { + return false; } + + $_SESSION = $this->sessionData; + \session_write_close(); + + return true; } /** diff --git a/DataStorage/Session/SessionInterface.php b/DataStorage/Session/SessionInterface.php index b342a304b..9ef96056b 100644 --- a/DataStorage/Session/SessionInterface.php +++ b/DataStorage/Session/SessionInterface.php @@ -64,11 +64,11 @@ interface SessionInterface /** * Save session. * - * @return void + * @return bool * * @since 1.0.0 */ - public function save() : void; + public function save() : bool; /** * @return string diff --git a/Math/Functions/Beta.php b/Math/Functions/Beta.php index a439d20e2..e101e1008 100644 --- a/Math/Functions/Beta.php +++ b/Math/Functions/Beta.php @@ -47,23 +47,40 @@ final class Beta */ public static function incompleteBeta(float $x, float $p, float $q) : float { - if ($x < 0.0) { - return 0.0; - } elseif ($x >= 1.0) { - return 1.0; - } elseif ($p <= 0.0 || $q >= 0.0 || $p + $q > 10000000000.0) { - return 0.0; - } - - $bGamma = \exp(-self::logBeta($p, $q)) + $p * \log($x) + $q * \log(1.0 - $x); - - return $x < ($p + 1.0) / ($p + $q + 2.0) - ? $bGamma * self::betaFraction($x, $p, $q) / $p - : 1.0 - $bGamma * self::betaFraction(1 - $x, $q, $p) / $q; + return self::regularizedBeta($x, $p, $q) * self::beta($p, $q); } /** - * Fraction of the incomplete beta function + * Incomplete beta function + * + * @param float $x Value + * @param float $p p + * @param float $q q + * + * @return float + * + * @since 1.0.0 + */ + public static function regularizedBeta(float $x, float $p, float $q) : float + { + if ($x <= 0.0) { + return 0.0; + } elseif ($x >= 1.0) { + return 1.0; + } elseif ($p <= 0.0 || $q <= 0.0 || $p + $q > 10000000000.0) { + return 0.0; + } + + $bGamma = \exp(-self::logBeta($p, $q) + $p * \log($x) + $q * \log(1.0 - $x)); + + // this uses the symmetry of the beta function + return ($x < ($p + 1.0) / ($p + $q + 2.0) + ? $bGamma * self::betaFraction($x, $p, $q) / $p + : 1.0 - $bGamma * self::betaFraction(1.0 - $x, $q, $p) / $q); + } + + /** + * Fraction of the beta function * * @param float $x Value * @param float $p p @@ -72,6 +89,7 @@ final class Beta * @see JSci * @author Jaco van Kooten * @license LGPL 2.1 + * @since 1.0.0 */ private static function betaFraction(float $x, float $p, float $q) : float { diff --git a/Math/Functions/Functions.php b/Math/Functions/Functions.php index 48659aafc..eadf5a957 100644 --- a/Math/Functions/Functions.php +++ b/Math/Functions/Functions.php @@ -315,4 +315,47 @@ final class Functions return 1 / \sqrt(\M_PI) * \exp(-$value * $value) * $q2; } + + /** + * Generalized hypergeometric function. + * + * pFq(a1, ..., ap; b1, ..., bq; z) + * + * @param array $a Array of values + * @param array $b Array of values + * @param float $z Z + * + * @return float + * + * @since 1.0.0 + */ + public static function generalizedHypergeometricFunction(array $a, array $b, float $z) : float + { + $sum = 0.0; + $aProd = \array_fill(0, 20, []); + $bProd = \array_fill(0, 20, []); + + for ($n = 0; $n < 20; ++$n) { + foreach ($a as $key => $value) { + if ($n === 0) { + $aProd[$n][$key] = 1; + } else { + $aProd[$n][$key] = $aProd[$n - 1][$key] * ($value + $n - 1); + } + } + + foreach ($b as $key => $value) { + if ($n === 0) { + $bProd[$n][$key] = 1; + } else { + $bProd[$n][$key] = $bProd[$n - 1][$key] * ($value + $n - 1); + } + } + + $temp = \array_product($aProd[$n]) / \array_product($bProd[$n]); + $sum += $temp * $z ** $n / self::fact($n); + } + + return $sum; + } } diff --git a/Math/Functions/Gamma.php b/Math/Functions/Gamma.php index 6cfd83cd5..f0a8e1381 100644 --- a/Math/Functions/Gamma.php +++ b/Math/Functions/Gamma.php @@ -34,6 +34,20 @@ final class Gamma { } + /** + * Gamma function + * + * @param int|float $z Value + * + * @return float + * + * @since 1.0.0 + */ + public static function gamma($z) : float + { + return \exp(self::logGamma($z)); + } + /** * approximation values. * @@ -134,16 +148,15 @@ final class Gamma ]; $y = $z; - $x = $z; - $temp = $x + 5.5 - ($x + 0.5) * \log($x + 5.5); + $temp = $z + 5.5 - ($z + 0.5) * \log($z + 5.5); $sum = 1.000000000190015; for ($i = 0; $i < 6; ++$i) { $sum += $approx[$i] / ++$y; } - return -$temp + \log(\sqrt(2 * \M_PI * $sum / $x)); + return -$temp + \log(\sqrt(2 * \M_PI) * $sum / $z); } /** @@ -161,4 +174,131 @@ final class Gamma { return Functions::fact($k - 1); } + + /** + * First or lower incomplete gamma function + * + * @param float $a a + * @param float $x Value + * + * @return float + * + * @since 1.0.0 + */ + public static function incompleteGammaFirst(float $a, float $x) : float + { + return self::regularizedGamma($a, $x) * \exp(self::logGamma($a)); + } + + /** + * Second or upper incomplete gamma function + * + * @param float $a a + * @param float $x Value + * + * @return float + * + * @since 1.0.0 + */ + public static function incompleteGammaSecond(float $a, float $x) : float + { + return \exp(self::logGamma($a)) - self::regularizedGamma($a, $x) * \exp(self::logGamma($a)); + } + + /** + * Incomplete gamma function + * + * @param float $a a + * @param float $x Value + * + * @return float + * + * @since 1.0.0 + */ + public static function regularizedGamma(float $a, float $x) : float + { + if ($x <= 0.0 || $a <= 0.0 || $a > 10000000000.0) { + return 0.0; + } elseif ($x < $a + 1.0) { + return self::gammaSeriesExpansion($a, $x); + } + + return 1.0 - self::gammaFraction($a, $x); + } + + /** + * Gamma series expansion + * + * @param float $a a + * @param float $x Value + * + * @return float + * + * @see JSci + * @author Jaco van Kooten + * @license LGPL 2.1 + * @since 1.0.0 + */ + private static function gammaSeriesExpansion(float $a, float $x) : float + { + $ap = $a; + $del = 1.0 / $a; + $sum = $del; + + for ($i = 1; $i < 150; ++$i) { + ++$ap; + + $del *= $x / $ap; + $sum += $del; + + if ($del < $sum * 2.22e-16) { + return $sum * \exp(-$x + $a * \log($x) - self::logGamma($a)); + } + } + + return 0.0; + } + + /** + * Gamma fraction + * + * @param float $a a + * @param float $x Value + * + * @return float + * + * @see JSci + * @author Jaco van Kooten + * @license LGPL 2.1 + * @since 1.0.0 + */ + private static function gammaFraction(float $a, float $x) : float + { + $b = $x + 1.0 - $a; + $c = 1.0 / 2.23e-308; + $d = 1.0 / $b; + $h = $d; + $del = 0.0; + + for ($i = 1; $i < 150 && \abs($del - 1.0) > 2.22e-16; ++$i) { + $an = - $i * ($i - $a); + $b += 2.0; + $d = $an * $d + $b; + $c = $b + $an / $c; + + if (\abs($c) < 2.23e-308) { + $c = 2.23e-308; + } + + if (\abs($d) < 2.23e-308) { + $d = 2.23e-308; + } + + $d = 1.0 / $d; + $del = $d * $c; + $h *= $del; + } + + return \exp(-$x + $a * \log($x) - self::logGamma($a)) * $h; + } } diff --git a/Math/Stochastic/Distribution/BernoulliDistribution.php b/Math/Stochastic/Distribution/BernoulliDistribution.php index 3a1303fa8..9cbb1e931 100644 --- a/Math/Stochastic/Distribution/BernoulliDistribution.php +++ b/Math/Stochastic/Distribution/BernoulliDistribution.php @@ -32,7 +32,7 @@ final class BernoulliDistribution * * @return float * - * @throws \Exception + * @throws \InvalidArgumentException * * @since 1.0.0 */ @@ -44,11 +44,11 @@ final class BernoulliDistribution return $p; } - throw new \Exception('wrong parameter'); + throw new \InvalidArgumentException('k needs to be 0 or 1'); } /** - * Get cummulative distribution function. + * Get cumulative distribution function. * * @param float $p Value p * @param float $k Value k diff --git a/Math/Stochastic/Distribution/BetaDistribution.php b/Math/Stochastic/Distribution/BetaDistribution.php index 36fa22e30..c643df2c5 100644 --- a/Math/Stochastic/Distribution/BetaDistribution.php +++ b/Math/Stochastic/Distribution/BetaDistribution.php @@ -139,9 +139,9 @@ final class BetaDistribution public static function getMgf(float $t, float $alpha, float $beta) : float { $sum = 0; - for ($k = 1; $k < 20; ++$k) { + for ($k = 1; $k < 15; ++$k) { $product = 1; - for ($r = 0; $r < $k - 1; ++$r) { + for ($r = 0; $r < $k; ++$r) { $product *= ($alpha + $r) / ($alpha + $beta + $r); } @@ -152,7 +152,23 @@ final class BetaDistribution } /** - * Get cummulative distribution function. + * Get prdobability distribution function. + * + * @param float $x Value + * @param float $alpha Alpha + * @param float $beta Beta + * + * @return float + * + * @since 1.0.0 + */ + public static function getPdf(float $x, float $alpha, float $beta) : float + { + return \pow($x, $alpha - 1) * \pow(1 - $x, $beta - 1) / Beta::beta($alpha, $beta); + } + + /** + * Get cumulative distribution function. * * @param float $x Value * @param float $alpha Alpha @@ -164,6 +180,6 @@ final class BetaDistribution */ public static function getCdf(float $x, float $alpha, float $beta) : float { - return Beta::incompleteBeta($x, $alpha, $beta); + return Beta::regularizedBeta($x, $alpha, $beta); } } diff --git a/Math/Stochastic/Distribution/ChiSquaredDistribution.php b/Math/Stochastic/Distribution/ChiSquaredDistribution.php index df54327e9..d296d2df0 100644 --- a/Math/Stochastic/Distribution/ChiSquaredDistribution.php +++ b/Math/Stochastic/Distribution/ChiSquaredDistribution.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace phpOMS\Math\Stochastic\Distribution; +use phpOMS\Math\Functions\Gamma; + /** * Chi squared distribution. * @@ -159,7 +161,22 @@ final class ChiSquaredDistribution throw new \OutOfBoundsException('Out of bounds'); } - return 0.0; + return 1 / (\pow(2, $df / 2) * Gamma::gamma($df / 2)) * \pow($x, $df / 2 - 1) * \exp(-$x / 2); + } + + /** + * Get cumulative density function. + * + * @param float $x Value x + * @param int $df Degreegs of freedom + * + * @return float + * + * @since 1.0.0 + */ + public static function getCdf(float $x, int $df) : float + { + return 1 / Gamma::gamma($df / 2) * Gamma::incompleteGammaFirst($df / 2, $x / 2); } /** diff --git a/Math/Stochastic/Distribution/FDistribution.php b/Math/Stochastic/Distribution/FDistribution.php index 6fa6852e6..c228f1d70 100644 --- a/Math/Stochastic/Distribution/FDistribution.php +++ b/Math/Stochastic/Distribution/FDistribution.php @@ -13,6 +13,8 @@ declare(strict_types=1); namespace phpOMS\Math\Stochastic\Distribution; +use phpOMS\Math\Functions\Beta; + /** * F distribution. * @@ -23,6 +25,39 @@ namespace phpOMS\Math\Stochastic\Distribution; */ final class FDistribution { + /** + * Get probability density function. + * + * @param float $x Value x + * @param int $d1 Degreegs of freedom + * @param int $d2 Degreegs of freedom + * + * @return float + * + * @since 1.0.0 + */ + public static function getPdf(float $x, int $d1, int $d2) : float + { + return \sqrt((\pow($d1 * $x, $d1) * ($d2 ** $d2)) / \pow($d1 * $x + $d2, $d1 + $d2)) + / ($x * Beta::beta($d1 / 2, $d2 / 2)); + } + + /** + * Get cumulative density function. + * + * @param float $x Value x + * @param int $d1 Degreegs of freedom + * @param int $d2 Degreegs of freedom + * + * @return float + * + * @since 1.0.0 + */ + public static function getCdf(float $x, int $d1, int $d2) : float + { + return Beta::regularizedBeta($d1 * $x / ($d1 * $x + $d2), $d1 / 2, $d2 / 2); + } + /** * Get expected value. * diff --git a/Math/Stochastic/Distribution/GammaDistribution.php b/Math/Stochastic/Distribution/GammaDistribution.php index f276a14b5..f85b96f41 100644 --- a/Math/Stochastic/Distribution/GammaDistribution.php +++ b/Math/Stochastic/Distribution/GammaDistribution.php @@ -26,7 +26,39 @@ use phpOMS\Math\Functions\Gamma; final class GammaDistribution { /** - * Get probability density function. + * Get probability density function for shape and scale. + * + * @param float $x Value x + * @param float $k k shape + * @param float $theta Theta scale + * + * @return float + * + * @since 1.0.0 + */ + public static function getPdfScale(float $x, float $k, float $theta) : float + { + return 1 / (Gamma::gamma($k) * $theta ** $k) * \pow($x, $k - 1) * \exp(-$x / $theta); + } + + /** + * Get probability density function for shape and rate. + * + * @param float $x Value x + * @param float $alpha Alpha shape + * @param float $beta Beta rate + * + * @return float + * + * @since 1.0.0 + */ + public static function getPdfRate(float $x, float $alpha, float $beta) : float + { + return $beta ** $alpha / Gamma::gamma($alpha) * \pow($x, $alpha - 1) * \exp(-$beta * $x); + } + + /** + * Get probability density function for shape and scale. * * @param float $x Value x * @param int $k k shape @@ -36,13 +68,13 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getPdfIntegerK(float $x, int $k, float $theta) : float + public static function getPdfIntegerScale(float $x, int $k, float $theta) : float { return 1 / (Gamma::getGammaInteger($k) * $theta ** $k) * \pow($x, $k - 1) * \exp(-$x / $theta); } /** - * Get probability density function. + * Get probability density function for shape and rate. * * @param float $x Value x * @param int $alpha Alpha shape @@ -52,11 +84,43 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getPdfIntegerAlphaBeta(float $x, int $alpha, float $beta) : float + public static function getPdfIntegerRate(float $x, int $alpha, float $beta) : float { return $beta ** $alpha / Gamma::getGammaInteger($alpha) * \pow($x, $alpha - 1) * \exp(-$beta * $x); } + /** + * Get cumulative density function for shape and scale. + * + * @param float $x Value x + * @param float $k k shape + * @param float $theta Theta scale + * + * @return float + * + * @since 1.0.0 + */ + public static function getCdfScale(float $x, float $k, float $theta) : float + { + return 1 / Gamma::gamma($k) * Gamma::incompleteGammaFirst($k, $x / $theta); + } + + /** + * Get cumulative density function for shape and rate. + * + * @param float $x Value x + * @param float $alpha Alpha shape + * @param float $beta Beta rate + * + * @return float + * + * @since 1.0.0 + */ + public static function getCdfRate(float $x, float $alpha, float $beta) : float + { + return 1 / Gamma::gamma($alpha) * Gamma::incompleteGammaFirst($alpha, $beta * $x); + } + /** * Get expected value. * @@ -67,7 +131,7 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getMeanK(float $k, float $theta) : float + public static function getMeanScale(float $k, float $theta) : float { return $k * $theta; } @@ -82,9 +146,9 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getMeanAlphaBeta(float $alpha, float $beta) : float + public static function getMeanRate(float $alpha, float $beta) : float { - return $alpha * $beta; + return $alpha / $beta; } /** @@ -97,7 +161,7 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getModeK(float $k, float $theta) : float + public static function getModeScale(float $k, float $theta) : float { return ($k - 1) * $theta; } @@ -112,7 +176,7 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getModeAlphaBeta(float $alpha, float $beta) : float + public static function getModeRate(float $alpha, float $beta) : float { return ($alpha - 1) / $beta; } @@ -155,7 +219,7 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getVarianceK(float $k, float $theta) : float + public static function getVarianceScale(float $k, float $theta) : float { return $k * $theta ** 2; } @@ -170,9 +234,9 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getStandardDeviationK(float $k, float $theta) : float + public static function getStandardDeviationScale(float $k, float $theta) : float { - return \sqrt(self::getVarianceK($k, $theta)); + return \sqrt(self::getVarianceScale($k, $theta)); } /** @@ -185,7 +249,7 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getVarianceAlphaBeta(float $alpha, float $beta) : float + public static function getVarianceRate(float $alpha, float $beta) : float { return $alpha / ($beta ** 2); } @@ -200,9 +264,9 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getStandardDeviationAlphaBeta(float $alpha, float $beta) : float + public static function getStandardDeviationRate(float $alpha, float $beta) : float { - return \sqrt(self::getVarianceAlphaBeta($alpha, $beta)); + return \sqrt(self::getVarianceRate($alpha, $beta)); } /** @@ -216,7 +280,7 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getMgfK(float $k, float $t, float $theta) : float + public static function getMgfScale(float $k, float $t, float $theta) : float { return \pow(1 - $theta * $t, -$k); } @@ -232,7 +296,7 @@ final class GammaDistribution * * @since 1.0.0 */ - public static function getMgfAlphaBeta(float $t, float $alpha, float $beta) : float + public static function getMgfRate(float $t, float $alpha, float $beta) : float { return \pow(1 - $t / $beta, -$alpha); } diff --git a/Math/Stochastic/Distribution/GeometricDistribution.php b/Math/Stochastic/Distribution/GeometricDistribution.php index 41008794f..8cb704356 100644 --- a/Math/Stochastic/Distribution/GeometricDistribution.php +++ b/Math/Stochastic/Distribution/GeometricDistribution.php @@ -134,7 +134,9 @@ final class GeometricDistribution */ public static function getMgf(float $p, float $t) : float { - return $t < -\log(1 - $p) ? $p * \exp($t) / (1 - (1 - $p) * \exp($t)) : $p / (1 - (1 - $p) * \exp($t)); + return $t < -\log(1 - $p) + ? $p * \exp($t) / (1 - (1 - $p) * \exp($t)) + : $p / (1 - (1 - $p) * \exp($t)); } /** diff --git a/Math/Stochastic/Distribution/HypergeometricDistribution.php b/Math/Stochastic/Distribution/HypergeometricDistribution.php index da50a7520..72ec36bbb 100644 --- a/Math/Stochastic/Distribution/HypergeometricDistribution.php +++ b/Math/Stochastic/Distribution/HypergeometricDistribution.php @@ -39,7 +39,7 @@ final class HypergeometricDistribution */ public static function getPmf(int $K, int $N, int $k, int $n) : float { - return Functions::fact($K, $k) * Functions::fact($N - $K, $n - $k) / Functions::fact($N, $n); + return Functions::binomialCoefficient($K, $k) * Functions::binomialCoefficient($N - $K, $n - $k) / Functions::binomialCoefficient($N, $n); } /** @@ -141,22 +141,26 @@ final class HypergeometricDistribution } /** - * Get cummulative distribution function. + * Get cumulative distribution function. * - * @param int $sampleSuccesses Amount of sample successes - * @param int $samples Sample size - * @param int $populationSuccesses Amount of population successes - * @param int $population Population size + * @param int $K Successful states in the population + * @param int $N Population size + * @param int $k Observed successes + * @param int $n Number of draws * * @return float * * @since 1.0.0 */ - public static function getCdf(int $sampleSuccesses, int $samples, int $populationSuccesses, int $population) : float + public static function getCdf(int $K, int $N, int $k, int $n) : float { - // Each multiplication calculates the total amount of possible group combinations based on a total amount of items. - return (int) (\round(Functions::fact($populationSuccesses) / Functions::fact($populationSuccesses - $sampleSuccesses)) / Functions::fact($sampleSuccesses) - * \round(Functions::fact($population - $populationSuccesses) / Functions::fact($population - $populationSuccesses - ($samples - $sampleSuccesses))) / Functions::fact($samples - $sampleSuccesses) - * \round(Functions::fact($population) / Functions::fact($population - $samples)) / Functions::fact($samples)); + return 1 - Functions::binomialCoefficient($n, $k + 1) + * Functions::binomialCoefficient($N - $n, $K - $k - 1) + / Functions::binomialCoefficient($N, $K) + * Functions::generalizedHypergeometricFunction( + [1, $k + 1 - $K, $k + 1 - $n], + [$k + 2, $N + $k + 2 - $K - $n], + 1 + ); } } diff --git a/Math/Stochastic/Distribution/LogDistribution.php b/Math/Stochastic/Distribution/LogDistribution.php index 75679b7e8..76039d55d 100644 --- a/Math/Stochastic/Distribution/LogDistribution.php +++ b/Math/Stochastic/Distribution/LogDistribution.php @@ -13,6 +13,8 @@ declare(strict_types=1); namespace phpOMS\Math\Stochastic\Distribution; +use phpOMS\Math\Functions\Beta; + /** * Log distribution. * @@ -38,6 +40,24 @@ final class LogDistribution return -1 / \log(1 - $p) * $p ** $k / $k; } + /** + * Get cumulative distribution function. + * + * @param float $p Value p + * @param int $k Value k + * + * @return float + * + * @since 1.0.0 + */ + public static function getCdf(float $p, int $k) : float + { + // This is a workaround! + // Actually 0 should be used instead of 0.0001. + // This is only used because the incomplete beta function doesn't work for p or q = 0 + return 1 + Beta::incompleteBeta($p, $k + 1, 0.0001) / \log(1 - $p); + } + /** * Get expected value. * @@ -97,13 +117,13 @@ final class LogDistribution * Get moment generating function. * * @param float $p Value p - * @param int $t Value t + * @param float $t Value t * * @return float * * @since 1.0.0 */ - public static function getMgf(float $p, int $t) : float + public static function getMgf(float $p, float $t) : float { return \log(1 - $p * \exp($t)) / \log(1 - $p); } diff --git a/Math/Stochastic/Distribution/LogNormalDistribution.php b/Math/Stochastic/Distribution/LogNormalDistribution.php index ef14c0681..d728229d7 100644 --- a/Math/Stochastic/Distribution/LogNormalDistribution.php +++ b/Math/Stochastic/Distribution/LogNormalDistribution.php @@ -154,9 +154,9 @@ final class LogNormalDistribution * * @since 1.0.0 */ - public static function getEntrpoy(float $mu, float $sigma) : float + public static function getEntropy(float $mu, float $sigma) : float { - return \log($sigma * \exp($mu + 1 / 2) * \sqrt(2 * \M_1_PI), 2); + return \log($sigma * \exp($mu + 1 / 2) * \sqrt(2 * \M_PI), 2); } /** @@ -172,12 +172,12 @@ final class LogNormalDistribution { return [ [1 / ($sigma ** 2), 0], - [0, 1 / (2 * $sigma ** 2)], + [0, 1 / (2 * $sigma ** 4)], ]; } /** - * Get cummulative distribution function. + * Get cumulative distribution function. * * @param float $x Value * @param float $mean Mean diff --git a/Math/Stochastic/Distribution/LogisticDistribution.php b/Math/Stochastic/Distribution/LogisticDistribution.php index 4f2a4495d..f3629444f 100644 --- a/Math/Stochastic/Distribution/LogisticDistribution.php +++ b/Math/Stochastic/Distribution/LogisticDistribution.php @@ -41,7 +41,7 @@ final class LogisticDistribution } /** - * Get cummulative distribution function. + * Get cumulative distribution function. * * @param float $x Value x * @param float $mu Mean diff --git a/Math/Stochastic/Distribution/NormalDistribution.php b/Math/Stochastic/Distribution/NormalDistribution.php index 6fd462e9b..20a45fa1c 100644 --- a/Math/Stochastic/Distribution/NormalDistribution.php +++ b/Math/Stochastic/Distribution/NormalDistribution.php @@ -89,7 +89,7 @@ final class NormalDistribution } /** - * Get cummulative distribution function. + * Get cumulative distribution function. * * @param float $x Value x * @param float $mu Mean @@ -213,7 +213,10 @@ final class NormalDistribution */ public static function getFisherInformation(float $sig) : array { - return [[1 / $sig ** 2, 0], [0, 1 / (2 * $sig ** 4)]]; + return [ + [1 / $sig ** 2, 0], + [0, 1 / (2 * $sig ** 4)], + ]; } /** diff --git a/Math/Stochastic/Distribution/TDistribution.php b/Math/Stochastic/Distribution/TDistribution.php index b42fba6a2..097baaf62 100644 --- a/Math/Stochastic/Distribution/TDistribution.php +++ b/Math/Stochastic/Distribution/TDistribution.php @@ -161,7 +161,7 @@ final class TDistribution } /** - * Get cummulative distribution function. + * Get cumulative distribution function. * * @param float $x Value * @param int $degrees Degrees of freedom @@ -171,7 +171,7 @@ final class TDistribution * * @since 1.0.0 */ - public static function getCdf(float $x, int $degrees, int $tails = 2) : float + public static function getCdf(float $x, int $degrees, int $tails = 1) : float { if ($x < 0.0 || $degrees < 1 || $tails < 1 || $tails > 2) { return 0.0; @@ -210,6 +210,6 @@ final class TDistribution $t = 0.5 * (1 + $sum); - return $tails === 1 ? 1 - \abs($t) : 1 - \abs(1 - $t - $t); + return $tails === 1 ? \abs($t) : 1 - \abs(1 - $t - $t); } } diff --git a/Math/Stochastic/Distribution/UniformDistributionDiscrete.php b/Math/Stochastic/Distribution/UniformDistributionDiscrete.php index 6edca2ab0..6126375a6 100644 --- a/Math/Stochastic/Distribution/UniformDistributionDiscrete.php +++ b/Math/Stochastic/Distribution/UniformDistributionDiscrete.php @@ -74,7 +74,8 @@ final class UniformDistributionDiscrete */ public static function getMgf(int $t, float $a, float $b) : float { - return (\exp($a * $t) - \exp(($b + 1) * $t)) / (($b - $a + 1) * (1 - \exp($t))); + return (\exp($a * $t) - \exp(($b + 1) * $t)) + / (($b - $a + 1) * (1 - \exp($t))); } /** diff --git a/Math/Stochastic/Distribution/WeibullDistribution.php b/Math/Stochastic/Distribution/WeibullDistribution.php index ce7d8af8e..7ff16a816 100644 --- a/Math/Stochastic/Distribution/WeibullDistribution.php +++ b/Math/Stochastic/Distribution/WeibullDistribution.php @@ -13,6 +13,8 @@ declare(strict_types=1); namespace phpOMS\Math\Stochastic\Distribution; +use phpOMS\Math\Functions\Gamma; + /** * Weibull distribution. * @@ -36,7 +38,9 @@ final class WeibullDistribution */ public static function getPdf(float $x, float $lambda, float $k) : float { - return $x < 0.0 ? 0.0 : $k / $lambda * \pow($x / $lambda, $k - 1) * \exp(-($x / $lambda) ** $k); + return $x < 0.0 + ? 0.0 + : $k / $lambda * \pow($x / $lambda, $k - 1) * \exp(-($x / $lambda) ** $k); } /** @@ -52,7 +56,24 @@ final class WeibullDistribution */ public static function getCdf(float $x, float $lambda, float $k) : float { - return $x < 0.0 ? 0.0 : 1 - \exp(-($x / $lambda) ** $k); + return $x < 0.0 + ? 0.0 + : 1 - \exp(-($x / $lambda) ** $k); + } + + /** + * Get mean. + * + * @param float $lambda Scale lambda + * @param float $k Shape k + * + * @return float + * + * @since 1.0.0 + */ + public static function getMean(float $lambda, float $k) : float + { + return $lambda * Gamma::gamma(1 + 1 / $k); } /** @@ -70,6 +91,36 @@ final class WeibullDistribution return $lambda * \pow(\log(2), 1 / $k); } + /** + * Get the variance. + * + * @param float $lambda Scale lambda + * @param float $k Shape k + * + * @return float + * + * @since 1.0.0 + */ + public static function getVariance(float $lambda, float $k) : float + { + return $lambda ** 2 * (Gamma::gamma(1 + 2 / $k) - Gamma::gamma(1 + 1 / $k) ** 2); + } + + /** + * Get the standard deviation. + * + * @param float $lambda Scale lambda + * @param float $k Shape k + * + * @return float + * + * @since 1.0.0 + */ + public static function getStandardDeviation(float $lambda, float $k) : float + { + return \sqrt(self::getVariance($lambda, $k)); + } + /** * Get mode. * @@ -85,6 +136,25 @@ final class WeibullDistribution return $lambda * \pow(($k - 1) / $k, 1 / $k); } + /** + * Get skewness. + * + * @param float $lambda Scale lambda + * @param float $k Shape k + * + * @return float + * + * @since 1.0.0 + */ + public static function getSkewness(float $lambda, float $k) : float + { + $mu = self::getMean($lambda, $k); + $sig = self::getStandardDeviation($lambda, $k); + + return (Gamma::gamma(1 + 3 / $k) * $lambda ** 3 - 3 * $mu * $sig ** 2 - $mu ** 3) + / ($sig ** 3); + } + /** * Get entropy. * diff --git a/Math/Stochastic/Distribution/ZTest.php b/Math/Stochastic/Distribution/ZTesting.php similarity index 89% rename from Math/Stochastic/Distribution/ZTest.php rename to Math/Stochastic/Distribution/ZTesting.php index 0183155c0..29be4ef46 100644 --- a/Math/Stochastic/Distribution/ZTest.php +++ b/Math/Stochastic/Distribution/ZTesting.php @@ -27,7 +27,7 @@ use phpOMS\Math\Statistic\MeasureOfDispersion; * * @internal */ -final class ZTest +final class ZTesting { public const TABLE = [ '2.58' => 0.99, @@ -75,11 +75,11 @@ final class ZTest * * @since 1.0.0 */ - public static function zTesting(float $value, array $data, float $sigma = null) : float + public static function zTest(float $value, array $data, float $sigma = null) : float { $sigma ??= MeasureOfDispersion::standardDeviationSample($data); - return 1 - NormalDistribution::getCdf((Average::arithmeticMean($data) - $value) / ($sigma / \sqrt(\count($data))), 0.0, 1.0, true); + return 1 - NormalDistribution::getCdf((Average::arithmeticMean($data) - $value) / ($sigma / \sqrt(\count($data))), 0.0, 1.0); } /** @@ -94,8 +94,8 @@ final class ZTest * * @since 1.0.0 */ - public static function zTestingValues(float $value, float $mean, int $dataSize, float $sigma) : float + public static function zTestValues(float $value, float $mean, int $dataSize, float $sigma) : float { - return 1 - NormalDistribution::getCdf(($mean - $value) / ($sigma / \sqrt($dataSize)), 0.0, 1.0, true); + return 1 - NormalDistribution::getCdf(($mean - $value) / ($sigma / \sqrt($dataSize)), 0.0, 1.0); } } diff --git a/tests/Ai/Ocr/BasicOcrTest.php b/tests/Ai/Ocr/BasicOcrTest.php index 6ea8367ff..983e8c78b 100644 --- a/tests/Ai/Ocr/BasicOcrTest.php +++ b/tests/Ai/Ocr/BasicOcrTest.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace phpOMS\tests\Ai\Ocr; +use phpOMS\Ai\Ocr\BasicOcr; + /** * @internal */ diff --git a/tests/DataStorage/Cache/Connection/FileCacheTest.php b/tests/DataStorage/Cache/Connection/FileCacheTest.php index cf3c488eb..c00fae077 100644 --- a/tests/DataStorage/Cache/Connection/FileCacheTest.php +++ b/tests/DataStorage/Cache/Connection/FileCacheTest.php @@ -57,6 +57,9 @@ class FileCacheTest extends \PHPUnit\Framework\TestCase self::assertTrue(\is_dir(__DIR__ . '/Cache')); self::assertTrue($this->cache->flushAll()); self::assertEquals(50, $this->cache->getThreshold()); + self::assertEquals('', $this->cache->getCache()); + self::assertEquals('', $this->cache->getHost()); + self::assertEquals(0, $this->cache->getPort()); self::assertNull($this->cache->get('test')); self::assertEquals( [ diff --git a/tests/DataStorage/Cache/Connection/MemCachedTest.php b/tests/DataStorage/Cache/Connection/MemCachedTest.php index ca9cb00d9..941f92dc8 100644 --- a/tests/DataStorage/Cache/Connection/MemCachedTest.php +++ b/tests/DataStorage/Cache/Connection/MemCachedTest.php @@ -55,6 +55,9 @@ class MemCachedTest extends \PHPUnit\Framework\TestCase self::assertTrue($this->cache->flushAll()); self::assertEquals(0, $this->cache->getThreshold()); self::assertNull($this->cache->get('test')); + self::assertEquals('', $this->cache->getCache()); + self::assertEquals('127.0.0.1', $this->cache->getHost()); + self::assertEquals(11211, $this->cache->getPort()); self::assertEquals( [ 'status' => CacheStatus::OK, @@ -244,6 +247,20 @@ class MemCachedTest extends \PHPUnit\Framework\TestCase self::assertNull($this->cache->get('key2', 1)); } + /** + * @testdox Cache data can be flushed by expiration date + * @covers phpOMS\DataStorage\Cache\Connection\MemCached + * @group framework + */ + public function testFlushExpired() : void + { + $this->cache->set('key6', 'testVal6', 1); + \sleep(2); + + $this->cache->flush(0); + self::assertNull($this->cache->get('key6', 0)); + } + /** * @testdox A bad cache status will prevent all cache actions * @covers phpOMS\DataStorage\Cache\Connection\MemCached diff --git a/tests/DataStorage/Cache/Connection/RedisCacheTest.php b/tests/DataStorage/Cache/Connection/RedisCacheTest.php index c1891cdf8..cb4aff81e 100644 --- a/tests/DataStorage/Cache/Connection/RedisCacheTest.php +++ b/tests/DataStorage/Cache/Connection/RedisCacheTest.php @@ -58,6 +58,9 @@ class RedisCacheTest extends \PHPUnit\Framework\TestCase self::assertEquals(CacheStatus::OK, $this->cache->stats()['status']); self::assertEquals(0, $this->cache->stats()['count']); self::assertGreaterThanOrEqual(0, $this->cache->stats()['size']); + self::assertEquals('1', $this->cache->getCache()); + self::assertEquals('127.0.0.1', $this->cache->getHost()); + self::assertEquals(6379, $this->cache->getPort()); } /** diff --git a/tests/DataStorage/Session/FileSessionHandlerTest.php b/tests/DataStorage/Session/FileSessionHandlerTest.php new file mode 100644 index 000000000..bad996100 --- /dev/null +++ b/tests/DataStorage/Session/FileSessionHandlerTest.php @@ -0,0 +1,130 @@ +sh = new FileSessionHandler(__DIR__ . '/test'); + } + + protected function tearDown() : void + { + if (\file_exists(__DIR__ . '/test')) { + Directory::delete(__DIR__ . '/test'); + } + } + + /** + * @testdox A session id can be generated + * @group framework + */ + public function testCreateSid() : void + { + self::assertMatchesRegularExpression('/^s\-[a-z0-9]+/', $this->sh->create_sid()); + } + + /** + * @testdox The session path can be accessed + * @group framework + */ + public function testSessionPath() : void + { + self::assertTrue($this->sh->open(__DIR__ . '/test', '')); + } + + /** + * @testdox A invalid session path cannot be accessed + * @group framework + */ + public function testInvalidSessionPath() : void + { + self::assertFalse($this->sh->open(__DIR__ . '/invalid', '')); + } + + /** + * @testdox A session can be closed + * @group framework + */ + public function testSessionClose() : void + { + self::assertTrue($this->sh->close()); + } + + /** + * @testdox A valid session id can store and return data + * @group framework + */ + public function testSessionInputOutput() : void + { + $id = $this->sh->create_sid(); + self::assertTrue($this->sh->write($id, 'test')); + self::assertEquals('test', $this->sh->read($id)); + } + + /** + * @testdox A invalid session id doesn't return any data + * @group framework + */ + public function testReadInvalidSessionId() : void + { + self::assertEquals('', $this->sh->read('invalid')); + } + + /** + * @testdox A session can be destroyed + * @group framework + */ + public function testSessionDestroy() : void + { + $id = $this->sh->create_sid(); + self::assertTrue($this->sh->write($id, 'test')); + self::assertEquals('test', $this->sh->read($id)); + + $this->sh->destroy($id); + self::assertEquals('', $this->sh->read($id)); + } + + /** + * @testdox Sessions can be removed based on a timeout + * @group framework + */ + public function testSessionTimeoutDestroy() : void + { + $id = $this->sh->create_sid(); + self::assertTrue($this->sh->write($id, 'test')); + self::assertEquals('test', $this->sh->read($id)); + + \sleep(2); + + $this->sh->gc(0); + self::assertEquals('', $this->sh->read($id)); + } +} diff --git a/tests/DataStorage/Session/FileSessionTest.php b/tests/DataStorage/Session/FileSessionTest.php new file mode 100644 index 000000000..12aae7f93 --- /dev/null +++ b/tests/DataStorage/Session/FileSessionTest.php @@ -0,0 +1,156 @@ +session = new FileSession(); + } + + /** + * @testdox The session has the expected default values after initialization + * @group framework + */ + public function testDefault() : void + { + self::assertNull($this->session->get('key')); + self::assertFalse($this->session->isLocked()); + } + + /** + * @testdox Session data can be set and returned + * @group framework + */ + public function testInputOutput() : void + { + self::assertTrue($this->session->set('test', 'value')); + self::assertEquals('value', $this->session->get('test')); + } + + /** + * @testdox Session data cannot be overwritten + * @group framework + */ + public function testInvalidOverwrite() : void + { + $this->session->set('test', 'value'); + self::assertFalse($this->session->set('test', 'value2')); + self::assertEquals('value', $this->session->get('test')); + } + + /** + * @testdox Session data can be forced to overwrite + * @group framework + */ + public function testOverwrite() : void + { + $this->session->set('test', 'value'); + self::assertTrue($this->session->set('test', 'value2', true)); + self::assertEquals('value2', $this->session->get('test')); + } + + /** + * @testdox Session data can be removed + * @group framework + */ + public function testRemove() : void + { + $this->session->set('test', 'value'); + self::assertTrue($this->session->remove('test')); + } + + /** + * @testdox None-existing session data cannot be removed + * @group framework + */ + public function testInvalidRemove() : void + { + $this->session->set('test', 'value'); + $this->session->remove('test'); + + self::assertFalse($this->session->remove('test')); + } + + /** + * @testdox A session id can be set and returned + * @group framework + */ + public function testSessionIdInputOutput() : void + { + $this->session->setSID('abc'); + self::assertEquals('abc', $this->session->getSID()); + } + + /** + * @testdox A session can be locked + * @group framework + */ + public function testLockInputOutput() : void + { + $this->session->lock(); + self::assertTrue($this->session->isLocked()); + } + + /** + * @testdox Session data can be saved + * @group framework + */ + public function testSave() : void + { + self::assertTrue($this->session->save()); + } + + /** + * @testdox Locked sessions cannot be saved + * @group framework + */ + public function testInvalidLockSave() : void + { + $this->session->lock(); + self::assertFalse($this->session->save()); + } + + /** + * @testdox A locked session cannot add or change data + * @group framework + */ + public function testLockInvalidSet() : void + { + $this->session->lock(); + self::assertFalse($this->session->set('test', 'value')); + } + + /** + * @testdox A locked session cannot remove data + * @group framework + */ + public function testLockInvalidRemove() : void + { + self::assertTrue($this->session->set('test', 'value')); + $this->session->lock(); + self::assertFalse($this->session->remove('test')); + } +} diff --git a/tests/DataStorage/Session/HttpSessionTest.php b/tests/DataStorage/Session/HttpSessionTest.php index 069918e89..0793cabd0 100644 --- a/tests/DataStorage/Session/HttpSessionTest.php +++ b/tests/DataStorage/Session/HttpSessionTest.php @@ -23,6 +23,13 @@ use phpOMS\DataStorage\Session\HttpSession; */ class HttpSessionTest extends \PHPUnit\Framework\TestCase { + protected HttpSession $session; + + protected function setUp() : void + { + $this->session = new HttpSession(1, '', 1); + } + /** * @testdox The session has the expected default values after initialization * @group framework @@ -40,9 +47,8 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testInputOutput() : void { - $session = new HttpSession(1, '', 1); - self::assertTrue($session->set('test', 'value')); - self::assertEquals('value', $session->get('test')); + self::assertTrue($this->session->set('test', 'value')); + self::assertEquals('value', $this->session->get('test')); } /** @@ -51,10 +57,9 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testInvalidOverwrite() : void { - $session = new HttpSession(1, '', 1); - $session->set('test', 'value'); - self::assertFalse($session->set('test', 'value2')); - self::assertEquals('value', $session->get('test')); + $this->session->set('test', 'value'); + self::assertFalse($this->session->set('test', 'value2')); + self::assertEquals('value', $this->session->get('test')); } /** @@ -63,10 +68,9 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testOverwrite() : void { - $session = new HttpSession(1, '', 1); - $session->set('test', 'value'); - self::assertTrue($session->set('test', 'value2', true)); - self::assertEquals('value2', $session->get('test')); + $this->session->set('test', 'value'); + self::assertTrue($this->session->set('test', 'value2', true)); + self::assertEquals('value2', $this->session->get('test')); } /** @@ -75,9 +79,8 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testRemove() : void { - $session = new HttpSession(1, '', 1); - $session->set('test', 'value'); - self::assertTrue($session->remove('test')); + $this->session->set('test', 'value'); + self::assertTrue($this->session->remove('test')); } /** @@ -86,11 +89,10 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testInvalidRemove() : void { - $session = new HttpSession(1, '', 1); - $session->set('test', 'value'); - $session->remove('test'); + $this->session->set('test', 'value'); + $this->session->remove('test'); - self::assertFalse($session->remove('test')); + self::assertFalse($this->session->remove('test')); } /** @@ -99,9 +101,8 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testSessionIdInputOutput() : void { - $session = new HttpSession(1, '', 1); - $session->setSID('abc'); - self::assertEquals('abc', $session->getSID()); + $this->session->setSID('abc'); + self::assertEquals('abc', $this->session->getSID()); } /** @@ -110,10 +111,27 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testLockInputOutput() : void { - $session = new HttpSession(1, '', 1); + $this->session->lock(); + self::assertTrue($this->session->isLocked()); + } - $session->lock(); - self::assertTrue($session->isLocked()); + /** + * @testdox Session data can be saved + * @group framework + */ + public function testSave() : void + { + self::assertTrue($this->session->save()); + } + + /** + * @testdox Locked sessions cannot be saved + * @group framework + */ + public function testInvalidLockSave() : void + { + $this->session->lock(); + self::assertFalse($this->session->save()); } /** @@ -122,10 +140,8 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testLockInvalidSet() : void { - $session = new HttpSession(1, '', 1); - - $session->lock(); - self::assertFalse($session->set('test', 'value')); + $this->session->lock(); + self::assertFalse($this->session->set('test', 'value')); } /** @@ -134,10 +150,8 @@ class HttpSessionTest extends \PHPUnit\Framework\TestCase */ public function testLockInvalidRemove() : void { - $session = new HttpSession(1, '', 1); - - self::assertTrue($session->set('test', 'value')); - $session->lock(); - self::assertFalse($session->remove('test')); + self::assertTrue($this->session->set('test', 'value')); + $this->session->lock(); + self::assertFalse($this->session->remove('test')); } } diff --git a/tests/Math/Functions/BetaTest.php b/tests/Math/Functions/BetaTest.php index 546f5e1a0..a3fa59211 100644 --- a/tests/Math/Functions/BetaTest.php +++ b/tests/Math/Functions/BetaTest.php @@ -23,18 +23,56 @@ use phpOMS\Math\Functions\Beta; */ class BetaTest extends \PHPUnit\Framework\TestCase { - public function testIncompleteBeta() : void - { - self::markTestIncomplete(); - } - - public function testLogBeta() : void - { - self::markTestIncomplete(); - } - + /** + * @testdox The beta function can be approximated + * @covers phpOMS\Math\Functions\Beta + * @group framework + */ public function beta() : void { - self::markTestIncomplete(); + self::assertEqualsWithDelta(1.0, Beta::beta(0, 3), 0.001); + self::assertEqualsWithDelta(4.4776093, Beta::beta(1.5, 0.2), 0.001); + self::assertEqualsWithDelta(0.045648, Beta::beta(2, 4), 0.001); + } + + /** + * @testdox The log beta function can be approximated + * @covers phpOMS\Math\Functions\Beta + * @group framework + */ + public function testLogBeta() : void + { + self::assertEqualsWithDelta(0, Beta::logBeta(1, 0), 0.001); + self::assertEqualsWithDelta(\log(4.4776093), Beta::logBeta(1.5, 0.2), 0.001); + self::assertEqualsWithDelta(\log(Beta::beta(2, 4)), Beta::logBeta(2, 4), 0.001); + } + + /** + * @testdox The incomplete beta function can be approximated + * @covers phpOMS\Math\Functions\Beta + * @group framework + */ + public function testIncompleteBeta() : void + { + self::assertEqualsWithDelta(0.0, Beta::incompleteBeta(-1, 1, 3), 0.001); + self::assertEqualsWithDelta(0.3333, Beta::incompleteBeta(1.0, 1, 3), 0.001); + self::assertEqualsWithDelta(0.0, Beta::incompleteBeta(0.4, 0, 3), 0.001); + self::assertEqualsWithDelta(0.261333, Beta::incompleteBeta(0.4, 1, 3), 0.001); + self::assertEqualsWithDelta(0.045648, Beta::incompleteBeta(0.6, 2, 4), 0.001); + } + + /** + * @testdox The regularized beta function can be approximated + * @covers phpOMS\Math\Functions\Beta + * @group framework + */ + public function testRegularizedBeta() : void + { + self::assertEqualsWithDelta(0.0, Beta::regularizedBeta(-1, 1, 3), 0.001); + self::assertEqualsWithDelta(1.0, Beta::regularizedBeta(1.0, 1, 3), 0.001); + self::assertEqualsWithDelta(0.0, Beta::regularizedBeta(0.4, 0, 3), 0.001); + self::assertEqualsWithDelta(0.784, Beta::regularizedBeta(0.4, 1, 3), 0.001); + self::assertEqualsWithDelta(0.04, Beta::regularizedBeta(0.2, 2, 1), 0.001); + self::assertEqualsWithDelta(0.91296, Beta::regularizedBeta(0.6, 2, 4), 0.001); } } diff --git a/tests/Math/Functions/FunctionsTest.php b/tests/Math/Functions/FunctionsTest.php index bd9b0bc53..be886739b 100644 --- a/tests/Math/Functions/FunctionsTest.php +++ b/tests/Math/Functions/FunctionsTest.php @@ -109,13 +109,39 @@ class FunctionsTest extends \PHPUnit\Framework\TestCase self::assertEquals(11, Functions::getRelativeDegree(6, 12, 7)); } + /** + * @testdox The error function can be correctly approximated + * @covers phpOMS\Math\Functions\Functions + * @group framework + */ public function testErf() : void { - self::markTestIncomplete(); + self::assertEqualsWithDelta(-0.8427, Functions::getErf(-1), 0.001); + self::assertEqualsWithDelta(0.0, Functions::getErf(0), 0.001); + self::assertEqualsWithDelta(0.8427, Functions::getErf(1), 0.001); + self::assertEqualsWithDelta(0.9988, Functions::getErf(2.3), 0.001); } + /** + * @testdox The complementary error function can be correctly approximated + * @covers phpOMS\Math\Functions\Functions + * @group framework + */ public function testErfc() : void { - self::markTestIncomplete(); + self::assertEqualsWithDelta(1.8427, Functions::getErfc(-1), 0.001); + self::assertEqualsWithDelta(1, Functions::getErfc(0), 0.001); + self::assertEqualsWithDelta(0.15729920705, Functions::getErfc(1), 0.001); + self::assertEqualsWithDelta(2.0, Functions::getErfc(-5), 0.001); + } + + /** + * @testdox The generalized hypergeometric function can be correctly calculated + * @covers phpOMS\Math\Functions\Functions + * @group framework + */ + public function testGeneralizedHypergeometricFunction() : void + { + self::assertEqualsWithDelta(2.7289353, Functions::generalizedHypergeometricFunction([2, 3], [4], 0.5), 0.001); } } diff --git a/tests/Math/Functions/GammaTest.php b/tests/Math/Functions/GammaTest.php index dbc213c54..96ed94323 100644 --- a/tests/Math/Functions/GammaTest.php +++ b/tests/Math/Functions/GammaTest.php @@ -24,6 +24,17 @@ use phpOMS\Math\Functions\Gamma; */ class GammaTest extends \PHPUnit\Framework\TestCase { + /** + * @testdox The gamma function can be approximated + * @covers phpOMS\Math\Functions\Gamma + * @group framework + */ + public function testGamma() : void + { + self::assertEqualsWithDelta(2.0, Gamma::gamma(3.0), 0.001); + self::assertEqualsWithDelta(11.631728, Gamma::gamma(4.5), 0.001); + } + /** * @testdox The gamma function can be calculated for integers * @covers phpOMS\Math\Functions\Gamma @@ -94,8 +105,59 @@ class GammaTest extends \PHPUnit\Framework\TestCase self::assertTrue(true); } + /** + * @testdox The log gamma function can be approximated + * @covers phpOMS\Math\Functions\Gamma + * @group framework + */ public function testLogGamma() : void { - self::markTestIncomplete(); + $gsl = [ + 0.0, 0.0, 0.693147, 1.791759, 3.178053, 4.787491, 6.57925, 8.52516, 10.604602, 12.801827, + ]; + + for ($i = 1; $i <= 10; ++$i) { + if (!(\abs($gsl[$i - 1] - Gamma::logGamma($i)) < 0.01)) { + self::assertTrue(false); + } + } + + self::assertTrue(true); + } + + /** + * @testdox The first incomplete gamma function can be approximated + * @covers phpOMS\Math\Functions\Gamma + * @group framework + */ + public function testFirstIncompleteGamma() : void + { + self::assertEqualsWithDelta(0.0, Gamma::incompleteGammaFirst(3.0, 0.0), 0.001); + self::assertEqualsWithDelta(1.523793, Gamma::incompleteGammaFirst(3.0, 4.0), 0.001); + self::assertEqualsWithDelta(2.116608, Gamma::incompleteGammaFirst(4.0, 3.0), 0.001); + } + + /** + * @testdox The second incomplete gamma function can be approximated + * @covers phpOMS\Math\Functions\Gamma + * @group framework + */ + public function testSecondIncompleteGamma() : void + { + self::assertEqualsWithDelta(2.0, Gamma::incompleteGammaSecond(3.0, 0.0), 0.001); + self::assertEqualsWithDelta(0.476206, Gamma::incompleteGammaSecond(3.0, 4.0), 0.001); + self::assertEqualsWithDelta(3.883391, Gamma::incompleteGammaSecond(4.0, 3.0), 0.001); + } + + /** + * @testdox The regularized incomplete gamma function can be approximated + * @covers phpOMS\Math\Functions\Gamma + * @group framework + */ + public function testRegularizedGamma() : void + { + self::assertEqualsWithDelta(0.0, Gamma::regularizedGamma(3.0, 0.0), 0.001); + self::assertEqualsWithDelta(0.761896, Gamma::regularizedGamma(3.0, 4.0), 0.001); + self::assertEqualsWithDelta(0.352768, Gamma::regularizedGamma(4.0, 3.0), 0.001); } } diff --git a/tests/Math/Matrix/LUDecompositionTest.php b/tests/Math/Matrix/LUDecompositionTest.php index 77a4deeb5..aba597678 100644 --- a/tests/Math/Matrix/LUDecompositionTest.php +++ b/tests/Math/Matrix/LUDecompositionTest.php @@ -190,6 +190,24 @@ class LUDecompositionTest extends \PHPUnit\Framework\TestCase ); } + /** + * @testdox The determinat can be calculated + * @covers phpOMS\Math\Matrix\LUDecomposition + * @group framework + */ + public function testDet() : void + { + $B = new Matrix(); + $B->setMatrix([ + [25, 15, -5], + [15, 17, 0], + [-5, 0, 11], + ]); + + $lu = new LUDecomposition($B); + self::assertEqualsWithDelta(1775.0, $lu->det(), 0.1); + } + /** * @testdox A invalid vector throws a InvalidDimensionException * @covers phpOMS\Math\Matrix\LUDecomposition diff --git a/tests/Math/Numerics/Interpolation/CubicSplineInterpolationTest.php b/tests/Math/Numerics/Interpolation/CubicSplineInterpolationTest.php index e8b9fa9fb..a19de9b2f 100644 --- a/tests/Math/Numerics/Interpolation/CubicSplineInterpolationTest.php +++ b/tests/Math/Numerics/Interpolation/CubicSplineInterpolationTest.php @@ -65,4 +65,26 @@ class CubicSplineInterpolationTest extends \PHPUnit\Framework\TestCase self::assertEqualsWithDelta(0.915345, $interpolation->interpolate(1.5), 0.1); } + + /** + * @testdox The spline interpolation for out of bounds values uses linear extrapolation + * @covers phpOMS\Math\Numerics\Interpolation\CubicSplineInterpolation + * @group framework + */ + public function testInterpolationUnderOverflow() : void + { + $interpolation = new CubicSplineInterpolation([ + ['x' => 0.1, 'y' => 0.1], + ['x' => 0.4, 'y' => 0.7], + ['x' => 1.2, 'y' => 0.6], + ['x' => 1.8, 'y' => 1.1], + ['x' => 2.0, 'y' => 0.9], + ], + 0.0, DerivativeType::SECOND, + 0.0, DerivativeType::SECOND, + ); + + self::assertEqualsWithDelta(-0.140528, $interpolation->interpolate(0), 0.001); + self::assertEqualsWithDelta(-0.016007, $interpolation->interpolate(2.5), 0.001); + } } diff --git a/tests/Math/Stochastic/Distribution/BernoulliDistributionTest.php b/tests/Math/Stochastic/Distribution/BernoulliDistributionTest.php index 90ca38dfc..59cc57226 100644 --- a/tests/Math/Stochastic/Distribution/BernoulliDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/BernoulliDistributionTest.php @@ -109,4 +109,10 @@ class BernoulliDistributionTest extends \PHPUnit\Framework\TestCase self::assertEqualsWithDelta(1 / ($p * $q), BernoulliDistribution::getFisherInformation($p), 0.01); } + + public function testInvalidPmfParameter() : void + { + $this->expectException(\InvalidArgumentException::class); + BernoulliDistribution::getPmf(0.7, 3); + } } diff --git a/tests/Math/Stochastic/Distribution/BetaDistributionTest.php b/tests/Math/Stochastic/Distribution/BetaDistributionTest.php index 63e40850f..f00ee0098 100644 --- a/tests/Math/Stochastic/Distribution/BetaDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/BetaDistributionTest.php @@ -55,4 +55,20 @@ class BetaDistributionTest extends \PHPUnit\Framework\TestCase { self::assertEqualsWithDelta(-6 / 7, BetaDistribution::getExKurtosis(2.0, 2.0), 0.001); } + + public function testPdf() : void + { + self::assertEqualsWithDelta(0.9375, BetaDistribution::getPdf(0.5, 2, 5), 0.001); + } + + public function testCdf() : void + { + self::assertEqualsWithDelta(0.890625, BetaDistribution::getCdf(0.5, 2, 5), 0.001); + } + + public function testMgf() : void + { + self::assertEqualsWithDelta(1.0, BetaDistribution::getMgf(0, 2, 5), 0.001); + self::assertEqualsWithDelta(1.869356, BetaDistribution::getMgf(2, 2, 5), 0.001); + } } diff --git a/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php b/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php index d583e1687..1c03995a8 100644 --- a/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/ChiSquaredDistributionTest.php @@ -103,6 +103,16 @@ class ChiSquaredDistributionTest extends \PHPUnit\Framework\TestCase self::assertEquals((1 - 2 * $t) ** (-$df / 2), ChiSquaredDistribution::getMgf($df, $t)); } + public function testPdf() : void + { + self::assertEqualsWithDelta(0.20755, ChiSquaredDistribution::getPdf(2, 3), 0.001); + } + + public function testCdf() : void + { + self::assertEqualsWithDelta(0.42759, ChiSquaredDistribution::getCdf(2, 3), 0.001); + } + public function testHypothesisSizeException() : void { $this->expectException(\Exception::class); diff --git a/tests/Math/Stochastic/Distribution/FDistributionTest.php b/tests/Math/Stochastic/Distribution/FDistributionTest.php index 7c4bc7a9e..37a6a82b1 100644 --- a/tests/Math/Stochastic/Distribution/FDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/FDistributionTest.php @@ -53,4 +53,14 @@ class FDistributionTest extends \PHPUnit\Framework\TestCase self::assertEquals(0.0, FDistribution::getSkewness(1, 6)); self::assertEquals(2 * (2 * 4 + 7 - 2) / (7 - 6) * \sqrt(2 * (7 - 4) / (4 * (7 + 4 - 2))), FDistribution::getSkewness(4, 7)); } + + public function testPdf() : void + { + self::assertEqualsWithDelta(0.2788548, FDistribution::getPdf(1, 2, 3), 0.001); + } + + public function testCdf() : void + { + self::assertEqualsWithDelta(0.5352419, FDistribution::getCdf(1, 2, 3), 0.001); + } } diff --git a/tests/Math/Stochastic/Distribution/GammaDistributionTest.php b/tests/Math/Stochastic/Distribution/GammaDistributionTest.php index 4397f7a94..97188fa97 100644 --- a/tests/Math/Stochastic/Distribution/GammaDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/GammaDistributionTest.php @@ -21,25 +21,71 @@ use phpOMS\Math\Stochastic\Distribution\GammaDistribution; */ class GammaDistributionTest extends \PHPUnit\Framework\TestCase { - public function testPDFIntegerK() : void + public function testPdfScale() : void { - self::assertEqualsWithDelta(\exp(-1), GammaDistribution::getPdfIntegerK(1, 1, 1), 0.001); - self::assertEqualsWithDelta(3 * \exp(-3 / 4) / 16, GammaDistribution::getPdfIntegerK(3, 2, 4), 0.001); + self::assertEqualsWithDelta(0.0734, GammaDistribution::getPdfScale(10, 4, 3), 0.001); } - public function testMeanK() : void + public function testPdfAlphaBete() : void { - self::assertEqualsWithDelta(8, GammaDistribution::getMeanK(2, 4), 0.001); + self::assertEqualsWithDelta(0.180447, GammaDistribution::getPdfRate(2, 4, 1), 0.001); } - public function testVarianceK() : void + public function testCdfScale() : void { - self::assertEqualsWithDelta(32, GammaDistribution::getVarianceK(2, 4), 0.001); + self::assertEqualsWithDelta(0.42701, GammaDistribution::getCdfScale(10, 4, 3), 0.001); } - public function testStandardDeviationK() : void + public function testCdfAlphaBete() : void { - self::assertEqualsWithDelta(\sqrt(32), GammaDistribution::getStandardDeviationK(2, 4), 0.001); + self::assertEqualsWithDelta(0.142876, GammaDistribution::getCdfRate(2, 4, 1), 0.001); + } + + public function testPdfIntegerScale() : void + { + self::assertEqualsWithDelta(\exp(-1), GammaDistribution::getPdfIntegerScale(1, 1, 1), 0.001); + self::assertEqualsWithDelta(3 * \exp(-3 / 4) / 16, GammaDistribution::getPdfIntegerScale(3, 2, 4), 0.001); + } + + public function testPdfIntegerRate() : void + { + self::assertEqualsWithDelta(0.180447, GammaDistribution::getPdfIntegerRate(2, 4, 1), 0.001); + } + + public function testMeanScale() : void + { + self::assertEqualsWithDelta(8, GammaDistribution::getMeanScale(2, 4), 0.001); + } + + public function testMeanRate() : void + { + $alpha = 4; + $beta = 2; + self::assertEquals($alpha / $beta, GammaDistribution::getMeanRate($alpha, $beta)); + } + + public function testVarianceScale() : void + { + self::assertEqualsWithDelta(32, GammaDistribution::getVarianceScale(2, 4), 0.001); + } + + public function testVarianceRate() : void + { + $alpha = 4; + $beta = 2; + self::assertEquals($alpha / \pow($beta, 2), GammaDistribution::getVarianceRate($alpha, $beta)); + } + + public function testStandardDeviationScale() : void + { + self::assertEqualsWithDelta(\sqrt(32), GammaDistribution::getStandardDeviationScale(2, 4), 0.001); + } + + public function testStandardDeviationRate() : void + { + $alpha = 4; + $beta = 2; + self::assertEquals(\sqrt($alpha / \pow($beta, 2)), GammaDistribution::getStandardDeviationRate($alpha, $beta)); } public function testExKurtosis() : void @@ -51,4 +97,30 @@ class GammaDistributionTest extends \PHPUnit\Framework\TestCase { self::assertEqualsWithDelta(\sqrt(2), GammaDistribution::getSkewness(2, 4), 0.001); } + + public function testMgfScale() : void + { + $theta = 2; + $t = 1 / $theta * 0.4; + $k = 3; + self::assertEquals(\pow(1 - $theta * $t, -$k), GammaDistribution::getMgfScale($k, $t, $theta)); + } + + public function testMgfRate() : void + { + $alpha = 4; + $beta = 3; + $t = 2; + self::assertEquals(\pow(1 - $t / $beta, -$alpha), GammaDistribution::getMgfRate($t, $alpha, $beta)); + } + + public function testModeScale() : void + { + self::assertEquals((3 - 1) * 2, GammaDistribution::getModeScale(3, 2)); + } + + public function testModeRate() : void + { + self::assertEquals((3 - 1) / 2, GammaDistribution::getModeRate(3, 2)); + } } diff --git a/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php b/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php index 3e8b93b37..0fb0f2aa6 100644 --- a/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/GeometricDistributionTest.php @@ -83,4 +83,14 @@ class GeometricDistributionTest extends \PHPUnit\Framework\TestCase self::assertEquals(\ceil(-1 / \log(1 - $p, 2)), GeometricDistribution::getMedian($p)); } + + public function testMgf() : void + { + $p = 0.3; + $t1 = 2; + $t2 = -\log(1 - $p) * 0.8; + + self::assertEquals($p / (1 - (1 - $p) * \exp($t1)), GeometricDistribution::getMgf($p, $t1)); + self::assertEquals($p * \exp($t2) / (1 - (1 - $p) * \exp($t2)), GeometricDistribution::getMgf($p, $t2)); + } } diff --git a/tests/Math/Stochastic/Distribution/HypergeometricDistributionTest.php b/tests/Math/Stochastic/Distribution/HypergeometricDistributionTest.php index 325e97c50..ac7c7dced 100644 --- a/tests/Math/Stochastic/Distribution/HypergeometricDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/HypergeometricDistributionTest.php @@ -45,4 +45,23 @@ class HypergeometricDistributionTest extends \PHPUnit\Framework\TestCase { self::assertEqualsWithDelta(-0.247277, HypergeometricDistribution::getExKurtosis(15, 20, 12), 0.001); } + + public function testMode() : void + { + $N = 8; + $n = 4; + $K = 5; + + self::assertEquals(3, HypergeometricDistribution::getMode($K, $N, $n)); + } + + public function testPmf() : void + { + self::assertEqualsWithDelta(0.146284, HypergeometricDistribution::getPmf(7, 20, 5, 10), 0.001); + } + + public function testCdf() : void + { + self::assertEqualsWithDelta(0.97136, HypergeometricDistribution::getCdf(7, 20, 5, 10), 0.001); + } } diff --git a/tests/Math/Stochastic/Distribution/LogDistributionTest.php b/tests/Math/Stochastic/Distribution/LogDistributionTest.php index 4604008f7..d98d90443 100644 --- a/tests/Math/Stochastic/Distribution/LogDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/LogDistributionTest.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace phpOMS\tests\Math\Stochastic\Distribution; +use phpOMS\Math\Stochastic\Distribution\LogDistribution; + /** * @internal */ @@ -21,31 +23,66 @@ class LogDistributionTest extends \PHPUnit\Framework\TestCase { public function testPmf() : void { - self::markTestIncomplete(); + $p = 0.3; + $k = 4; + + self::assertEquals( + -1 / \log(1 - $p) * $p ** $k / $k, + LogDistribution::getPmf($p, $k) + ); + } + + public function testCdf() : void + { + $p = 6 / 9; + $k = 2; + + self::assertEqualsWithDelta( + 0.8091, + LogDistribution::getCdf($p, $k), 0.001 + ); } public function testMean() : void { - self::markTestIncomplete(); + $p = 0.3; + + self::assertEquals(-1 / \log(1 - $p) * $p / (1 - $p), LogDistribution::getMean($p)); } public function testMode() : void { - self::markTestIncomplete(); + self::assertEquals(1, LogDistribution::getMode()); } public function testVariance() : void { - self::markTestIncomplete(); + $p = 0.3; + + self::assertEquals( + -($p ** 2 + $p * \log(1 - $p)) / ((1 - $p) ** 2 * (\log(1 - $p)) ** 2), + LogDistribution::getVariance($p) + ); } public function testStandardDeviation() : void { - self::markTestIncomplete(); + $p = 0.3; + + self::assertEquals( + \sqrt(-($p ** 2 + $p * \log(1 - $p)) / ((1 - $p) ** 2 * (\log(1 - $p)) ** 2)), + LogDistribution::getStandardDeviation($p) + ); } public function testMgf() : void { - self::markTestIncomplete(); + $p = 0.3; + $t = 0.8; + + self::assertEquals( + \log(1 - $p * \exp($t)) / \log(1 - $p), + LogDistribution::getMgf($p, $t) + ); } } diff --git a/tests/Math/Stochastic/Distribution/LogNormalDistributionTest.php b/tests/Math/Stochastic/Distribution/LogNormalDistributionTest.php index 82d5b4790..978bc3520 100644 --- a/tests/Math/Stochastic/Distribution/LogNormalDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/LogNormalDistributionTest.php @@ -26,6 +26,11 @@ class LogNormalDistributionTest extends \PHPUnit\Framework\TestCase self::assertEqualsWithDelta(0.060069054, LogNormalDistribution::getPdf(3, 2, 2), 0.001); } + public function testCdf() : void + { + self::assertEqualsWithDelta(0.32610510, LogNormalDistribution::getCdf(3, 2, 2), 0.001); + } + public function testMean() : void { self::assertEqualsWithDelta(\exp(13 / 2), LogNormalDistribution::getMean(2, 3), 0.001); @@ -33,22 +38,67 @@ class LogNormalDistributionTest extends \PHPUnit\Framework\TestCase public function testVariance() : void { - self::assertEqualsWithDelta((\exp(9) - 1) * \exp(13), LogNormalDistribution::getVariance(2, 3), 0.001); + self::assertEqualsWithDelta( + (\exp(9) - 1) * \exp(13), + LogNormalDistribution::getVariance(2, 3), 0.001 + ); } public function testStandardDeviation() : void { - self::assertEqualsWithDelta(\exp(13 / 2) * \sqrt(\exp(9) - 1), LogNormalDistribution::getStandardDeviation(2, 3), 0.001); - self::assertEqualsWithDelta(\sqrt((\exp(9) - 1) * \exp(13)), LogNormalDistribution::getStandardDeviation(2, 3), 0.001); + self::assertEqualsWithDelta( + \exp(13 / 2) * \sqrt(\exp(9) - 1), + LogNormalDistribution::getStandardDeviation(2, 3), 0.001 + ); + + self::assertEqualsWithDelta( + \sqrt((\exp(9) - 1) * \exp(13)), + LogNormalDistribution::getStandardDeviation(2, 3), 0.001 + ); } public function testSkewness() : void { - self::assertEqualsWithDelta(\sqrt(\exp(9) - 1) * (\exp(9) + 2), LogNormalDistribution::getSkewness(3), 0.001); + self::assertEqualsWithDelta( + \sqrt(\exp(9) - 1) * (\exp(9) + 2), + LogNormalDistribution::getSkewness(3), 0.001 + ); } public function testExKurtosis() : void { - self::assertEqualsWithDelta(\exp(16) + 2 * \exp(12) + 3 * \exp(8) - 6, LogNormalDistribution::getExKurtosis(2), 0.001); + self::assertEqualsWithDelta( + \exp(16) + 2 * \exp(12) + 3 * \exp(8) - 6, + LogNormalDistribution::getExKurtosis(2), 0.001 + ); + } + + public function testMedian() : void + { + self::assertEquals(\exp(3), LogNormalDistribution::getMedian(3)); + } + + public function testMode() : void + { + self::assertEquals(\exp(3 - 4 ** 2), LogNormalDistribution::getMode(3, 4)); + } + + public function testEntropy() : void + { + self::assertEqualsWithDelta( + \log(4 * \exp(3 + 0.5) * \sqrt(2 * \M_PI), 2), + LogNormalDistribution::getEntropy(3, 4), 0.001 + ); + } + + public function testFisherInformation() : void + { + self::assertEquals( + [ + [1 / 3 ** 2, 0], + [0, 1 / (2 * 3 ** 4)], + ], + LogNormalDistribution::getFisherInformation(3) + ); } } diff --git a/tests/Math/Stochastic/Distribution/LogisticDistributionTest.php b/tests/Math/Stochastic/Distribution/LogisticDistributionTest.php index 287737811..9e2b6d2bf 100644 --- a/tests/Math/Stochastic/Distribution/LogisticDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/LogisticDistributionTest.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace phpOMS\tests\Math\Stochastic\Distribution; +use phpOMS\Math\Stochastic\Distribution\LogisticDistribution; + /** * @internal */ @@ -21,51 +23,74 @@ class LogisticDistributionTest extends \PHPUnit\Framework\TestCase { public function testPdf() : void { - self::markTestIncomplete(); + $x = 3; + $mu = 5; + $s = 2; + + self::assertEquals( + \exp(-($x - $mu) / $s) / ($s * (1 + \exp(-($x - $mu) / $s)) ** 2), + LogisticDistribution::getPdf($x, $mu, $s) + ); } public function testCdf() : void { - self::markTestIncomplete(); + $x = 3; + $mu = 5; + $s = 2; + + self::assertEquals( + 1 / (1 + \exp(-($x - $mu) / $s)), + LogisticDistribution::getCdf($x, $mu, $s) + ); } public function testMode() : void { - self::markTestIncomplete(); + self::assertEquals(3, LogisticDistribution::getMode(3)); } public function testMean() : void { - self::markTestIncomplete(); + self::assertEquals(3, LogisticDistribution::getMean(3)); } public function testMedian() : void { - self::markTestIncomplete(); + self::assertEquals(3, LogisticDistribution::getMedian(3)); } public function testVariance() : void { - self::markTestIncomplete(); + $s = 3; + self::assertEquals( + $s ** 2 * \M_PI ** 2 / 3, + LogisticDistribution::getVariance($s) + ); } public function testStandardDeviation() : void { - self::markTestIncomplete(); + $s = 3; + self::assertEquals( + \sqrt($s ** 2 * \M_PI ** 2 / 3), + LogisticDistribution::getStandardDeviation($s) + ); } public function testSkewness() : void { - self::markTestIncomplete(); + self::assertEquals(0, LogisticDistribution::getSkewness()); } public function testExKurtosis() : void { - self::markTestIncomplete(); + self::assertEquals(6 / 5, LogisticDistribution::getExKurtosis()); } public function testEntropy() : void { - self::markTestIncomplete(); + $s = 3; + self::assertEquals(\log($s) + 2, LogisticDistribution::getEntropy($s)); } } diff --git a/tests/Math/Stochastic/Distribution/NormalDistributionTest.php b/tests/Math/Stochastic/Distribution/NormalDistributionTest.php index 47925c6a0..2a3b391f7 100644 --- a/tests/Math/Stochastic/Distribution/NormalDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/NormalDistributionTest.php @@ -93,4 +93,27 @@ class NormalDistributionTest extends \PHPUnit\Framework\TestCase { self::assertEqualsWithDelta(384.16, NormalDistribution::getSampleSizeFromInfinitePopulation(NormalDistribution::TABLE['0.95'], 0.05, 0.5), 0.01); } + + public function testMgf() : void + { + $t = 3; + $mu = 4; + $sigma = 5; + + self::assertEquals( + \exp($mu * $t + $sigma ** 2 * $t **2 / 2), + NormalDistribution::getMgf($t, $mu, $sigma) + ); + } + + public function testFisherInformation() : void + { + self::assertEquals( + [ + [1 / 3 ** 2, 0], + [0, 1 / (2 * 3 ** 4)], + ], + NormalDistribution::getFisherInformation(3) + ); + } } diff --git a/tests/Math/Stochastic/Distribution/ParetoDistributionTest.php b/tests/Math/Stochastic/Distribution/ParetoDistributionTest.php index a607fc5f8..dd613f5b0 100644 --- a/tests/Math/Stochastic/Distribution/ParetoDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/ParetoDistributionTest.php @@ -59,4 +59,33 @@ class ParetoDistributionTest extends \PHPUnit\Framework\TestCase self::assertEqualsWithDelta(3.810317377662722, ParetoDistribution::getSkewness(6, 5), 0.001); self::assertEquals(0.0, ParetoDistribution::getSkewness(3)); } + + public function testMedian() : void + { + self::assertEquals(3 * \pow(2, 1 / 4), ParetoDistribution::getMedian(3, 4)); + } + + public function testMode() : void + { + self::assertEquals(3, ParetoDistribution::getMode(3)); + } + + public function testEntropy() : void + { + self::assertEquals( + \log(3 / 4 * \exp(1 + 1 / 4)), + ParetoDistribution::getEntropy(3, 4) + ); + } + + public function testFisherInformation() : void + { + self::assertEquals( + [ + [4 / (3 ** 2), -1 / 3], + [-1 / 3, 1 / (4 ** 2)], + ], + ParetoDistribution::getFisherInformation(3, 4) + ); + } } diff --git a/tests/Math/Stochastic/Distribution/TDistributionTest.php b/tests/Math/Stochastic/Distribution/TDistributionTest.php index feabaafd1..944d24e22 100644 --- a/tests/Math/Stochastic/Distribution/TDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/TDistributionTest.php @@ -58,4 +58,12 @@ class TDistributionTest extends \PHPUnit\Framework\TestCase { self::assertEquals(0, TDistribution::getSkewness()); } + + public function testCdf() : void + { + self::assertEqualsWithDelta(0.0, TDistribution::getCdf(1.25, 5, 0), 0.001); + self::assertEqualsWithDelta(0.86669, TDistribution::getCdf(1.25, 5, 1), 0.001); + self::assertEqualsWithDelta(0.78867, TDistribution::getCdf(1.0, 2, 1), 0.001); + self::assertEqualsWithDelta(0.4226, TDistribution::getCdf(1.0, 2, 2), 0.001); + } } diff --git a/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php b/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php index 3e208a1f0..7621eeda7 100644 --- a/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php +++ b/tests/Math/Stochastic/Distribution/UniformDistributionContinuousTest.php @@ -97,4 +97,13 @@ class UniformDistributionContinuousTest extends \PHPUnit\Framework\TestCase { self::assertEquals(-6 / 5, UniformDistributionContinuous::getExKurtosis()); } + + public function testMgf() : void + { + self::assertEquals(1, UniformDistributionContinuous::getMgf(0, 2, 3)); + self::assertEquals( + (\exp(2 * 4) - \exp(2 *3)) / (2 * (4 - 3)), + UniformDistributionContinuous::getMgf(2, 3, 4) + ); + } } diff --git a/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php b/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php index b1d2df219..ac4fbe4da 100644 --- a/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php +++ b/tests/Math/Stochastic/Distribution/UniformDistributionDiscreteTest.php @@ -84,6 +84,14 @@ class UniformDistributionDiscreteTest extends \PHPUnit\Framework\TestCase self::assertEquals(-(6 * ($n ** 2 + 1)) / (5 * ($n ** 2 - 1)), UniformDistributionDiscrete::getExKurtosis($a, $b)); } + public function testMgf() : void + { + self::assertEquals( + (\exp(3 * 2) - \exp((4 + 1) * 2)) / ((4 - 3 + 1) * (1 - \exp(2))), + UniformDistributionDiscrete::getMgf(2, 3, 4) + ); + } + public function testCdfExceptionUpper() : void { $this->expectException(\OutOfBoundsException::class); diff --git a/tests/Math/Stochastic/Distribution/WeibullDistributionTest.php b/tests/Math/Stochastic/Distribution/WeibullDistributionTest.php index 7b4207dce..31720850c 100644 --- a/tests/Math/Stochastic/Distribution/WeibullDistributionTest.php +++ b/tests/Math/Stochastic/Distribution/WeibullDistributionTest.php @@ -32,4 +32,39 @@ class WeibullDistributionTest extends \PHPUnit\Framework\TestCase self::assertEqualsWithDelta(0.430217175, WeibullDistribution::getCdf(3, 4, 2), 0.001); self::assertEqualsWithDelta(0.0, WeibullDistribution::getCdf(-1, 4, 2), 0.001); } + + public function testMean() : void + { + self::assertEqualsWithDelta(3.54490771, WeibullDistribution::getMean(4, 2), 0.001); + } + + public function testMedian() : void + { + self::assertEqualsWithDelta(3.33021844, WeibullDistribution::getMedian(4, 2), 0.001); + } + + public function testMode() : void + { + self::assertEqualsWithDelta(2.82842712, WeibullDistribution::getMode(4, 2), 0.001); + } + + public function testVariance() : void + { + self::assertEqualsWithDelta(3.43362932, WeibullDistribution::getVariance(4, 2), 0.001); + } + + public function testStandardDeviation() : void + { + self::assertEqualsWithDelta(\sqrt(3.43362932), WeibullDistribution::getStandardDeviation(4, 2), 0.001); + } + + public function testEntropy() : void + { + self::assertEqualsWithDelta(1.981755, WeibullDistribution::getEntropy(4, 2), 0.001); + } + + public function testSkewness() : void + { + self::assertEqualsWithDelta(0.631110, WeibullDistribution::getSkewness(4, 2), 0.001); + } } diff --git a/tests/Math/Stochastic/Distribution/ZTestTest.php b/tests/Math/Stochastic/Distribution/ZTestTest.php index ebe79fa94..3532e29ed 100644 --- a/tests/Math/Stochastic/Distribution/ZTestTest.php +++ b/tests/Math/Stochastic/Distribution/ZTestTest.php @@ -14,12 +14,14 @@ declare(strict_types=1); namespace phpOMS\tests\Math\Stochastic\Distribution; -use phpOMS\Math\Stochastic\Distribution\ZTest; +use phpOMS\Math\Statistic\Average; +use phpOMS\Math\Statistic\MeasureOfDispersion; +use phpOMS\Math\Stochastic\Distribution\ZTesting; /** * @internal */ -class ZTestTest extends \PHPUnit\Framework\TestCase +class ZTestingTest extends \PHPUnit\Framework\TestCase { // http://sphweb.bumc.bu.edu/otlt/MPH-Modules/BS/BS704_HypothesisTesting-ChiSquare/BS704_HypothesisTesting-ChiSquare_print.html public function testHypothesisFalse() : void @@ -29,14 +31,22 @@ class ZTestTest extends \PHPUnit\Framework\TestCase $expected = 0.75; $total = 125; // total count of observed sample size - self::assertFalse(ZTest::testHypothesis($observed, $expected, $total, $a)); + self::assertFalse(ZTesting::testHypothesis($observed, $expected, $total, $a)); } // https://support.microsoft.com/en-us/office/z-test-function-d633d5a3-2031-4614-a016-92180ad82bee?ui=en-us&rs=en-us&ad=us public function testZTest() : void { - //self::assertEqualsWithDelta(0.090574, ZTest::zTest(4, [3, 6, 7, 8, 6, 5, 4, 2, 1, 9]), 0.001); - self::markTestIncomplete(); - self::assertTrue(true); + self::assertEqualsWithDelta(0.090574, ZTesting::zTest(4, [3, 6, 7, 8, 6, 5, 4, 2, 1, 9]), 0.001); + } + + public function testZTestValues() : void + { + $data = [3, 6, 7, 8, 6, 5, 4, 2, 1, 9]; + $mean = Average::arithmeticMean($data); + $size = \count($data); + $sig = MeasureOfDispersion::standardDeviationSample($data); + + self::assertEqualsWithDelta(0.090574, ZTesting::zTestValues(4, $mean, $size, $sig), 0.001); } }