From 698145645a4ac05a7e19435fd96f94895db87033 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 21 Nov 2021 22:12:41 -0800 Subject: [PATCH 01/66] e Add PHP 8.1 to Github Actions CI builds. --- .github/workflows/test_develop_and_master.yml | 2 +- .github/workflows/test_other_branches.yml | 2 +- .github/workflows/test_pull_request.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index dad0fdf9b..afcb1af21 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1] steps: - name: Set up PHP diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index fb67ca2da..31b8e4fcc 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1'] steps: - name: Set up PHP diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index ef84a9aa3..dac91cfbf 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1'] steps: - name: Set up PHP From f45dd51eafb6209dc8d29f34b2cfe818f57672ce Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 21 Nov 2021 22:17:31 -0800 Subject: [PATCH 02/66] e Add PHP 8.1 to Github Actions CI builds. --- .github/workflows/test_develop_and_master.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index afcb1af21..0f5453152 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1] + php: ['7.2', '7.3', '7.4', '8.0', '8.1'] steps: - name: Set up PHP From 0739d69fdc6d4fc194a78f5cea61e80475bf6e74 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 30 Nov 2021 19:55:21 -0800 Subject: [PATCH 03/66] R Make truncatedMean behavior at 50 percent trim consistent. Throw exception if trim over 50 percent. --- README.md | 2 +- src/Statistics/Average.php | 16 ++++--- tests/Statistics/AverageTest.php | 71 +++++++++++++++++++++++++------- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index b68bd7b1f..c5ab9e9d7 100644 --- a/README.md +++ b/README.md @@ -2022,7 +2022,7 @@ $interquartile_mean = Average::iqm($numbers); // same as interqua $cubic_mean = Average::cubicMean($numbers); // Truncated mean (trimmed mean) -$trim_percent = 25; +$trim_percent = 25; // 25 percent of observations trimmed from each end of distribution $truncated_mean = Average::truncatedMean($numbers, $trim_percent); // Generalized mean (power mean) diff --git a/src/Statistics/Average.php b/src/Statistics/Average.php index d822df6af..02f0430a2 100644 --- a/src/Statistics/Average.php +++ b/src/Statistics/Average.php @@ -480,21 +480,21 @@ public static function cubicMean(array $numbers): float * This number of points to be discarded is given as a percentage of the total number of points. * https://en.wikipedia.org/wiki/Truncated_mean * - * Trim count = floor( (trim percent / 100) * sample size ) + * Trim count = floor((trim percent / 100) * sample size) * * For example: [8, 3, 7, 1, 3, 9] with a trim of 20% * First sort the list: [1, 3, 3, 7, 8, 9] * Sample size = 6 - * Then determine trim count: floot(20/100 * 6 ) = 1 + * Then determine trim count: floor(20/100 * 6) = 1 * Trim the list by removing 1 from each end: [3, 3, 7, 8] * Finally, find the mean: 5.2 * * @param float[] $numbers - * @param int $trim_percent Percent between 0-99 + * @param int $trim_percent Percent between 0-50 indicating percent of observations trimmed from each end of distribution * * @return float * - * @throws Exception\OutOfBoundsException if trim percent is not between 0 and 99 + * @throws Exception\OutOfBoundsException if trim percent is not between 0 and 50 * @throws Exception\BadDataException if the input array of numbers is empty */ public static function truncatedMean(array $numbers, int $trim_percent): float @@ -502,14 +502,18 @@ public static function truncatedMean(array $numbers, int $trim_percent): float if (empty($numbers)) { throw new Exception\BadDataException('Cannot find the truncated mean of an empty list of numbers'); } - if ($trim_percent < 0 || $trim_percent > 99) { - throw new Exception\OutOfBoundsException('Trim percent must be between 0 and 99.'); + if ($trim_percent < 0 || $trim_percent > 50) { + throw new Exception\OutOfBoundsException('Trim percent must be between 0 and 50.'); } $n = \count($numbers); $trim_count = \floor($n * ($trim_percent / 100)); \sort($numbers); + if ($trim_percent == 50) { + return self::median($numbers); + } + for ($i = 1; $i <= $trim_count; $i++) { \array_shift($numbers); \array_pop($numbers); diff --git a/tests/Statistics/AverageTest.php b/tests/Statistics/AverageTest.php index fcc9ed2a7..442fbd6b6 100644 --- a/tests/Statistics/AverageTest.php +++ b/tests/Statistics/AverageTest.php @@ -593,29 +593,61 @@ public function dataProviderForTrimean(): array * @test truncatedMean * @dataProvider dataProviderForTruncatedMean * @param array $numbers - * @param float $trim_percent + * @param int $trim_percent * @param float $expectedMean * @throws \Exception */ - public function testTruncatedMean(array $numbers, float $trim_percent, float $expectedMean) + public function testTruncatedMean(array $numbers, int $trim_percent, float $expectedMean) { // When $mean = Average::truncatedMean($numbers, $trim_percent); // Then - $this->assertEqualsWithDelta($expectedMean, $mean, 0.01); + $this->assertEqualsWithDelta($expectedMean, $mean, 0.00001); } /** + * Test data generated with R: mean(nums, trim=0.05) * @return array [numbers, trim_percent, mean] */ public function dataProviderForTruncatedMean(): array { return [ - [ [ 92, 19, 101, 58, 1053, 91, 26, 78, 10, 13, -40, 101, 86, 85, 15, 89, 89, 28, -5, 41 ], 5, 56.5 ], - [ [ 4,3,6,8,4,2,4,8,12,53,23,12,21 ], 5, 12.31 ], - [ [ 8, 3, 7, 1, 3, 9 ], 20, 5.25 ], - [ [ 8, 3, 7, 1, 3, 9 ], 0, 5.16666667 ], + [[92, 19, 101, 58, 1053, 91, 26, 78, 10, 13, -40, 101, 86, 85, 15, 89, 89, 28, -5, 41], 0, 101.5], + [[92, 19, 101, 58, 1053, 91, 26, 78, 10, 13, -40, 101, 86, 85, 15, 89, 89, 28, -5, 41], 5, 56.5], + [[92, 19, 101, 58, 1053, 91, 26, 78, 10, 13, -40, 101, 86, 85, 15, 89, 89, 28, -5, 41], 15, 57.85714], + [[92, 19, 101, 58, 1053, 91, 26, 78, 10, 13, -40, 101, 86, 85, 15, 89, 89, 28, -5, 41], 40, 65.5], + [[92, 19, 101, 58, 1053, 91, 26, 78, 10, 13, -40, 101, 86, 85, 15, 89, 89, 28, -5, 41], 50, 68], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 0, 12.30769], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 5, 12.30769], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 10, 9.545455], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 20, 8.777778], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 25, 7.714286], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 30, 7.714286], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 35, 7.6], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 40, 7.333333], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 45, 7.333333], + [[4,3,6,8,4,2,4,8,12,53,23,12,21], 50, 8], + [[8, 3, 7, 1, 3, 9], 0, 5.16666667], + [[8, 3, 7, 1, 3, 9], 20, 5.25], + [[8, 3, 7, 1, 3, 9], 50, 5], + [[6,4,2,4,3,7,6,33,77,22,3,5,6,5,0,2,3,4,6], 25, 4.727273], + [[6,4,2,4,3,7,6,33,77,22,3,5,6,5,0,2,3,4,6], 50, 5], + [[2, 3, 4, 5, 1, 9, 6, 7, 10, 8], 1, 5.5], + [[2, 3, 4, 5, 1, 9, 6, 7, 10, 8], 10, 5.5], + [[2, 3, 4, 5, 1, 9, 6, 7, 10, 8], 40, 5.5], + [[2, 3, 4, 5, 1, 9, 6, 7, 10, 8], 50, 5.5], + [[3, 5, 6, 7, 6, 5, 6, 4, 2, 1, 0, 9, 8, 2, 4, 16, 4, 3, 3, 2, 12], 1, 5.142857], + [[3, 5, 6, 7, 6, 5, 6, 4, 2, 1, 0, 9, 8, 2, 4, 16, 4, 3, 3, 2, 12], 1, 5.142857], + [[3, 5, 6, 7, 6, 5, 6, 4, 2, 1, 0, 9, 8, 2, 4, 16, 4, 3, 3, 2, 12], 10, 4.647059], + [[3, 5, 6, 7, 6, 5, 6, 4, 2, 1, 0, 9, 8, 2, 4, 16, 4, 3, 3, 2, 12], 20, 4.461538], + [[3, 5, 6, 7, 6, 5, 6, 4, 2, 1, 0, 9, 8, 2, 4, 16, 4, 3, 3, 2, 12], 25, 4.454545], + [[3, 5, 6, 7, 6, 5, 6, 4, 2, 1, 0, 9, 8, 2, 4, 16, 4, 3, 3, 2, 12], 40, 4.4], + [[3, 5, 6, 7, 6, 5, 6, 4, 2, 1, 0, 9, 8, 2, 4, 16, 4, 3, 3, 2, 12], 50, 4], + [[1, 2, 3], 50, 2], + [[1, 2, 3, 4], 50, 2.5], + [[1, 2, 3, 4, 5], 50, 3], + [[1, 2, 3, 4, 5, 6], 50, 3.5], ]; } @@ -644,7 +676,7 @@ public function testTruncatedMeanExceptionLessThanZeroTrimPercent() { // Given $numbers = [1, 2, 3]; - $trim_percent = -4; + $trim_percent = -1; // Then $this->expectException(Exception\OutOfBoundsException::class); @@ -654,20 +686,31 @@ public function testTruncatedMeanExceptionLessThanZeroTrimPercent() } /** - * @test truncatedMean trim percent greater than 99 - * @throws \Exception + * @test truncatedMean trim percent greater than 50 + * @dataProvider dataProviderForTruncatedMeanGreaterThan50TrimPercent + * @param int $trim_percent */ - public function testTruncatedMeanExceptionGreaterThan99TrimPercent() + public function testTruncatedMeanExceptionGreaterThan50TrimPercent(int $trim_percent) { // Given - $numbers = [1, 2, 3]; - $trim_percent = 100; + $numbers = [1, 2, 3, 6, 5, 4, 7]; // Then $this->expectException(Exception\OutOfBoundsException::class); // When - Average::truncatedMean([1, 2, 3], 100); + Average::truncatedMean([1, 2, 3], $trim_percent); + } + + public function dataProviderForTruncatedMeanGreaterThan50TrimPercent(): array + { + return [ + [51], + [75], + [99], + [100], + [101], + ]; } /** From 0d545da60e5de699040b7c4ad183ff467d30d2e4 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 30 Nov 2021 19:58:09 -0800 Subject: [PATCH 04/66] d Update CHANGELOG for v2.6.0 changes. --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af511772c..ff5e475d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # MathPHP Change Log +## 2.6.0 - TBD + +### Improvements +* `Average::truncatedMean` behavior at 50% trim made consistent + +### Backwards Incompatible Changes +# `Average::truncatedMean` throws exception if trim percent greater than 50% rather than error or unpredictable results. + ## v2.5.0 - 2021-11-21 ### New Features From ee7aea7b3eb717b1335cfe06fa79ebbc84586401 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 9 Apr 2022 09:55:45 -0700 Subject: [PATCH 05/66] Update CHANGELOG. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff5e475d4..238f6d10b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # MathPHP Change Log -## 2.6.0 - TBD +## v2.6.0 - 2022-04-TBD ### Improvements * `Average::truncatedMean` behavior at 50% trim made consistent From f4c407daca8e45ac740ef24f261d77092b3cc9f7 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 9 Apr 2022 11:32:21 -0700 Subject: [PATCH 06/66] Minor linting improvements. --- src/Probability/Distribution/Discrete/Pascal.php | 1 - tests/Functions/Map/MultiTest.php | 1 - .../NumericalIntegration/NumericalIntegrationTest.php | 1 - tests/Probability/Distribution/Table/StandardNormalTableTest.php | 1 - 4 files changed, 4 deletions(-) diff --git a/src/Probability/Distribution/Discrete/Pascal.php b/src/Probability/Distribution/Discrete/Pascal.php index 233374183..78f00bfcc 100644 --- a/src/Probability/Distribution/Discrete/Pascal.php +++ b/src/Probability/Distribution/Discrete/Pascal.php @@ -8,5 +8,4 @@ */ class Pascal extends NegativeBinomial { - } diff --git a/tests/Functions/Map/MultiTest.php b/tests/Functions/Map/MultiTest.php index 1a2b8aa62..169c77055 100644 --- a/tests/Functions/Map/MultiTest.php +++ b/tests/Functions/Map/MultiTest.php @@ -7,7 +7,6 @@ class MultiTest extends \PHPUnit\Framework\TestCase { - /** * @test add two arrays * @dataProvider dataProviderForAddTwoArrays diff --git a/tests/NumericalAnalysis/NumericalIntegration/NumericalIntegrationTest.php b/tests/NumericalAnalysis/NumericalIntegration/NumericalIntegrationTest.php index 20ae58898..858e00e1e 100644 --- a/tests/NumericalAnalysis/NumericalIntegration/NumericalIntegrationTest.php +++ b/tests/NumericalAnalysis/NumericalIntegration/NumericalIntegrationTest.php @@ -7,7 +7,6 @@ class NumericalIntegrationTest extends \PHPUnit\Framework\TestCase { - /** * @test The input $source is neither a callback or a set of arrays * @throws Exception\BadDataException diff --git a/tests/Probability/Distribution/Table/StandardNormalTableTest.php b/tests/Probability/Distribution/Table/StandardNormalTableTest.php index 998611427..21cf8ebb3 100644 --- a/tests/Probability/Distribution/Table/StandardNormalTableTest.php +++ b/tests/Probability/Distribution/Table/StandardNormalTableTest.php @@ -7,7 +7,6 @@ class StandardNormalTableTest extends \PHPUnit\Framework\TestCase { - /** * @test z score * @dataProvider dataProviderForZScores From 5ecf4b7aabbd4834e0053d97067cc81b04272835 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 9 Apr 2022 11:52:35 -0700 Subject: [PATCH 07/66] Unit test updates. --- tests/Expression/PolynomialTest.php | 2 +- tests/Statistics/Multivariate/PLS/MtCarsPLS1ScaleFalseTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Expression/PolynomialTest.php b/tests/Expression/PolynomialTest.php index 076c1ef96..d4d8133e5 100644 --- a/tests/Expression/PolynomialTest.php +++ b/tests/Expression/PolynomialTest.php @@ -1270,7 +1270,7 @@ public function testCompanionMatrix(array $poly, array $expected_matrix) $poly = new Polynomial($poly); $companion = $poly->companionMatrix(); - $this->assertEquals($expected_matrix, $companion->getMatrix(), '', .0000001); + $this->assertEqualsWithDelta($expected_matrix, $companion->getMatrix(), .0000001); } /** diff --git a/tests/Statistics/Multivariate/PLS/MtCarsPLS1ScaleFalseTest.php b/tests/Statistics/Multivariate/PLS/MtCarsPLS1ScaleFalseTest.php index 5cde89374..9e0278321 100644 --- a/tests/Statistics/Multivariate/PLS/MtCarsPLS1ScaleFalseTest.php +++ b/tests/Statistics/Multivariate/PLS/MtCarsPLS1ScaleFalseTest.php @@ -82,6 +82,6 @@ public function testB() $B = self::$pls->getCoefficients()->getMatrix(); // Then - $this->assertEquals($expected, $B, '', .00001); + $this->assertEqualsWithDelta($expected, $B, .00001); } } From 4e529aa2eddfd6e5e6eb0ca83933abed7bf6cd06 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 9 Apr 2022 21:53:27 -0700 Subject: [PATCH 08/66] R Minor PHP 8.1 compatibility improvements. --- src/NumberTheory/Integer.php | 2 +- src/Statistics/Distribution.php | 2 +- tests/Arithmetic/ArithmeticAxiomsTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NumberTheory/Integer.php b/src/NumberTheory/Integer.php index a1c020c31..8fb35ee26 100644 --- a/src/NumberTheory/Integer.php +++ b/src/NumberTheory/Integer.php @@ -142,7 +142,7 @@ public static function totient(int $n, int $k = 1): int $J *= 1 - 1 / $prime ** $k; } - return $J; + return (int) $J; } /** diff --git a/src/Statistics/Distribution.php b/src/Statistics/Distribution.php index ff9df45ad..792f8d72a 100644 --- a/src/Statistics/Distribution.php +++ b/src/Statistics/Distribution.php @@ -270,7 +270,7 @@ public static function stemAndLeafPlot(array $values, bool $print = false): arra \sort($values); $plot = array(); foreach ($values as $value) { - $stem = $value / 10; + $stem = intdiv($value, 10); $leaf = $value % 10; if (!isset($plot[$stem])) { $plot[$stem] = array(); diff --git a/tests/Arithmetic/ArithmeticAxiomsTest.php b/tests/Arithmetic/ArithmeticAxiomsTest.php index 143de18cc..a5572f277 100644 --- a/tests/Arithmetic/ArithmeticAxiomsTest.php +++ b/tests/Arithmetic/ArithmeticAxiomsTest.php @@ -116,7 +116,7 @@ public function dataProviderDigitalRootArithmetic(): array [12345, 67890], [405, 3], [0, 34434], - [398792873, 20598729038], + [398792873, 2059872903], ]; } From 73ec2b66411f76d6c523d33598b0dea512e32ed7 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 9 Apr 2022 22:05:17 -0700 Subject: [PATCH 09/66] R Minor changes for PHP 8.1 compatibility. --- src/LinearAlgebra/Matrix.php | 7 ++++--- src/LinearAlgebra/Vector.php | 7 +++++-- src/SetTheory/Set.php | 6 ++++-- tests/Util/ArrayIteratorFixture.php | 5 +++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/LinearAlgebra/Matrix.php b/src/LinearAlgebra/Matrix.php index 054651007..4232e86fb 100644 --- a/src/LinearAlgebra/Matrix.php +++ b/src/LinearAlgebra/Matrix.php @@ -955,6 +955,7 @@ public function offsetExists($i): bool * @param mixed $i * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($i) { return $this->A[$i]; @@ -965,7 +966,7 @@ public function offsetGet($i) * @param mixed $value * @throws Exception\MatrixException */ - public function offsetSet($i, $value) + public function offsetSet($i, $value): void { throw new Exception\MatrixException('Matrix class does not allow setting values'); } @@ -974,7 +975,7 @@ public function offsetSet($i, $value) * @param mixed $i * @throws Exception\MatrixException */ - public function offsetUnset($i) + public function offsetUnset($i): void { throw new Exception\MatrixException('Matrix class does not allow unsetting values'); } @@ -985,7 +986,7 @@ public function offsetUnset($i) /** * @return array */ - public function jsonSerialize() + public function jsonSerialize(): array { return $this->A; } diff --git a/src/LinearAlgebra/Vector.php b/src/LinearAlgebra/Vector.php index 752736a95..bca4da514 100644 --- a/src/LinearAlgebra/Vector.php +++ b/src/LinearAlgebra/Vector.php @@ -759,6 +759,7 @@ public function offsetExists($i): bool * @param mixed $i * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($i) { return $this->A[$i]; @@ -769,7 +770,7 @@ public function offsetGet($i) * @param mixed $value * @throws Exception\VectorException */ - public function offsetSet($i, $value) + public function offsetSet($i, $value): void { throw new Exception\VectorException('Vector class does not allow setting values'); } @@ -778,7 +779,7 @@ public function offsetSet($i, $value) * @param mixed $i * @throws Exception\VectorException */ - public function offsetUnset($i) + public function offsetUnset($i): void { throw new Exception\VectorException('Vector class does not allow unsetting values'); } @@ -804,11 +805,13 @@ public function rewind(): void $this->i = 0; } + #[\ReturnTypeWillChange] public function current() { return $this->A[$this->i]; } + #[\ReturnTypeWillChange] public function key() { return $this->i; diff --git a/src/SetTheory/Set.php b/src/SetTheory/Set.php index d5fc231ee..fcb7720b4 100644 --- a/src/SetTheory/Set.php +++ b/src/SetTheory/Set.php @@ -649,7 +649,7 @@ public function count(): int /** * Rewind (Iterator interface) */ - public function rewind() + public function rewind(): void { $this->iterator_keys = \array_keys($this->A); $this->iterator_position = \array_shift($this->iterator_keys); @@ -668,6 +668,7 @@ public function valid(): bool /** * Current (Iterator interface) */ + #[\ReturnTypeWillChange] public function current() { return $this->A[$this->iterator_position]; @@ -676,6 +677,7 @@ public function current() /** * Key (Iterator interface) */ + #[\ReturnTypeWillChange] public function key() { return $this->iterator_position; @@ -684,7 +686,7 @@ public function key() /** * Next (Iterator interface) */ - public function next() + public function next(): void { $this->iterator_position = \array_shift($this->iterator_keys); } diff --git a/tests/Util/ArrayIteratorFixture.php b/tests/Util/ArrayIteratorFixture.php index ada2abed4..f4b0343a0 100644 --- a/tests/Util/ArrayIteratorFixture.php +++ b/tests/Util/ArrayIteratorFixture.php @@ -16,7 +16,7 @@ public function __construct(array $values) $this->i = 0; } - public function rewind() + public function rewind(): void { $this->i = 0; } @@ -24,6 +24,7 @@ public function rewind() /** * @return mixed */ + #[\ReturnTypeWillChange] public function current() { return $this->values[$this->i]; @@ -37,7 +38,7 @@ public function key(): int return $this->i; } - public function next() + public function next(): void { ++$this->i; } From 85d7d7fe205a6df2b20f956720e25341f3b1462a Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 9 Apr 2022 22:15:37 -0700 Subject: [PATCH 10/66] d Update CHANGELOG. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 238f6d10b..6245f4480 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # MathPHP Change Log -## v2.6.0 - 2022-04-TBD +## v2.6.0 - 2022-04-10 ### Improvements * `Average::truncatedMean` behavior at 50% trim made consistent +* PHP 8.1 compatibility improvements ### Backwards Incompatible Changes # `Average::truncatedMean` throws exception if trim percent greater than 50% rather than error or unpredictable results. From cc8dc1698f03d9f331d8c9309565ff70742c0a39 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 17 Apr 2022 15:12:38 -0700 Subject: [PATCH 11/66] t Add additional quantile unit tests and update method description. --- src/Statistics/Descriptive.php | 3 ++- tests/Statistics/DescriptiveTest.php | 26 +++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Statistics/Descriptive.php b/src/Statistics/Descriptive.php index 423053110..35884f6a6 100644 --- a/src/Statistics/Descriptive.php +++ b/src/Statistics/Descriptive.php @@ -381,6 +381,7 @@ public static function quartiles(array $numbers, string $method = 'exclusive'): * * This rule is employed by the TI-83 calculator boxplot and "1-Var Stats" functions. * This is the most basic method that is commonly taught in math textbooks. + * It is "method 1" from Wikipedia. * * @param float[] $numbers * @@ -451,7 +452,7 @@ public static function quartilesExclusive(array $numbers): array * The upper quartile value is the median of the upper half of the data. * * The values found by this method are also known as "Tukey's hinges". - * This is the method that the programming language R uses by default. + * This is the "method 2" from Wikipedia. * * @param float[] $numbers * diff --git a/tests/Statistics/DescriptiveTest.php b/tests/Statistics/DescriptiveTest.php index 52d2e1553..bb7a42073 100644 --- a/tests/Statistics/DescriptiveTest.php +++ b/tests/Statistics/DescriptiveTest.php @@ -594,6 +594,10 @@ public function dataProviderForQuartilesExclusive(): array [ 7, 15, 36, 39, 40, 41 ], [ '0%' => 7, 'Q1' => 15, 'Q2' => 37.5, 'Q3' => 40, '100%' => 41, 'IQR' => 25 ], ], + [ + [ 41, 15, 39, 36, 40, 7 ], + [ '0%' => 7, 'Q1' => 15, 'Q2' => 37.5, 'Q3' => 40, '100%' => 41, 'IQR' => 25 ], + ], [ [ 0, 2, 2, 4, 5, 6, 7, 7, 8, 9, 34, 34, 43, 54, 54, 76, 234 ], [ '0%' => 0, 'Q1' => 4.5, 'Q2' => 8, 'Q3' => 48.5, '100%' => 234, 'IQR' => 44 ], @@ -601,7 +605,15 @@ public function dataProviderForQuartilesExclusive(): array [ [0], [ '0%' => 0, 'Q1' => 0, 'Q2' => 0, 'Q3' => 0, '100%' => 0, 'IQR' => 0 ], - ] + ], + [ + [4, 6, 6, 7, 8, 12, 15, 17, 20, 21, 21, 23, 24, 27, 28], + [ '0%' => 4, 'Q1' => 7, 'Q2' => 17, 'Q3' => 23, '100%' => 28, 'IQR' => 16 ], + ], + [ + [0, 900, 1800, 2700, 3600, 4500], + [ '0%' => 0, 'Q1' => 900, 'Q2' => 2250, 'Q3' => 3600, '100%' => 4500, 'IQR' => 2700 ], + ], ]; } @@ -651,9 +663,21 @@ public function dataProviderForQuartilesInclusive(): array [ 7, 15, 36, 39, 40, 41 ], [ '0%' => 7, 'Q1' => 15, 'Q2' => 37.5, 'Q3' => 40, '100%' => 41, 'IQR' => 25 ], ], + [ + [ 41, 15, 39, 36, 40, 7 ], + [ '0%' => 7, 'Q1' => 15, 'Q2' => 37.5, 'Q3' => 40, '100%' => 41, 'IQR' => 25 ], + ], [ [ 0, 2, 2, 4, 5, 6, 7, 7, 8, 9, 34, 34, 43, 54, 54, 76, 234 ], [ '0%' => 0, 'Q1' => 5, 'Q2' => 8, 'Q3' => 43, '100%' => 234, 'IQR' => 38 ], + ], + [ + [4, 6, 6, 7, 8, 12, 15, 17, 20, 21, 21, 23, 24, 27, 28], + [ '0%' => 4, 'Q1' => 7.5, 'Q2' => 17, 'Q3' => 22, '100%' => 28, 'IQR' => 14.5 ], + ], + [ + [0, 900, 1800, 2700, 3600, 4500], + [ '0%' => 0, 'Q1' => 900, 'Q2' => 2250, 'Q3' => 3600, '100%' => 4500, 'IQR' => 2700 ], ] ]; } From 59571baf3850052e78e1db7eaa69c96365563db4 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 16:42:23 -0800 Subject: [PATCH 12/66] Add withDelta to tests with floating point results. --- tests/Expression/PolynomialTest.php | 2 +- tests/Functions/SpecialTest.php | 2 +- tests/Number/ComplexTest.php | 12 ++++++------ tests/Number/QuaternionTest.php | 8 ++++---- .../Interpolation/ClampedCubicSplineTest.php | 2 +- .../Interpolation/LagrangePolynomialTest.php | 2 +- .../Interpolation/NaturalCubicSplineTest.php | 2 +- .../Interpolation/NewtonPolynomialForwardTest.php | 2 +- .../Interpolation/RegularGridInterpolatorTest.php | 2 +- .../NumericalIntegration/BoolesRuleTest.php | 8 ++++---- .../SimpsonsThreeEighthsRuleTest.php | 8 ++++---- .../Distribution/Discrete/BernoulliTest.php | 2 +- tests/Sequence/NonIntegerTest.php | 2 +- tests/Statistics/ANOVATest.php | 8 ++++---- tests/Statistics/AverageTest.php | 4 ++-- tests/Trigonometry/TrigonometryTest.php | 2 +- 16 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/Expression/PolynomialTest.php b/tests/Expression/PolynomialTest.php index d4d8133e5..f55f463b3 100644 --- a/tests/Expression/PolynomialTest.php +++ b/tests/Expression/PolynomialTest.php @@ -1033,7 +1033,7 @@ public function testRoots(array $polynomialA, array $expected_roots) $roots = $polynomialA->roots(); // Then - $this->assertEquals($expected_roots, $roots); + $this->assertEqualsWithDelta($expected_roots, $roots, 0.00001); } /** diff --git a/tests/Functions/SpecialTest.php b/tests/Functions/SpecialTest.php index 82bbd0e54..41b9e3b6e 100644 --- a/tests/Functions/SpecialTest.php +++ b/tests/Functions/SpecialTest.php @@ -1252,7 +1252,7 @@ public function testSoftmax(array $𝐳, array $expected) // Then $this->assertEqualsWithDelta($expected, $σ⟮𝐳⟯ⱼ, 0.00001); - $this->assertEquals(1, \array_sum($σ⟮𝐳⟯ⱼ)); + $this->assertEquals(1, \array_sum($σ⟮𝐳⟯ⱼ), 0.00001); } public function dataProviderForSoftmax(): array diff --git a/tests/Number/ComplexTest.php b/tests/Number/ComplexTest.php index 08699c7cf..201027bae 100644 --- a/tests/Number/ComplexTest.php +++ b/tests/Number/ComplexTest.php @@ -677,8 +677,8 @@ public function testDivide(array $complex1, array $complex2, array $expected) $result = $c1->divide($c2); // Then - $this->assertEquals($expected['r'], $result->r); - $this->assertEquals($expected['i'], $result->i); + $this->assertEqualsWithDelta($expected['r'], $result->r, 0.00001); + $this->assertEqualsWithDelta($expected['i'], $result->i, 0.00001); } public function dataProviderForDivide(): array @@ -816,8 +816,8 @@ public function testPowNumber(array $complex1, $number, array $expected) $result = $c1->pow($number); // Then - $this->assertEquals($expected['r'], $result->r); - $this->assertEquals($expected['i'], $result->i); + $this->assertEqualsWithDelta($expected['r'], $result->r, 0.00001); + $this->assertEqualsWithDelta($expected['i'], $result->i, 0.00001); } /** @@ -971,8 +971,8 @@ public function testInverse($r, $i, $expected_r, $expected_i) $inverse = $c->inverse(); // Then - $this->assertEquals($expected_r, $inverse->r); - $this->assertEquals($expected_i, $inverse->i); + $this->assertEqualsWithDelta($expected_r, $inverse->r, 0.00001); + $this->assertEqualsWithDelta($expected_i, $inverse->i, 0.00001); } public function dataProviderForInverse(): array diff --git a/tests/Number/QuaternionTest.php b/tests/Number/QuaternionTest.php index c973b9028..e3ac57c4e 100644 --- a/tests/Number/QuaternionTest.php +++ b/tests/Number/QuaternionTest.php @@ -494,10 +494,10 @@ public function testDivide(array $complex1, array $complex2, array $expected) $result = $q1->divide($q2); // Then - $this->assertEquals($expected['r'], $result->r); - $this->assertEquals($expected['i'], $result->i); - $this->assertEquals($expected['j'], $result->j); - $this->assertEquals($expected['k'], $result->k); + $this->assertEqualsWithDelta($expected['r'], $result->r, 0.00001); + $this->assertEqualsWithDelta($expected['i'], $result->i, 0.00001); + $this->assertEqualsWithDelta($expected['j'], $result->j, 0.00001); + $this->assertEqualsWithDelta($expected['k'], $result->k, 0.00001); } public function dataProviderForDivide(): array diff --git a/tests/NumericalAnalysis/Interpolation/ClampedCubicSplineTest.php b/tests/NumericalAnalysis/Interpolation/ClampedCubicSplineTest.php index 105cbbc05..fb1fcefd7 100644 --- a/tests/NumericalAnalysis/Interpolation/ClampedCubicSplineTest.php +++ b/tests/NumericalAnalysis/Interpolation/ClampedCubicSplineTest.php @@ -27,7 +27,7 @@ public function testPolynomialAgrees(int $x, int $expected) $evaluated = $p($x); // Then - $this->assertEquals($expected, $evaluated); + $this->assertEqualsWithDelta($expected, $evaluated, 0.00001); } /** diff --git a/tests/NumericalAnalysis/Interpolation/LagrangePolynomialTest.php b/tests/NumericalAnalysis/Interpolation/LagrangePolynomialTest.php index 1c195348f..03af64121 100644 --- a/tests/NumericalAnalysis/Interpolation/LagrangePolynomialTest.php +++ b/tests/NumericalAnalysis/Interpolation/LagrangePolynomialTest.php @@ -25,7 +25,7 @@ public function testPolynomialAgrees(int $x, int $expected) $evaluated = $p($x); // Then - $this->assertEquals($expected, $evaluated); + $this->assertEqualsWithDelta($expected, $evaluated, 0.00001); } /** diff --git a/tests/NumericalAnalysis/Interpolation/NaturalCubicSplineTest.php b/tests/NumericalAnalysis/Interpolation/NaturalCubicSplineTest.php index ddf5e31fd..8a6fad972 100644 --- a/tests/NumericalAnalysis/Interpolation/NaturalCubicSplineTest.php +++ b/tests/NumericalAnalysis/Interpolation/NaturalCubicSplineTest.php @@ -26,7 +26,7 @@ public function testPolynomialAgrees(int $x, int $expected) $evaluated = $p($x); // Then - $this->assertEquals($expected, $evaluated); + $this->assertEqualsWithDelta($expected, $evaluated, 0.00001); } /** diff --git a/tests/NumericalAnalysis/Interpolation/NewtonPolynomialForwardTest.php b/tests/NumericalAnalysis/Interpolation/NewtonPolynomialForwardTest.php index c9fb95615..461efd7f9 100644 --- a/tests/NumericalAnalysis/Interpolation/NewtonPolynomialForwardTest.php +++ b/tests/NumericalAnalysis/Interpolation/NewtonPolynomialForwardTest.php @@ -25,7 +25,7 @@ public function testPolynomialAgrees(int $x, int $expected) $evaluated = $p($x); // Then - $this->assertEquals($expected, $evaluated); + $this->assertEqualsWithDelta($expected, $evaluated, 0.00001); } /** diff --git a/tests/NumericalAnalysis/Interpolation/RegularGridInterpolatorTest.php b/tests/NumericalAnalysis/Interpolation/RegularGridInterpolatorTest.php index 59a8650a3..c9384e345 100644 --- a/tests/NumericalAnalysis/Interpolation/RegularGridInterpolatorTest.php +++ b/tests/NumericalAnalysis/Interpolation/RegularGridInterpolatorTest.php @@ -26,7 +26,7 @@ public function testRegularGridAgrees(array $point, float $expected) $evaluated = $p($point); // Then - $this->assertEquals($expected, $evaluated); + $this->assertEqualsWithDelta($expected, $evaluated, 0.00001); } /** diff --git a/tests/NumericalAnalysis/NumericalIntegration/BoolesRuleTest.php b/tests/NumericalAnalysis/NumericalIntegration/BoolesRuleTest.php index e9e59b9aa..526fb2fd1 100644 --- a/tests/NumericalAnalysis/NumericalIntegration/BoolesRuleTest.php +++ b/tests/NumericalAnalysis/NumericalIntegration/BoolesRuleTest.php @@ -32,7 +32,7 @@ public function testApproximatePolynomialSortedPoints() // Given $sortedPoints = [[0, 1], [1, 4], [2, 13], [3, 34], [4, 73]]; $expected = 84; - $tol = 0; + $tol = 0.00001; // When $x = BoolesRule::approximate($sortedPoints); @@ -66,7 +66,7 @@ public function testApproximatePolynomialNonSortedPoints() // Given $nonSortedPoints = [[0, 1], [3, 34], [2, 13], [1, 4], [4, 73]]; $expected = 84; - $tol = 0; + $tol = 0.00001; // When $x = BoolesRule::approximate($nonSortedPoints); @@ -105,7 +105,7 @@ public function testApproximatePolynomialCallback() $end = 4; $n = 5; $expected = 84; - $tol = 0; + $tol = 0.00001; // When $x = BoolesRule::approximate($func, $start, $end, $n); @@ -142,7 +142,7 @@ public function testApproximatePolynomialUsingPolynomial() $end = 4; $n = 5; $expected = 84; - $tol = 0; + $tol = 0.00001; // When $x = BoolesRule::approximate($polynomial, $start, $end, $n); diff --git a/tests/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRuleTest.php b/tests/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRuleTest.php index fde535c39..724e766ff 100644 --- a/tests/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRuleTest.php +++ b/tests/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRuleTest.php @@ -31,7 +31,7 @@ public function testApproximateWithPoints() { // Given $points = [[0, 1], [1, 4], [2, 9], [3, 16]]; - $tol = 0; + $tol = 0.00001; $expected = 21; // When @@ -65,7 +65,7 @@ public function testApproximateWitPointsNotSorted() { // Given $points = [[2, 9], [3, 16], [0, 1], [1, 4]]; - $tol = 0; + $tol = 0.00001; $expected = 21; // When @@ -104,7 +104,7 @@ public function testApproximateUsingCallback() $start = 0; $end = 3; $n = 4; - $tol = 0; + $tol = 0.00001; $expected = 21; // When @@ -141,7 +141,7 @@ public function testApproximateUsingPolynomial() $start = 0; $end = 3; $n = 4; - $tol = 0; + $tol = 0.00001; $expected = 21; // When diff --git a/tests/Probability/Distribution/Discrete/BernoulliTest.php b/tests/Probability/Distribution/Discrete/BernoulliTest.php index 97ee5b53b..12330b1a1 100644 --- a/tests/Probability/Distribution/Discrete/BernoulliTest.php +++ b/tests/Probability/Distribution/Discrete/BernoulliTest.php @@ -217,7 +217,7 @@ public function testVariance(float $p, float $σ²) $variance = $bernoulli->variance(); // Then - $this->assertEquals($σ², $variance); + $this->assertEqualsWithDelta($σ², $variance, 0.00001); } /** diff --git a/tests/Sequence/NonIntegerTest.php b/tests/Sequence/NonIntegerTest.php index 9e0235fba..1d64874c9 100644 --- a/tests/Sequence/NonIntegerTest.php +++ b/tests/Sequence/NonIntegerTest.php @@ -19,7 +19,7 @@ public function testHarmonicNumbers(int $n, array $expectedSequence) $harmonicSequence = NonInteger::harmonic($n); // Then - $this->assertEquals($expectedSequence, $harmonicSequence); + $this->assertEqualsWithDelta($expectedSequence, $harmonicSequence, 0.00001); } /** diff --git a/tests/Statistics/ANOVATest.php b/tests/Statistics/ANOVATest.php index 83f883fd1..6a1c47b0f 100644 --- a/tests/Statistics/ANOVATest.php +++ b/tests/Statistics/ANOVATest.php @@ -308,13 +308,13 @@ public function testOneWayAxiomsThreeSamples(array $sample1, array $sample2, arr $SST = $anova['ANOVA']['total']['SS']; $SSB = $anova['ANOVA']['treatment']['SS']; $SSW = $anova['ANOVA']['error']['SS']; - $this->assertEquals($SST, $SSB + $SSW); + $this->assertEqualsWithDelta($SST, $SSB + $SSW, 0.00001); // And dfT = dfB + dfW $dfT = $anova['ANOVA']['total']['df']; $dfB = $anova['ANOVA']['treatment']['df']; $dfW = $anova['ANOVA']['error']['df']; - $this->assertEquals($dfT, $dfB + $dfW); + $this->assertEqualsWithDelta($dfT, $dfB + $dfW, 0.00001); } /** @@ -359,13 +359,13 @@ public function testOneWayAxiomsFiveSamples(array $sample1, array $sample2, arra $SST = $anova['ANOVA']['total']['SS']; $SSB = $anova['ANOVA']['treatment']['SS']; $SSW = $anova['ANOVA']['error']['SS']; - $this->assertEquals($SST, $SSB + $SSW); + $this->assertEqualsWithDelta($SST, $SSB + $SSW, 0.00001); // And dfT = dfB + dfW $dfT = $anova['ANOVA']['total']['df']; $dfB = $anova['ANOVA']['treatment']['df']; $dfW = $anova['ANOVA']['error']['df']; - $this->assertEquals($dfT, $dfB + $dfW); + $this->assertEqualsWithDelta($dfT, $dfB + $dfW, 0.00001); } /** diff --git a/tests/Statistics/AverageTest.php b/tests/Statistics/AverageTest.php index 442fbd6b6..690f635b0 100644 --- a/tests/Statistics/AverageTest.php +++ b/tests/Statistics/AverageTest.php @@ -909,7 +909,7 @@ public function testLehmerMeanPEqualsOneHalfIsGeometricMean() $mean = Average::lehmerMean($numbers, $p); // Then - $this->assertEquals(Average::geometricMean($numbers), $mean); + $this->assertEqualsWithDelta(Average::geometricMean($numbers), $mean, 0.00001); } /** @@ -1422,7 +1422,7 @@ public function testHeronianMean(float $A, float $B, float $expected) $H = Average::heronianMean($A, $B); // Then - $this->assertEquals($expected, $H); + $this->assertEqualsWithDelta($expected, $H, 0.00001); } /** diff --git a/tests/Trigonometry/TrigonometryTest.php b/tests/Trigonometry/TrigonometryTest.php index 9b1729283..c1e796576 100644 --- a/tests/Trigonometry/TrigonometryTest.php +++ b/tests/Trigonometry/TrigonometryTest.php @@ -18,7 +18,7 @@ public function testUnitCircle(int $points, array $expected) $unitCircle = Trigonometry::unitCircle($points); // Then - $this->assertEquals($expected, $unitCircle); + $this->assertEqualsWithDelta($expected, $unitCircle, 0.00000001); } /** From 83aaf6f8dce8a0806679edaef8a9897d394c5b06 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 16:50:08 -0800 Subject: [PATCH 13/66] Add withDelta to tests with floating point results. --- tests/Functions/SpecialTest.php | 2 +- tests/Sequence/NonIntegerTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Functions/SpecialTest.php b/tests/Functions/SpecialTest.php index 41b9e3b6e..428da39d8 100644 --- a/tests/Functions/SpecialTest.php +++ b/tests/Functions/SpecialTest.php @@ -1252,7 +1252,7 @@ public function testSoftmax(array $𝐳, array $expected) // Then $this->assertEqualsWithDelta($expected, $σ⟮𝐳⟯ⱼ, 0.00001); - $this->assertEquals(1, \array_sum($σ⟮𝐳⟯ⱼ), 0.00001); + $this->assertEqualsWithDelta(1, \array_sum($σ⟮𝐳⟯ⱼ), 0.00001); } public function dataProviderForSoftmax(): array diff --git a/tests/Sequence/NonIntegerTest.php b/tests/Sequence/NonIntegerTest.php index 1d64874c9..2b3140835 100644 --- a/tests/Sequence/NonIntegerTest.php +++ b/tests/Sequence/NonIntegerTest.php @@ -48,7 +48,7 @@ public function testGeneralizedHarmonicNumbers(int $n, float $p, array $expected $harmonicSequence = NonInteger::generalizedHarmonic($n, $p); // Then - $this->assertEquals($expectedSequence, $harmonicSequence); + $this->assertEqualsWithDelta($expectedSequence, $harmonicSequence, 0.00001); } /** From 749876ff724402d9a2c862c0aa91639bdfb1e363 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 17:49:30 -0800 Subject: [PATCH 14/66] Add withDelta to tests with floating point results. --- .../Decomposition/CholeskyTest.php | 2 +- .../MatrixArithmeticOperationsTest.php | 2 +- .../Matrix/Numeric/MatrixAxiomsTest.php | 36 +++++++++---------- .../Numeric/MatrixColumnOperationsTest.php | 2 +- .../Matrix/Numeric/MatrixOperationsTest.php | 4 +-- .../Numeric/MatrixRowOperationsTest.php | 8 ++--- .../Numeric/MatrixVectorOperationsTest.php | 4 +-- .../Matrix/Other/GivensMatrixTest.php | 2 +- .../LinearAlgebra/Vector/VectorAxiomsTest.php | 10 +++--- .../Vector/VectorOperationsTest.php | 12 +++---- 10 files changed, 41 insertions(+), 41 deletions(-) diff --git a/tests/LinearAlgebra/Decomposition/CholeskyTest.php b/tests/LinearAlgebra/Decomposition/CholeskyTest.php index ff0054cd2..6ee07c1e6 100644 --- a/tests/LinearAlgebra/Decomposition/CholeskyTest.php +++ b/tests/LinearAlgebra/Decomposition/CholeskyTest.php @@ -32,7 +32,7 @@ public function testCholeskyDecomposition(array $A, array $expected_L) // And LLᵀ = A $LLᵀ = $L->multiply($Lᵀ); - $this->assertEquals($A->getMatrix(), $LLᵀ->getMatrix()); + $this->assertEqualsWithDelta($A->getMatrix(), $LLᵀ->getMatrix(), 0.00001); } /** diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixArithmeticOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixArithmeticOperationsTest.php index 13e369003..554e9f4f3 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixArithmeticOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixArithmeticOperationsTest.php @@ -421,7 +421,7 @@ public function testMultiply(array $A, array $B, array $expected) $R = $A->multiply($B); // Then - $this->assertEquals($expected, $R); + $this->assertEqualsWithDelta($expected, $R, 0.00001); $this->assertTrue($R->isEqual($expected)); } diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php index 221136f5b..692cf93a5 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php @@ -652,9 +652,9 @@ public function testMatrixTimesInverseIsIdentity(array $A) $I = MatrixFactory::identity($A->getN()); // Then - $this->assertEquals($I->getMatrix(), $AA⁻¹->getMatrix()); - $this->assertEquals($I->getMatrix(), $A⁻¹A->getMatrix()); - $this->assertEquals($AA⁻¹->getMatrix(), $A⁻¹A->getMatrix()); + $this->assertEqualsWithDelta($I->getMatrix(), $AA⁻¹->getMatrix(), 0.00001); + $this->assertEqualsWithDelta($I->getMatrix(), $A⁻¹A->getMatrix(), 0.00001); + $this->assertEqualsWithDelta($AA⁻¹->getMatrix(), $A⁻¹A->getMatrix(), 0.00001); } /** @@ -674,7 +674,7 @@ public function testInverseOfInverseIsOriginalMatrix(array $A) $⟮A⁻¹⟯⁻¹ = $A->inverse()->inverse(); // Then - $this->assertEquals($A->getMatrix(), $⟮A⁻¹⟯⁻¹->getMatrix()); + $this->assertEqualsWithDelta($A->getMatrix(), $⟮A⁻¹⟯⁻¹->getMatrix(), 0.00001); } /** @@ -804,7 +804,7 @@ public function testInverseProductIsReverseProductOfInverses(array $A, array $B) $B⁻¹A⁻¹ = $B⁻¹->multiply($A⁻¹); // Then - $this->assertEquals($⟮AB⟯⁻¹->getMatrix(), $B⁻¹A⁻¹->getMatrix()); + $this->assertEqualsWithDelta($⟮AB⟯⁻¹->getMatrix(), $B⁻¹A⁻¹->getMatrix(), 0.00001); } /** @@ -973,7 +973,7 @@ public function testTransposeOfInverseIsInverseOfTranspose(array $A) $⟮Aᵀ⟯⁻¹ = $A->transpose()->inverse(); // Then - $this->assertEquals($⟮A⁻¹⟯ᵀ->getMatrix(), $⟮Aᵀ⟯⁻¹->getMatrix()); + $this->assertEqualsWithDelta($⟮A⁻¹⟯ᵀ->getMatrix(), $⟮Aᵀ⟯⁻¹->getMatrix(), 0.00001); } /** @@ -1167,7 +1167,7 @@ public function testLUDecompositionPAEqualsLU(array $A) // Then PA = LU; $PA = $P->multiply($A); $LU = $L->multiply($U); - $this->assertEquals($PA->getMatrix(), $LU->getMatrix()); + $this->assertEqualsWithDelta($PA->getMatrix(), $LU->getMatrix(), 0.00001); } /** @@ -1190,7 +1190,7 @@ public function testLUDecompositionAEqualsPInverseLU(array $A) // Then A = P⁻¹LU $P⁻¹LU = $P->inverse()->multiply($L)->multiply($U); - $this->assertEquals($A->getMatrix(), $P⁻¹LU->getMatrix()); + $this->assertEqualsWithDelta($A->getMatrix(), $P⁻¹LU->getMatrix(), 0.00001); } /** @@ -1250,9 +1250,9 @@ public function testInverseWithLUDecompositionInverse(array $A) $U⁻¹L⁻¹ = $U⁻¹->multiply($L⁻¹); // Then (PA)⁻¹ = (LU)⁻¹ = U⁻¹L⁻¹ - $this->assertEquals($⟮PA⟯⁻¹->getMatrix(), $⟮LU⟯⁻¹->getMatrix()); - $this->assertEquals($⟮LU⟯⁻¹->getMatrix(), $U⁻¹L⁻¹->getMatrix()); - $this->assertEquals($⟮PA⟯⁻¹->getMatrix(), $U⁻¹L⁻¹->getMatrix()); + $this->assertEqualsWithDelta($⟮PA⟯⁻¹->getMatrix(), $⟮LU⟯⁻¹->getMatrix(), 0.00001); + $this->assertEqualsWithDelta($⟮LU⟯⁻¹->getMatrix(), $U⁻¹L⁻¹->getMatrix(), 0.00001); + $this->assertEqualsWithDelta($⟮PA⟯⁻¹->getMatrix(), $U⁻¹L⁻¹->getMatrix(), 0.00001); } /** @@ -1631,8 +1631,8 @@ public function testSymmetricInverseTransposeEqualsIdentity(array $A) $I = MatrixFactory::identity($A->getM()); // Then - $this->assertEquals($I, $A⁻¹Aᵀ); - $this->assertEquals($I->getMatrix(), $A⁻¹Aᵀ->getMatrix()); + $this->assertEqualsWithDelta($I, $A⁻¹Aᵀ, 0.00001); + $this->assertEqualsWithDelta($I->getMatrix(), $A⁻¹Aᵀ->getMatrix(), 0.00001); } /** @@ -2012,7 +2012,7 @@ public function testKroneckerProductInverse(array $A, array $B) $⟮A⊗B⟯⁻¹ = $A->kroneckerProduct($B)->inverse(); // Then - $this->assertEquals($A⁻¹⊗B⁻¹->getMatrix(), $⟮A⊗B⟯⁻¹->getMatrix()); + $this->assertEqualsWithDelta($A⁻¹⊗B⁻¹->getMatrix(), $⟮A⊗B⟯⁻¹->getMatrix(), 0.00001); } /** @@ -3082,7 +3082,7 @@ public function testCholeskyDecompositionLTimesLTransposeIsA(array $A) $LLᵀ = $L->multiply($Lᵀ); // Then - $this->assertEquals($A->getMatrix(), $LLᵀ->getMatrix()); + $this->assertEqualsWithDelta($A->getMatrix(), $LLᵀ->getMatrix(), 0.00001); } /** @@ -3514,7 +3514,7 @@ public function testOrthogonalMatrixTimesTransposeIsIdentityMatrix(array $A) $AAᵀ = $A->multiply($Aᵀ); // Then - $this->assertEquals($I->getMatrix(), $AAᵀ->getMatrix()); + $this->assertEqualsWithDelta($I->getMatrix(), $AAᵀ->getMatrix(), 0.00001); } /** @@ -3534,7 +3534,7 @@ public function testOrthogonalTransposeOfOrthogonalMatrixTimesMatrixIsIdentityMa $AᵀA = $Aᵀ->multiply($A); // Then - $this->assertEquals($I->getMatrix(), $AᵀA->getMatrix()); + $this->assertEqualsWithDelta($I->getMatrix(), $AᵀA->getMatrix(), 0.00001); } /** @@ -3553,7 +3553,7 @@ public function testOrthogonalMatrixInverseEqualsTransposeOfOrthogonalMatrix(arr $A⁻¹ = $A->inverse(); // Then - $this->assertEquals($A⁻¹->getMatrix(), $Aᵀ->getMatrix()); + $this->assertEqualsWithDelta($A⁻¹->getMatrix(), $Aᵀ->getMatrix(), 0.00001); } /** diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php index c666c7a2c..b116fc343 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php @@ -26,7 +26,7 @@ public function testColumnMultiply(array $A, int $nᵢ, float $k, array $expecte $R = $A->columnMultiply($nᵢ, $k); // Then - $this->assertEquals($expectedMatrix, $R); + $this->assertEqualsWithDelta($expectedMatrix, $R, 0.00001); } /** diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php index 0baecea14..db31122d2 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php @@ -1070,8 +1070,8 @@ public function testAdjugate(array $A, array $expected) $adj⟮A⟯ = $A->adjugate(); // Then - $this->assertEquals($expected, $adj⟮A⟯); - $this->assertEquals($expected->getMatrix(), $adj⟮A⟯->getMatrix()); + $this->assertEqualsWithDelta($expected, $adj⟮A⟯, 0.00001); + $this->assertEqualsWithDelta($expected->getMatrix(), $adj⟮A⟯->getMatrix(), 0.00001); } public function dataProviderForAdjugate(): array diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php index b143acaa1..ef7c5664f 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php @@ -26,7 +26,7 @@ public function testRowMultiply(array $A, int $mᵢ, float $k, array $expectedMa $R = $A->rowMultiply($mᵢ, $k); // Then - $this->assertEquals($expectedMatrix, $R); + $this->assertEqualsWithDelta($expectedMatrix, $R, 0.00001); } /** @@ -137,7 +137,7 @@ public function testRowDivide(array $A, int $mᵢ, float $k, array $expectedMatr $R = $A->rowDivide($mᵢ, $k); // Then - $this->assertEquals($expectedMatrix, $R); + $this->assertEqualsWithDelta($expectedMatrix, $R, 0.00001); } /** @@ -428,7 +428,7 @@ public function testRowSubtract(array $A, int $mᵢ, int $mⱼ, float $k, array $R = $A->rowSubtract($mᵢ, $mⱼ, $k); // Then - $this->assertEquals($expectedMatrix, $R); + $this->assertEqualsWithDelta($expectedMatrix, $R, 0.00001); } /** @@ -527,7 +527,7 @@ public function testRowSubtractScalar(array $A, int $mᵢ, float $k, array $expe $R = $A->rowSubtractScalar($mᵢ, $k); // Then - $this->assertEquals($expectedMatrix, $R); + $this->assertEqualsWithDelta($expectedMatrix, $R, 0.00001); } /** diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixVectorOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixVectorOperationsTest.php index 66c1ec052..c4cbc8a57 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixVectorOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixVectorOperationsTest.php @@ -122,7 +122,7 @@ public function testRowSums(array $A, array $expected) $R = $A->rowSums(); // Then - $this->assertEquals($expected, $R); + $this->assertEqualsWithDelta($expected, $R, 0.00001); } /** @@ -189,7 +189,7 @@ public function testRowMeans(array $A, array $expected) $R = $A->rowMeans(); // Then - $this->assertEquals($expected, $R); + $this->assertEqualsWithDelta($expected, $R, 0.00001); } /** diff --git a/tests/LinearAlgebra/Matrix/Other/GivensMatrixTest.php b/tests/LinearAlgebra/Matrix/Other/GivensMatrixTest.php index 490a89cb0..80370af93 100644 --- a/tests/LinearAlgebra/Matrix/Other/GivensMatrixTest.php +++ b/tests/LinearAlgebra/Matrix/Other/GivensMatrixTest.php @@ -42,7 +42,7 @@ public function testGivensMatrix(int $m, int $n, float $angle, int $size, array $G = MatrixFactory::givens($m, $n, $angle, $size); // Then - $this->assertEquals($expected, $G->getMatrix()); + $this->assertEqualsWithDelta($expected, $G->getMatrix(), 0.00001); } /** diff --git a/tests/LinearAlgebra/Vector/VectorAxiomsTest.php b/tests/LinearAlgebra/Vector/VectorAxiomsTest.php index a1e2cb9ef..77bb62a66 100644 --- a/tests/LinearAlgebra/Vector/VectorAxiomsTest.php +++ b/tests/LinearAlgebra/Vector/VectorAxiomsTest.php @@ -735,8 +735,8 @@ public function testProjPerpSumEqualsA(array $A, array $B) $projᵇA+perpᵇA = $projᵇA->add($perpᵇA); // Then - $this->assertEquals($A, $projᵇA+perpᵇA); - $this->assertEquals($A->getVector(), $projᵇA+perpᵇA->getVector()); + $this->assertEqualsWithDelta($A, $projᵇA+perpᵇA, 0.00001); + $this->assertEqualsWithDelta($A->getVector(), $projᵇA+perpᵇA->getVector(), 0.00001); } /** @@ -756,7 +756,7 @@ public function testProjPerpSumOfSquares(array $A, array $B) $│perpᵇA│² = ($A->perp($B)->length()) ** 2; // Then - $this->assertEquals($│A│², $│projᵇA│² + $│perpᵇA│²); + $this->assertEqualsWithDelta($│A│², $│projᵇA│² + $│perpᵇA│², 0.00001); } /** @@ -777,7 +777,7 @@ public function testProjPerpDotProductEqualsZero(array $A, array $B) $projᵇA⋅perpᵇA = $projᵇA->dotProduct($perpᵇA); // Then - $this->assertEquals(0, $projᵇA⋅perpᵇA); + $this->assertEqualsWithDelta(0, $projᵇA⋅perpᵇA, 0.00001); } /** @@ -801,7 +801,7 @@ public function testProjPerpPerpDotProductEqualsProductOfLengths(array $A, array $│perpᵇA│ = $perpᵇA->length(); // Then - $this->assertEquals($projᵇA⊥⋅perpᵇA, $│projᵇA│ * $│perpᵇA│); + $this->assertEqualsWithDelta($projᵇA⊥⋅perpᵇA, $│projᵇA│ * $│perpᵇA│, 0.00001); } public function dataProviderForProjPerp(): array diff --git a/tests/LinearAlgebra/Vector/VectorOperationsTest.php b/tests/LinearAlgebra/Vector/VectorOperationsTest.php index cc81fbd31..2fb541141 100644 --- a/tests/LinearAlgebra/Vector/VectorOperationsTest.php +++ b/tests/LinearAlgebra/Vector/VectorOperationsTest.php @@ -301,8 +301,8 @@ public function testScalarMultiply(array $A, $k, array $R) $kA = $A->scalarMultiply($k); // Then - $this->assertEquals($R, $kA); - $this->assertEquals($R->getVector(), $kA->getVector()); + $this->assertEqualsWithDelta($R, $kA, 0.00001); + $this->assertEqualsWithDelta($R->getVector(), $kA->getVector(), 0.00001); } public function dataProviderForScalarMultiply(): array @@ -817,8 +817,8 @@ public function testProjection(array $A, array $B, array $expected) $projₐb = $A->projection($B); // Then - $this->assertEquals($expected, $projₐb); - $this->assertEquals($expected->getVector(), $projₐb->getVector()); + $this->assertEqualsWithDelta($expected, $projₐb, 0.00001); + $this->assertEqualsWithDelta($expected->getVector(), $projₐb->getVector(), 0.00001); } public function dataProviderForProjection(): array @@ -882,8 +882,8 @@ public function testPerp(array $A, array $B, array $expected) $perpₐb = $A->perp($B); // Then - $this->assertEquals($expected, $perpₐb); - $this->assertEquals($expected->getVector(), $perpₐb->getVector()); + $this->assertEqualsWithDelta($expected, $perpₐb, 0.00001); + $this->assertEqualsWithDelta($expected->getVector(), $perpₐb->getVector(), 0.00001); } public function dataProviderForPerp(): array From 2b99ecd0d5a2102cee646b60e94af3816cf003c8 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 17:53:29 -0800 Subject: [PATCH 15/66] Add withDelta to tests with floating point results. --- tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php | 2 +- .../LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php | 2 +- tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php index 692cf93a5..7886af737 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixAxiomsTest.php @@ -3571,7 +3571,7 @@ public function testOrthogonalMatrixDeterminateIsOne(array $A) $det⟮A⟯ = $A->det(); // Then - $this->assertEquals(1, \abs($det⟮A⟯)); + $this->assertEqualsWithDelta(1, \abs($det⟮A⟯), 0.000001); } /** diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php index b116fc343..9641590d5 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php @@ -138,7 +138,7 @@ public function testColumnAdd(array $A, int $nᵢ, int $nⱼ, float $k, array $e $R = $A->columnAdd($nᵢ, $nⱼ, $k); // Then - $this->assertEquals($expectedMatrix, $R); + $this->assertEqualsWithDelta($expectedMatrix, $R, 0.00001); } /** diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php index db31122d2..5024d942d 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixOperationsTest.php @@ -777,7 +777,7 @@ public function testMeanDeviationColumnsAsVariables(array $A, array $B) $meanDeviation = $A->meanDeviation('columns'); // Then - $this->assertEquals($B, $meanDeviation); + $this->assertEqualsWithDelta($B, $meanDeviation, 0.00001); } public function dataProviderForMeanDeviationColumnsAsVariables(): array From 7275502af59c016b6ff5f8c8491ef54b8f87004b Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 17:58:36 -0800 Subject: [PATCH 16/66] Add PHP 8.2 to CI Github Actions. --- .github/workflows/test_develop_and_master.yml | 2 +- .github/workflows/test_other_branches.yml | 2 +- .github/workflows/test_pull_request.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index 0f5453152..259399561 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] steps: - name: Set up PHP diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index 31b8e4fcc..cd82afd7b 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] steps: - name: Set up PHP diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index dac91cfbf..4c0150702 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] steps: - name: Set up PHP From 8c248c9e38a4aa6ad0d1590aeb325f20dbfcc809 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 19:08:18 -0800 Subject: [PATCH 17/66] Update README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c5ab9e9d7..9d736f47d 100644 --- a/README.md +++ b/README.md @@ -1773,7 +1773,7 @@ $hexagons = Advanced::hexagonalNumber($n); // [1, 6, 15, 28, 45, 66] - Indexed from 1 // Heptagonal numbers (figurate number) -$hexagons = Advanced::heptagonalNumber($n); +$heptagons = Advanced::heptagonalNumber($n); // [1, 4, 7, 13, 18, 27] - Indexed from 1 // Look-and-say sequence (describe the previous term!) From d40041b428cbc8c089c04a97f1be811fdc39abcb Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 20:24:35 -0800 Subject: [PATCH 18/66] Update README: Add Matrix row operations. --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9d736f47d..faa3741d5 100644 --- a/README.md +++ b/README.md @@ -444,16 +444,20 @@ $Aᵢⱼ = $A[2][2]; // Row operations [$mᵢ, $mⱼ, $k] = [1, 2, 5]; $R = $A->rowInterchange($mᵢ, $mⱼ); -$R = $A->rowMultiply($mᵢ, $k); // Multiply row mᵢ by k -$R = $A->rowAdd($mᵢ, $mⱼ, $k); // Add k * row mᵢ to row mⱼ -$R = $A->rowExclude($mᵢ); // Exclude row $mᵢ +$R = $A->rowExclude($mᵢ); // Exclude row $mᵢ +$R = $A->rowMultiply($mᵢ, $k); // Multiply row mᵢ by k +$R = $A->rowDivide($mᵢ, $k); // Divide row mᵢ by k +$R = $A->rowAdd($mᵢ, $mⱼ, $k); // Add k * row mᵢ to row mⱼ +$R = $A->rowAddScalar($mᵢ, $k); // Add k to each item of row mᵢ +$R = $A->rowSubtract($mᵢ, $mⱼ, $k); // Subtract k * row mᵢ from row mⱼ +$R = $A->rowSubtractScalar($mᵢ, $k); // Subtract k from each item of row mᵢ // Column operations [$nᵢ, $nⱼ, $k] = [1, 2, 5]; $R = $A->columnInterchange($nᵢ, $nⱼ); +$R = $A->columnExclude($nᵢ); // Exclude column $nᵢ $R = $A->columnMultiply($nᵢ, $k); // Multiply column nᵢ by k $R = $A->columnAdd($nᵢ, $nⱼ, $k); // Add k * column nᵢ to column nⱼ -$R = $A->columnExclude($nᵢ); // Exclude column $nᵢ // Matrix augmentations - return a new Matrix $⟮A∣B⟯ = $A->augment($B); // Augment on the right - standard augmentation From 8abfa12411f4c708527fea655c6c4f6fd11550f7 Mon Sep 17 00:00:00 2001 From: Rob Sheldon Date: Fri, 30 Dec 2022 21:53:41 -0800 Subject: [PATCH 19/66] Fix issue #458 (#460) * Issue 458: Fix division-by-zero error in Special::regularizedIncompleteBeta() Switched to a slightly different algorithm for computing the continued fraction. Removed Special::iBetaCF(), which was a private function only used by regularizedIncompletBeta() and no longer needed. * Cross-check test values for Special::regularizedIncompleteBeta Values were verified against Wolfram Alpha (using its "BetaRegularized[x, a, b]" function) as well as the online calculator mentioned in comments for dataProviderForRegularizedIncompleteBeta(). * Add tests for issue #458 --- src/Functions/Special.php | 144 ++++++++++---------------------- tests/Functions/SpecialTest.php | 21 +++-- 2 files changed, 57 insertions(+), 108 deletions(-) diff --git a/src/Functions/Special.php b/src/Functions/Special.php index c74a2aaa9..1c19207bf 100644 --- a/src/Functions/Special.php +++ b/src/Functions/Special.php @@ -1053,78 +1053,6 @@ public static function incompleteBeta(float $x, float $a, float $b): float return self::regularizedIncompleteBeta($x, $a, $b) * self::beta($a, $b); } - /** - * Regularized incomplete beta function - Iₓ(a, b) - * - * A continuous fraction is used to evaluate I - * - * / α₁ \ - * xᵃyᵇ | -------------- | - * Iₓ(a, b) = -------- | β₁ + α₂ | - * B(a,b) | ------ | - * \ β₂ + … / - * - * (a + m - 1) * (a + b + m -1) * m * (b - m) * x² - * α₁ = 1, αm+1 = ------------------------------------------------- - * (a + 2m - 1)² - * - * m * (b - m) * x (a + m) * (a - (a + b) * x + 1 + m * (2 - x)) - * βm+1 = m + ------------------ + ----------------------------------------------- - * a + 2 * m - 1 a + 2 * m + 1 - * - * This algorithm is valid when both a and b are greater than 1 - * - * @param int $m the number of α and β parameters to calculate - * @param float $x Upper limit of the integration 0 ≦ x ≦ 1 - * @param float $a Shape parameter a > 1 - * @param float $b Shape parameter b > 1 - * - * @return float - * - * @throws Exception\BadDataException - * @throws Exception\BadParameterException - * @throws Exception\OutOfBoundsException - */ - private static function iBetaCF(int $m, float $x, float $a, float $b): float - { - $limits = [ - 'x' => '[0, 1]', - 'a' => '(1,∞)', - 'b' => '(1,∞)', - ]; - Support::checkLimits($limits, ['x' => $x, 'a' => $a, 'b' => $b]); - - $beta = self::beta($a, $b); - $constant = $x ** $a * (1 - $x) ** $b / $beta; - - $α_array = []; - $β_array = []; - - for ($i = 0; $i < $m; $i++) { - if ($i == 0) { - $α = 1; - } else { - $α = ($a + $i - 1) * ($a + $b + $i - 1) * $i * ($b - $i) * $x ** 2 / ($a + 2 * $i - 1) ** 2; - } - $β₁ = $i + $i * ($b - $i) * $x / ($a + 2 * $i - 1); - $β₂ = ($a + $i) * ($a - ($a + $b) * $x + 1 + $i * (2 - $x)) / ($a + 2 * $i + 1); - $β = $β₁ + $β₂; - $α_array[] = $α; - $β_array[] = $β; - } - - $fraction_array = []; - for ($i = $m - 1; $i >= 0; $i--) { - if ($i == $m - 1) { - $fraction_array[$i] = $α_array[$i] / $β_array[$i]; - } else { - $fraction_array[$i] = $α_array[$i] / ($β_array[$i] + $fraction_array[$i + 1]); - } - } - - return $constant * $fraction_array[0]; - } - /** * Regularized incomplete beta function - Iₓ(a, b) * @@ -1135,6 +1063,7 @@ private static function iBetaCF(int $m, float $x, float $a, float $b): float * * http://www.boost.org/doc/libs/1_35_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_beta/ibeta_function.html * https://github.com/boostorg/math/blob/develop/include/boost/math/special_functions/beta.hpp + * https://github.com/codeplea/incbeta * * @param float $x Upper limit of the integration 0 ≦ x ≦ 1 * @param float $a Shape parameter a > 0 @@ -1144,6 +1073,8 @@ private static function iBetaCF(int $m, float $x, float $a, float $b): float * * @throws Exception\BadDataException * @throws Exception\BadParameterException + * @throws Exception\FunctionFailedToConvergeException + * @throws Exception\NanException * @throws Exception\OutOfBoundsException */ public static function regularizedIncompleteBeta(float $x, float $a, float $b): float @@ -1167,40 +1098,55 @@ public static function regularizedIncompleteBeta(float $x, float $a, float $b): return $x ** $a; } - if ($x > .9 || $b > $a && $x > .5) { - $y = 1 - $x; - return 1 - self::regularizedIncompleteBeta($y, $b, $a); + if ($x > ($a + 1)/($a + $b + 2)) { + return 1 - self::regularizedIncompleteBeta((1 - $x), $b, $a); } - if ($a > 1 && $b > 1) { - // Tolerance on evaluating the continued fraction. - $tol = .000000000000001; - $dif = $tol + 1; // Initialize - // We will calculate the continuous fraction with a minimum depth of 10. - $m = 10; // Counter - $I = 0; - do { - $I_new = self::iBetaCF($m, $x, $a, $b); - if ($m > 10) { - $dif = \abs(($I - $I_new) / $I_new); - } - $I = $I_new; + // There are several different ways to calculate the incomplete beta function + // (https://dlmf.nist.gov/8.17). This follows the continued fraction form, + // which consists of a term followed by a converging series of fractions. + // Lentz's Algorithm is used to solve the continued fraction. + + $first_term = \exp(log($x) * $a + \log(1.0 - $x) * $b - (self::logGamma($a) + self::logGamma($b) - self::logGamma($a + $b))) / $a; + + // PHP 7.2.0 offers PHP_FLOAT_EPSILON, but 1.0e-30 is used in Lewis Van Winkle's + // reference implementation to prevent division-by-zero errors, so we use the same here. + $ε = 1.0e-30; + + // These starting values are changed from the reference implementation at + // https://github.com/codeplea/incbeta to precalculate $i = 0 and avoid the + // extra conditional expression inside the loop. + $d = 1.0; + $c = 2.0; + $f = $c * $d; + + $m = 0; + for ($i = 1; $i <= 200; $i++) { + if ($i % 2 === 0) { + // Even term. $m++; - } while ($dif > $tol); - return $I; - } else { - if ($a <= 1) { - // We shift a up by one, to the region that the continuous fraction works best. - $offset = $x ** $a * (1 - $x) ** $b / $a / self::beta($a, $b); - return self::regularizedIncompleteBeta($x, $a + 1, $b) + $offset; - } else { // $b <= 1 - // We shift b up by one, to the region that the continuous fraction works best. - $offset = $x ** $a * (1 - $x) ** $b / $b / self::beta($a, $b); - return self::regularizedIncompleteBeta($x, $a, $b + 1) - $offset; + $numerator = ($m * ($b - $m) * $x) / (($a + 2.0 * $m - 1.0) * ($a + 2.0 * $m)); + } else { + // Odd term. + $numerator = -(($a + $m) * ($a + $b + $m) * $x) / (($a + 2.0 * $m) * ($a + 2.0 * $m + 1)); + } + + // Lentz's Algorithm. + $d = 1.0 + $numerator * $d; + $d = 1.0 / (\abs($d) < $ε ? $ε : $d); + $c = 1.0 + $numerator / (\abs($c) < $ε ? $ε : $c); + $f *= $c * $d; + + if (\abs(1.0 - $c * $d) < 1.0e-8) { + return $first_term * ($f - 1.0); } } + + // Series did not converge. + throw new Exception\FunctionFailedToConvergeException(sprintf('Continuous fraction series is not converging for x = %f, a = %f, b = %f', $x, $a, $b)); } + /** * Generalized Hypergeometric Function * diff --git a/tests/Functions/SpecialTest.php b/tests/Functions/SpecialTest.php index 428da39d8..dc6a699c6 100644 --- a/tests/Functions/SpecialTest.php +++ b/tests/Functions/SpecialTest.php @@ -1017,23 +1017,26 @@ public function dataProviderForRegularizedIncompleteBeta(): array [0.9, 1, 1, 0.9], [1, 1, 1, 1], [0, 2, 2, 0], - [0.1, 2, 2, 0.028000000000000004], - [0.2, 2, 2, 0.10400000000000002], - [0.3, 2, 2, 0.21600000000000003], - [0.4, 2, 2, 0.3520000000000001], + [0.1, 2, 2, 0.028], + [0.2, 2, 2, 0.104], + [0.3, 2, 2, 0.216], + [0.4, 2, 2, 0.352], [0.5, 2, 2, 0.5], - [0.6, 2, 2, 0.6479999999999999], - [0.7, 2, 2, 0.7839999999999999], + [0.6, 2, 2, 0.648], + [0.7, 2, 2, 0.784], [0.8, 2, 2, 0.896], [0.9, 2, 2, 0.972], [1, 2, 2, 1], // SciPy examples - https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.betainc.html#scipy.special.betainc [1, 0.2, 3.5, 1], [0.5, 1.4, 3.1, 0.8148904036225296], - [0.4, 2.2, 3.1, 0.49339638807619446], + [0.4, 2.2, 3.1, 0.4933963880761945], // Issue #429 - [0.0041461509490402, 0.5, 170.5, 0.7657225092554765], - [0.0041461509490402, 1.5, 170.5, 0.29887797299850866], + [0.0041461509490402, 0.5, 170.5, 0.7657225092554762], + [0.0041461509490402, 1.5, 170.5, 0.29887797299851921], + // Issue #458 + [0.47241392386467, 0.5, 55.5, 0.99999999999999996], + [0.47241392386467, 1.5, 55.5, 0.99999999999999773], ]; } From c293fcda9a9cebb4910d08cc8292e698ad9bef09 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 22:16:31 -0800 Subject: [PATCH 20/66] Minor refactor of regularizedIncompleteBeta and add additional unit tests. --- src/Functions/Special.php | 29 ++++++++++++++++------------- tests/Functions/SpecialTest.php | 13 +++++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/Functions/Special.php b/src/Functions/Special.php index 1c19207bf..6d75b6786 100644 --- a/src/Functions/Special.php +++ b/src/Functions/Special.php @@ -1061,9 +1061,16 @@ public static function incompleteBeta(float $x, float $a, float $b): float * This function looks at the values of x, a, and b, and determines which algorithm is best to calculate * the value of Iₓ(a, b) * - * http://www.boost.org/doc/libs/1_35_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_beta/ibeta_function.html - * https://github.com/boostorg/math/blob/develop/include/boost/math/special_functions/beta.hpp - * https://github.com/codeplea/incbeta + * There are several ways to calculate the incomplete beta function (See: https://dlmf.nist.gov/8.17). + * This follows the continued fraction form, which consists of a term followed by a converging series of fractions. + * Lentz's Algorithm is used to solve the continued fraction. + * + * The implementation of the continued fraction using Lentz's Algorithm is heavily inspired by Lewis Van Winkle's + * reference implementation in C: https://github.com/codeplea/incbeta + * + * Other implementations used as references in the past: + * http://www.boost.org/doc/libs/1_35_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_beta/ibeta_function.html + * https://github.com/boostorg/math/blob/develop/include/boost/math/special_functions/beta.hpp * * @param float $x Upper limit of the integration 0 ≦ x ≦ 1 * @param float $a Shape parameter a > 0 @@ -1102,19 +1109,15 @@ public static function regularizedIncompleteBeta(float $x, float $a, float $b): return 1 - self::regularizedIncompleteBeta((1 - $x), $b, $a); } - // There are several different ways to calculate the incomplete beta function - // (https://dlmf.nist.gov/8.17). This follows the continued fraction form, - // which consists of a term followed by a converging series of fractions. - // Lentz's Algorithm is used to solve the continued fraction. + // Continued fraction using Lentz's Algorithm. - $first_term = \exp(log($x) * $a + \log(1.0 - $x) * $b - (self::logGamma($a) + self::logGamma($b) - self::logGamma($a + $b))) / $a; + $first_term = \exp(\log($x) * $a + \log(1.0 - $x) * $b - (self::logGamma($a) + self::logGamma($b) - self::logGamma($a + $b))) / $a; // PHP 7.2.0 offers PHP_FLOAT_EPSILON, but 1.0e-30 is used in Lewis Van Winkle's // reference implementation to prevent division-by-zero errors, so we use the same here. $ε = 1.0e-30; - // These starting values are changed from the reference implementation at - // https://github.com/codeplea/incbeta to precalculate $i = 0 and avoid the + // These starting values are changed from the reference implementation to precalculate $i = 0 and avoid the // extra conditional expression inside the loop. $d = 1.0; $c = 2.0; @@ -1123,15 +1126,15 @@ public static function regularizedIncompleteBeta(float $x, float $a, float $b): $m = 0; for ($i = 1; $i <= 200; $i++) { if ($i % 2 === 0) { - // Even term. + // Even term $m++; $numerator = ($m * ($b - $m) * $x) / (($a + 2.0 * $m - 1.0) * ($a + 2.0 * $m)); } else { - // Odd term. + // Odd term $numerator = -(($a + $m) * ($a + $b + $m) * $x) / (($a + 2.0 * $m) * ($a + 2.0 * $m + 1)); } - // Lentz's Algorithm. + // Lentz's Algorithm $d = 1.0 + $numerator * $d; $d = 1.0 / (\abs($d) < $ε ? $ε : $d); $c = 1.0 + $numerator / (\abs($c) < $ε ? $ε : $c); diff --git a/tests/Functions/SpecialTest.php b/tests/Functions/SpecialTest.php index dc6a699c6..38bdc47b9 100644 --- a/tests/Functions/SpecialTest.php +++ b/tests/Functions/SpecialTest.php @@ -1037,6 +1037,19 @@ public function dataProviderForRegularizedIncompleteBeta(): array // Issue #458 [0.47241392386467, 0.5, 55.5, 0.99999999999999996], [0.47241392386467, 1.5, 55.5, 0.99999999999999773], + // Reference implementation tests computed using SciPy - https://github.com/codeplea/incbeta/blob/master/test.c + [0.1, 10, 10, 3.929882327128003e-06], + [0.3, 10, 10, 0.03255335688130092], + [0.5, 10, 10, 0.5], + [0.7, 10, 10, 0.967446643118699], + [1, 10, 10, 1.0], + [0.5, 15, 10, 0.1537281274795532], + [0.6, 15, 10, 0.4890801931489529], + [0.5, 10, 15, 0.8462718725204468], + [0.6, 10, 15, 0.978341948670397], + [0.4, 20, 20, 0.10205863128940816], + [0.4, 40, 40, 0.03581030716079576], + [0.7, 40, 40, 0.9999016649962936], ]; } From cab7510d3bba9f443f9beefcc30fb5079c27b6bc Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 22:26:36 -0800 Subject: [PATCH 21/66] Add regression test for issue 458. --- tests/Statistics/SignificanceTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Statistics/SignificanceTest.php b/tests/Statistics/SignificanceTest.php index 4574c4593..e6502697a 100644 --- a/tests/Statistics/SignificanceTest.php +++ b/tests/Statistics/SignificanceTest.php @@ -676,4 +676,22 @@ public function testChiSquaredTestExceptionCountsDiffer() // When Significance::chiSquaredTest($observed, $expected); } + + /** + * @test Issue 458 regression test - Division-by-zero error in t-test + * https://github.com/markrogoyski/math-php/issues/458 + */ + public function testIssue458(): void { + // Given + $values = []; + for ($i=0; $i < 95; $i++) {$values[] = 1;} + for ($i=0; $i < 5; $i++) {$values[] = 0.5;} + for ($i=0; $i < 12; $i++) {$values[] = 0;} + + // When + $tTest = Significance::tTest($values, 0.569); + + // Then t-test completed without division-by-zero error + $this->expectNotToPerformAssertions(); + } } From 75771ae0964dce683d4c8e45bbfc5f65b6d97c6e Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 22:32:28 -0800 Subject: [PATCH 22/66] Minor formating improvements. --- tests/Statistics/SignificanceTest.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/Statistics/SignificanceTest.php b/tests/Statistics/SignificanceTest.php index e6502697a..01c7c9b6c 100644 --- a/tests/Statistics/SignificanceTest.php +++ b/tests/Statistics/SignificanceTest.php @@ -681,12 +681,19 @@ public function testChiSquaredTestExceptionCountsDiffer() * @test Issue 458 regression test - Division-by-zero error in t-test * https://github.com/markrogoyski/math-php/issues/458 */ - public function testIssue458(): void { + public function testIssue458(): void + { // Given $values = []; - for ($i=0; $i < 95; $i++) {$values[] = 1;} - for ($i=0; $i < 5; $i++) {$values[] = 0.5;} - for ($i=0; $i < 12; $i++) {$values[] = 0;} + for ($i = 0; $i < 95; $i++) { + $values[] = 1; + } + for ($i = 0; $i < 5; $i++) { + $values[] = 0.5; + } + for ($i = 0; $i < 12; $i++) { + $values[] = 0; + } // When $tTest = Significance::tTest($values, 0.569); From d347007d78933337cb189a0bd2d8150ba41c38d1 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 22:52:12 -0800 Subject: [PATCH 23/66] Change 'number' to int-float type hint in PHPDoc comments: Issue 456. --- src/Expression/Piecewise.php | 14 +++++----- src/Expression/Polynomial.php | 2 +- src/Functions/Map/Single.php | 28 +++++++++---------- src/Functions/Special.php | 2 +- src/InformationTheory/Entropy.php | 4 +-- src/LinearAlgebra/MatrixCatalog.php | 2 +- src/LinearAlgebra/MatrixFactory.php | 8 +++--- src/LinearAlgebra/Vector.php | 8 +++--- src/Number/Complex.php | 6 ++-- src/Number/Quaternion.php | 8 +++--- .../Interpolation/ClampedCubicSpline.php | 2 +- .../Interpolation/LagrangePolynomial.php | 2 +- .../Interpolation/NaturalCubicSpline.php | 2 +- .../Interpolation/NewtonPolynomialForward.php | 2 +- .../FivePointFormula.php | 2 +- .../NumericalDifferentiation.php | 12 ++++---- .../SecondDerivativeMidpointFormula.php | 2 +- .../ThreePointFormula.php | 2 +- .../NumericalIntegration/BoolesRule.php | 2 +- .../NumericalIntegration/MidpointRule.php | 2 +- .../NumericalIntegration/RectangleMethod.php | 2 +- .../NumericalIntegration/SimpsonsRule.php | 2 +- .../SimpsonsThreeEighthsRule.php | 2 +- .../NumericalIntegration/TrapezoidalRule.php | 2 +- .../RootFinding/BisectionMethod.php | 16 +++++------ .../RootFinding/FixedPointIteration.php | 16 +++++------ .../RootFinding/NewtonsMethod.php | 14 +++++----- .../RootFinding/SecantMethod.php | 10 +++---- .../RootFinding/Validation.php | 6 ++-- .../Distribution/Discrete/Zipf.php | 4 +-- src/Probability/Distribution/Distribution.php | 2 +- src/Sequence/Basic.php | 6 ++-- 32 files changed, 97 insertions(+), 97 deletions(-) diff --git a/src/Expression/Piecewise.php b/src/Expression/Piecewise.php index be1ac0481..3766a4579 100644 --- a/src/Expression/Piecewise.php +++ b/src/Expression/Piecewise.php @@ -221,13 +221,13 @@ private function constructorPreconditions(array $intervals, array $functions) * Check the as and bs in the intervals * Helper method of constructor. * - * @param number $a - * @param number $b - * @param number $lastA - * @param number $lastB - * @param bool $lastBOpen - * @param bool $aOpen - * @param bool $bOpen + * @param int|float $a + * @param int|float $b + * @param int|float $lastA + * @param int|float $lastB + * @param bool $lastBOpen + * @param bool $aOpen + * @param bool $bOpen * * @return void * diff --git a/src/Expression/Polynomial.php b/src/Expression/Polynomial.php index 4d47bf828..0ee6d237a 100644 --- a/src/Expression/Polynomial.php +++ b/src/Expression/Polynomial.php @@ -173,7 +173,7 @@ public function __toString(): string * echo $polynomial(4); * // prints -13 * - * @param number $x₀ The value at which we are evaluating our polynomial + * @param int|float $x₀ The value at which we are evaluating our polynomial * * @return float The result of our polynomial evaluated at $x₀ */ diff --git a/src/Functions/Map/Single.php b/src/Functions/Map/Single.php index a0f9046d9..37407227d 100644 --- a/src/Functions/Map/Single.php +++ b/src/Functions/Map/Single.php @@ -12,8 +12,8 @@ class Single /** * Map addition * - * @param array $xs - * @param number $k Number to add to each element + * @param array $xs + * @param int|float $k Number to add to each element * * @return array */ @@ -30,8 +30,8 @@ function ($x) use ($k) { /** * Map subtract * - * @param array $xs - * @param number $k Number to subtract from each element + * @param array $xs + * @param int|float $k Number to subtract from each element * * @return array */ @@ -48,8 +48,8 @@ function ($x) use ($k) { /** * Map multiply * - * @param array $xs - * @param number $k Number to multiply to each element + * @param array $xs + * @param int|float $k Number to multiply to each element * * @return array */ @@ -66,8 +66,8 @@ function ($x) use ($k) { /** * Map Divide * - * @param array $xs - * @param number $k Number to divide each element by + * @param array $xs + * @param int|float $k Number to divide each element by * * @return array */ @@ -148,8 +148,8 @@ function ($x) { /** * Map raise to a power * - * @param array $xs - * @param number $n + * @param array $xs + * @param int|float $n * * @return array */ @@ -202,8 +202,8 @@ function ($x) { * Each element in array is compared against the value, * and the min of each is returned. * - * @param array $xs - * @param number $value + * @param array $xs + * @param int|float $value * * @return array */ @@ -222,8 +222,8 @@ function ($x) use ($value) { * Each element in the array is compared against the value, * and the max of each is returned. * - * @param array $xs - * @param number $value + * @param array $xs + * @param int|float $value * * @return array */ diff --git a/src/Functions/Special.php b/src/Functions/Special.php index 6d75b6786..38cd9d1be 100644 --- a/src/Functions/Special.php +++ b/src/Functions/Special.php @@ -898,7 +898,7 @@ public static function erf(float $x): float * Complementary error function (erfc) * erfc(x) ≡ 1 - erf(x) * - * @param number $x + * @param int|float $x * * @return float */ diff --git a/src/InformationTheory/Entropy.php b/src/InformationTheory/Entropy.php index 7b197817b..393e81391 100644 --- a/src/InformationTheory/Entropy.php +++ b/src/InformationTheory/Entropy.php @@ -236,8 +236,8 @@ public static function jointEntropy(array $P⟮x、y⟯) * * H is in shannons, or bits. * - * @param array $p probability distribution - * @param number $α order α + * @param array $p probability distribution + * @param int|float $α order α * * @return float * diff --git a/src/LinearAlgebra/MatrixCatalog.php b/src/LinearAlgebra/MatrixCatalog.php index 6e2ad3619..07d5ec1d8 100644 --- a/src/LinearAlgebra/MatrixCatalog.php +++ b/src/LinearAlgebra/MatrixCatalog.php @@ -297,7 +297,7 @@ public function getSVD(): Decomposition\SVD // DETERMINANT /** - * @param number $det + * @param int|float $det */ public function addDeterminant($det): void { diff --git a/src/LinearAlgebra/MatrixFactory.php b/src/LinearAlgebra/MatrixFactory.php index 2a5a59d2a..12235ffff 100644 --- a/src/LinearAlgebra/MatrixFactory.php +++ b/src/LinearAlgebra/MatrixFactory.php @@ -14,8 +14,8 @@ class MatrixFactory /** * Factory method * - * @param number[][] $A 2-dimensional array of Matrix data - * @param float|null $ε Optional error tolerance + * @param int[][]|float[][]|Complex[][]|object[][] $A 2-dimensional array of Matrix data + * @param float|null $ε Optional error tolerance * * @return Matrix * @@ -46,8 +46,8 @@ public static function create(array $A, ?float $ε = null): Matrix } /** - * @param number[][] $A - * @param float|null $ε Optional error tolerance + * @param int[][]|float[][] $A + * @param float|null $ε Optional error tolerance * * @return NumericMatrix * diff --git a/src/LinearAlgebra/Vector.php b/src/LinearAlgebra/Vector.php index bca4da514..c10c90a03 100644 --- a/src/LinearAlgebra/Vector.php +++ b/src/LinearAlgebra/Vector.php @@ -427,7 +427,7 @@ public function divide(Vector $B): Vector * Scalar multiplication (scale) * kA = [k * a₁, k * a₂, k * a₃ ...] * - * @param number $k Scale factor + * @param int|float $k Scale factor * * @return Vector */ @@ -440,7 +440,7 @@ public function scalarMultiply($k): Vector * Scalar divide * kA = [k / a₁, k / a₂, k / a₃ ...] * - * @param number $k Scale factor + * @param int|float $k Scale factor * * @return Vector */ @@ -692,9 +692,9 @@ public function l2Norm() * * |x|p = (∑|xᵢ|ᵖ)¹/ᵖ * - * @param number $p + * @param int|float $p * - * @return number + * @return int|float */ public function pNorm($p) { diff --git a/src/Number/Complex.php b/src/Number/Complex.php index 18f80719f..6fd9e2f6e 100644 --- a/src/Number/Complex.php +++ b/src/Number/Complex.php @@ -39,8 +39,8 @@ class Complex implements ObjectArithmetic /** * Constructor * - * @param number $r Real part - * @param number $i Imaginary part + * @param int|float $r Real part + * @param int|float $i Imaginary part */ public function __construct($r, $i) { @@ -383,7 +383,7 @@ public function divide($c): Complex * - https://en.wikipedia.org/wiki/Complex_number#Exponentiation * - https://mathworld.wolfram.com/ComplexExponentiation.html * - * @param Complex|number $c + * @param Complex|int|float $c * * @return Complex * diff --git a/src/Number/Quaternion.php b/src/Number/Quaternion.php index ac9dfada0..530b18105 100644 --- a/src/Number/Quaternion.php +++ b/src/Number/Quaternion.php @@ -30,10 +30,10 @@ class Quaternion implements ObjectArithmetic const EPSILON = 1e-6; /** - * @param number $r Real part - * @param number $i Imaginary part - * @param number $j Imaginary part - * @param number $k Imaginary part + * @param int|float $r Real part + * @param int|float $i Imaginary part + * @param int|float $j Imaginary part + * @param int|float $k Imaginary part */ public function __construct($r, $i, $j, $k) { diff --git a/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php b/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php index 5e2384bb1..742b10610 100644 --- a/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php +++ b/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php @@ -42,7 +42,7 @@ class ClampedCubicSpline extends Interpolation * (point) contains precisely three numbers: x, y, and y' * Example array: [[1,2,1], [2,3,0], [3,4,2]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args (Optional) An additional callback: our first derivative, + * @param int|float ...$args (Optional) An additional callback: our first derivative, * and arguments of our callback functions: start, * end, and n. * Example: approximate($source, $derivative, 0, 8, 5). diff --git a/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php b/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php index 566f66a95..23be3aae2 100644 --- a/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php +++ b/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php @@ -36,7 +36,7 @@ class LagrangePolynomial extends Interpolation * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php b/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php index f9656fb91..e28492028 100644 --- a/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php +++ b/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php @@ -39,7 +39,7 @@ class NaturalCubicSpline extends Interpolation * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php b/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php index 51f7a694a..25c262ba3 100644 --- a/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php +++ b/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php @@ -31,7 +31,7 @@ class NewtonPolynomialForward extends Interpolation * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php index 8a4e7e1be..c926afd65 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php @@ -57,7 +57,7 @@ class FivePointFormula extends NumericalDifferentiation * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4], [4,5], [5,6]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($number, $source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php index 8a56b101d..2b8b3bbd2 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php @@ -69,10 +69,10 @@ public static function getPoints($source, array $args = []): array * Evaluate our callback function at n evenly spaced points on the interval * between start and end * - * @param callable $function f(x) callback function - * @param number $start the start of the interval - * @param number $end the end of the interval - * @param number $n the number of function evaluations + * @param callable $function f(x) callback function + * @param int|float $start the start of the interval + * @param int|float $end the end of the interval + * @param int|float $n the number of function evaluations * * @return array[] */ @@ -164,8 +164,8 @@ public static function isSpacingConstant(array $sorted) /** * Ensures that our target is the x-component of one of the points we supply * - * @param number $target The value at which we are approximating the derivative - * @param array $sorted Points sorted by (increasing) x-component + * @param int|float $target The value at which we are approximating the derivative + * @param array $sorted Points sorted by (increasing) x-component * * @throws Exception\BadDataException if $target is not contained in the array of our x-components */ diff --git a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php index 12d539d69..6a62aa536 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php @@ -46,7 +46,7 @@ class SecondDerivativeMidpointFormula extends NumericalDifferentiation * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: differentiate($target, $source, 0, 8, 3). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php index 09c0c638f..6161aed49 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php @@ -57,7 +57,7 @@ class ThreePointFormula extends NumericalDifferentiation * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: differentiate($target, $source, 0, 8, 3). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php b/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php index d8bf35422..07e04993d 100644 --- a/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php @@ -68,7 +68,7 @@ class BoolesRule extends NumericalIntegration * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4], [4,5], [5,6]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 4). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php b/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php index 284b54ec3..b53cb39c5 100644 --- a/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php @@ -60,7 +60,7 @@ class MidpointRule extends NumericalIntegration * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php b/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php index d582fc643..8ee7fe1a8 100644 --- a/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php +++ b/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php @@ -63,7 +63,7 @@ class RectangleMethod extends NumericalIntegration * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php b/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php index e3620da79..c472b8729 100644 --- a/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php @@ -67,7 +67,7 @@ class SimpsonsRule extends NumericalIntegration * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php b/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php index de77d1fc1..32df65ff7 100644 --- a/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php @@ -68,7 +68,7 @@ class SimpsonsThreeEighthsRule extends NumericalIntegration * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4], [4,5]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 4). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php b/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php index 997bf49ec..4acfa66ba 100644 --- a/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php @@ -64,7 +64,7 @@ class TrapezoidalRule extends NumericalIntegration * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} - * @param number ...$args The arguments of our callback function: start, + * @param int|float ...$args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). diff --git a/src/NumericalAnalysis/RootFinding/BisectionMethod.php b/src/NumericalAnalysis/RootFinding/BisectionMethod.php index 2e20bb204..5b3ccd31b 100644 --- a/src/NumericalAnalysis/RootFinding/BisectionMethod.php +++ b/src/NumericalAnalysis/RootFinding/BisectionMethod.php @@ -26,10 +26,10 @@ class BisectionMethod /** * Use the Bisection Method to find the x which produces $function(x) = 0. * - * @param callable $function f(x) callback function - * @param number $a The start of the interval which contains a root - * @param number $b The end of the interval which contains a root - * @param number $tol Tolerance; How close to the actual solution we would like. + * @param callable $function f(x) callback function + * @param int|float $a The start of the interval which contains a root + * @param int|float $b The end of the interval which contains a root + * @param int|float $tol Tolerance; How close to the actual solution we would like. * @return number * @@ -65,10 +65,10 @@ public static function solve(callable $function, $a, $b, $tol) * we cannot run our loop as $a and $b will themselves be the midpoint, so we * throw an Exception. * - * @param Callable $function f(x) callback function - * @param number $a The start of the interval which contains a root - * @param number $b The end of the interval which contains a root - * @param number $tol Tolerance; How close to the actual solution we would like. + * @param Callable $function f(x) callback function + * @param int|float $a The start of the interval which contains a root + * @param int|float $b The end of the interval which contains a root + * @param int|float $tol Tolerance; How close to the actual solution we would like. * * @throws Exception\OutOfBoundsException if $tol (the tolerance) is negative * @throws Exception\BadDataException if $a = $b diff --git a/src/NumericalAnalysis/RootFinding/FixedPointIteration.php b/src/NumericalAnalysis/RootFinding/FixedPointIteration.php index 147333d67..59e5619b4 100644 --- a/src/NumericalAnalysis/RootFinding/FixedPointIteration.php +++ b/src/NumericalAnalysis/RootFinding/FixedPointIteration.php @@ -28,10 +28,10 @@ class FixedPointIteration * * @param callable $function g(x) callback function, obtained by rewriting * f(x) = 0 as g(x) = x - * @param number $a The start of the interval which contains a root - * @param number $b The end of the interval which contains a root - * @param number $p The initial guess of our root, in [$a, $b] - * @param number $tol Tolerance; How close to the actual solution we would like. + * @param int|float $a The start of the interval which contains a root + * @param int|float $b The end of the interval which contains a root + * @param int|float $p The initial guess of our root, in [$a, $b] + * @param int|float $tol Tolerance; How close to the actual solution we would like. * @return number * @@ -58,10 +58,10 @@ public static function solve(callable $function, $a, $b, $p, $tol) * an interval, so we throw an Exception. If $a > $b, we simply reverse them * as if the user input $b = $a and $a = $b so the new $a < $b. * - * @param number $a The start of the interval which contains a root - * @param number $b The end of the interval which contains a root - * @param number $p The initial guess of our root - * @param number $tol Tolerance; How close to the actual solution we would like. + * @param int|float $a The start of the interval which contains a root + * @param int|float $b The end of the interval which contains a root + * @param int|float $p The initial guess of our root + * @param int|float $tol Tolerance; How close to the actual solution we would like. * * @throws Exception\OutOfBoundsException if $tol (the tolerance) is negative * @throws Exception\BadDataException if $a = $b diff --git a/src/NumericalAnalysis/RootFinding/NewtonsMethod.php b/src/NumericalAnalysis/RootFinding/NewtonsMethod.php index 24075f9cb..34820c967 100644 --- a/src/NumericalAnalysis/RootFinding/NewtonsMethod.php +++ b/src/NumericalAnalysis/RootFinding/NewtonsMethod.php @@ -17,13 +17,13 @@ class NewtonsMethod * $args is an array of parameters to pass to $function, but having the element that * will be changed and serve as the initial guess in position $position. * - * @param callable $function f(x) callback function - * @param array $args Parameters to pass to callback function. The initial value for the - * parameter of interest must be in this array. - * @param number $target Value of f(x) we a trying to solve for - * @param float $tol Tolerance; How close to the actual solution we would like. - * @param int $position Which element in the $args array will be changed; also serves as initial guess - * @param int $iterations + * @param callable $function f(x) callback function + * @param array $args Parameters to pass to callback function. The initial value for the + * parameter of interest must be in this array. + * @param int|float $target Value of f(x) we a trying to solve for + * @param float $tol Tolerance; How close to the actual solution we would like. + * @param int $position Which element in the $args array will be changed; also serves as initial guess + * @param int $iterations * * @return number * diff --git a/src/NumericalAnalysis/RootFinding/SecantMethod.php b/src/NumericalAnalysis/RootFinding/SecantMethod.php index 9c613b257..3ef5f8abb 100644 --- a/src/NumericalAnalysis/RootFinding/SecantMethod.php +++ b/src/NumericalAnalysis/RootFinding/SecantMethod.php @@ -21,12 +21,12 @@ class SecantMethod * the average change between our initial approximations and moving our * approximations closer to the root. * - * @param callable $function f(x) callback function - * @param number $p₀ First initial approximation - * @param number $p₁ Second initial approximation - * @param number $tol Tolerance; How close to the actual solution we would like. + * @param callable $function f(x) callback function + * @param int|float $p₀ First initial approximation + * @param int|float $p₁ Second initial approximation + * @param int|float $tol Tolerance; How close to the actual solution we would like. * - * @return number + * @return int|float * * @throws Exception\OutOfBoundsException if $tol (the tolerance) is negative * @throws Exception\BadDataException if $p₀ = $p₁ diff --git a/src/NumericalAnalysis/RootFinding/Validation.php b/src/NumericalAnalysis/RootFinding/Validation.php index a3a231015..c0e0bc4fd 100644 --- a/src/NumericalAnalysis/RootFinding/Validation.php +++ b/src/NumericalAnalysis/RootFinding/Validation.php @@ -12,7 +12,7 @@ class Validation /** * Throw an exception if the tolerance is negative. * - * @param number $tol Tolerance; How close to the actual solution we would like. + * @param int|float $tol Tolerance; How close to the actual solution we would like. * * @throws Exception\OutOfBoundsException if $tol (the tolerance) is negative */ @@ -26,8 +26,8 @@ public static function tolerance($tol) /** * Verify that the start and end of of an interval are distinct numbers. * - * @param number $a The start of the interval - * @param number $b The end of the interval + * @param int|float $a The start of the interval + * @param int|float $b The end of the interval * * @throws Exception\BadDataException if $a = $b */ diff --git a/src/Probability/Distribution/Discrete/Zipf.php b/src/Probability/Distribution/Discrete/Zipf.php index 335a01f4e..78ecc794e 100644 --- a/src/Probability/Distribution/Discrete/Zipf.php +++ b/src/Probability/Distribution/Discrete/Zipf.php @@ -42,8 +42,8 @@ class Zipf extends Discrete /** * Constructor * - * @param number $s exponent - * @param int $N elements + * @param int|float $s exponent + * @param int $N elements */ public function __construct($s, int $N) { diff --git a/src/Probability/Distribution/Distribution.php b/src/Probability/Distribution/Distribution.php index 03cefdf62..9b75c455a 100644 --- a/src/Probability/Distribution/Distribution.php +++ b/src/Probability/Distribution/Distribution.php @@ -12,7 +12,7 @@ abstract class Distribution /** * Constructor * - * @param number ...$params + * @param int|float ...$params */ public function __construct(...$params) { diff --git a/src/Sequence/Basic.php b/src/Sequence/Basic.php index 3038207e7..baf846ddb 100644 --- a/src/Sequence/Basic.php +++ b/src/Sequence/Basic.php @@ -68,9 +68,9 @@ public static function arithmeticProgression(int $n, int $d, int $a₁): array * Sequence: 2, 6, 18, 54 * Array index: 0 1 2 3 * - * @param int $n How many numbers in the sequence - * @param number $a Scalar value - * @param number $r Common ratio + * @param int $n How many numbers in the sequence + * @param int|float $a Scalar value + * @param int|float $r Common ratio * * @return array Indexed from 0 (indexes are powers of common ratio) * From dbc2d1d1dca9081782e7660e23eadb3d3663324e Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Fri, 30 Dec 2022 22:59:07 -0800 Subject: [PATCH 24/66] Update CHANGELOG for v.2.7.0. --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6245f4480..43ead575b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # MathPHP Change Log +## v2.7.0 - 2022-12-31 + +### Improvements +* Improved algorithm for `regularizedIncompleteBeta`: Addresses issue 458 +* Issue 456: Improved PHPDoc blocks: Changed "number" to "int|float" +* Added PHP 8.2 for CI test target + ## v2.6.0 - 2022-04-10 ### Improvements From c97386ddb2246bf90ac16f1f2f994adc65eb7ea4 Mon Sep 17 00:00:00 2001 From: Sam <40273116+Aweptimum@users.noreply.github.com> Date: Sat, 31 Dec 2022 17:00:13 -0500 Subject: [PATCH 25/66] Add row/columnAddVector to NumericMatrix (#462) --- src/LinearAlgebra/NumericMatrix.php | 64 +++++++++ .../Numeric/MatrixColumnOperationsTest.php | 127 +++++++++++++++++- .../Numeric/MatrixRowOperationsTest.php | 125 +++++++++++++++++ 3 files changed, 315 insertions(+), 1 deletion(-) diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index 639a6e364..173b61771 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -2366,6 +2366,7 @@ public function rank(): int * - rowDivide * - rowAdd * - rowAddScalar + * - rowAddVector * - rowSubtract * - rowSubtractScalar **************************************************************************/ @@ -2493,6 +2494,37 @@ public function rowAddScalar(int $mᵢ, float $k): NumericMatrix return MatrixFactory::createNumeric($R, $this->ε); } + /** + * Add components of vector v to row mᵢ + * + * @param Vector $v Vector to add to row mᵢ + * @param int $mᵢ Row to add vector $v to + * + * @return NumericMatrix + * + * @throws Exception\MatrixException if row to add does not exist + * @throws Exception\BadParameterException if the vector has a different # of components to the # of columns + * @throws Exception\IncorrectTypeException + */ + public function rowAddVector(Vector $v, int $mᵢ): NumericMatrix + { + if ($mᵢ < 0 || $mᵢ >= $this->m) { + throw new Exception\MatrixException('Row to add does not exist'); + } + if ($v->count() !== $this->m) { + throw new Exception\BadParameterException('Vector is not the same length as matrix columns'); + } + + $n = $this->n; + $R = $this->A; + + for ($j = 0; $j < $n; $j++) { + $R[$mᵢ][$j] += $v[$j]; + } + + return MatrixFactory::createNumeric($R, $this->ε); + } + /** * Subtract k times row mᵢ to row mⱼ * @@ -2554,6 +2586,7 @@ public function rowSubtractScalar(int $mᵢ, float $k): NumericMatrix * COLUMN OPERATIONS - Return a Matrix * - columnMultiply * - columnAdd + * - columnAddVector **************************************************************************/ /** @@ -2617,6 +2650,37 @@ public function columnAdd(int $nᵢ, int $nⱼ, float $k): NumericMatrix return MatrixFactory::createNumeric($R, $this->ε); } + /** + * Add components of vector v to column nᵢ + * + * @param Vector $v Vector to add to column nᵢ + * @param int $nᵢ Column to add vector $v to + * + * @return NumericMatrix + * + * @throws Exception\MatrixException if column to add does not exist + * @throws Exception\BadParameterException if the vector has a different # of components to the # of rows + * @throws Exception\IncorrectTypeException + */ + public function columnAddVector(Vector $v, int $nᵢ): NumericMatrix + { + if ($nᵢ < 0 || $nᵢ >= $this->n) { + throw new Exception\MatrixException('Column to add does not exist'); + } + if ($v->count() !== $this->m) { + throw new Exception\BadParameterException('Vector is not the same length as matrix rows'); + } + + $m = $this->m; + $R = $this->A; + + for ($i = 0; $i < $m; $i++) { + $R[$i][$nᵢ] += $v[$i]; + } + + return MatrixFactory::createNumeric($R, $this->ε); + } + /************************************************************************** * MATRIX REDUCTIONS - Return a Matrix in a reduced form * - ref (row echelon form) diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php index 9641590d5..de870fafa 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php @@ -4,6 +4,7 @@ use MathPHP\LinearAlgebra\MatrixFactory; use MathPHP\Exception; +use MathPHP\LinearAlgebra\Vector; class MatrixColumnOperationsTest extends \PHPUnit\Framework\TestCase { @@ -237,4 +238,128 @@ public function testColumnAddExceptionKIsZero() // When $A->columnAdd(1, 2, 0); } -} + + /** + * @test columnAddVector + * @dataProvider dataProviderForColumnAddVector + * @param array $A + * @param int $nᵢ + * @param array $v + * @param array $expectedMatrix + * @throws \Exception + */ + public function testColumnAddVector(array $A, int $nᵢ, array $v, array $expectedMatrix) + { + // Given + $A = MatrixFactory::createNumeric($A); + $v = new Vector($v); + $expectedMatrix = MatrixFactory::createNumeric($expectedMatrix); + + // When + $R = $A->columnAddVector($v, $nᵢ); + + // Then + $this->assertEquals($expectedMatrix, $R); + } + + /** + * @return array + */ + public function dataProviderForColumnAddVector(): array + { + return [ + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 0, [1,2,3], + [ + [2, 2, 3], + [4, 3, 4], + [6, 4, 5], + ] + ], + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 2, [6,9,12], + [ + [1, 2, 9], + [2, 3, 13], + [3, 4, 17], + ] + ], + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 2, [4,8,12], + [ + [1, 2, 7], + [2, 3, 12], + [3, 4, 17], + ] + ], + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 1, [2.2,3.3,4.4], + [ + [1, 4.2, 3], + [2, 6.3, 4], + [3, 8.4, 5], + ] + ], + ]; + } + + /** + * @test columnAddVector test column n exists + * @throws \Exception + */ + public function testColumnAddVectorExceptionColumnExists() + { + // Given + $A = MatrixFactory::createNumeric([ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ]); + + $b = new Vector([1,2,3]); + + // Then + $this->expectException(Exception\MatrixException::class); + + // When + $A->columnAddVector($b, 4); + } + + /** + * @test columnAddVector test Vector->count() === matrix->m + * @throws \Exception + */ + public function testColumnAddVectorExceptionElementMismatch() + { + // Given + $A = MatrixFactory::createNumeric([ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ]); + + $b = new Vector([1,2,3,4]); + + // Then + $this->expectException(Exception\BadParameterException::class); + + // When + $A->columnAddVector($b, 1); + } +} \ No newline at end of file diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php index ef7c5664f..02657c004 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php @@ -4,6 +4,7 @@ use MathPHP\LinearAlgebra\MatrixFactory; use MathPHP\Exception; +use MathPHP\LinearAlgebra\Vector; class MatrixRowOperationsTest extends \PHPUnit\Framework\TestCase { @@ -408,6 +409,130 @@ public function testRowAddScalarExceptionRowGreaterThanM() $A->rowAddScalar(4, 5); } + /** + * @test rowAddVector + * @dataProvider dataProviderForrowAddVector + * @param array $A + * @param int $mᵢ + * @param array $v + * @param array $expectedMatrix + * @throws \Exception + */ + public function testRowAddVector(array $A, int $mᵢ, array $v, array $expectedMatrix) + { + // Given + $A = MatrixFactory::createNumeric($A); + $v = new Vector($v); + $expectedMatrix = MatrixFactory::createNumeric($expectedMatrix); + + // When + $R = $A->rowAddVector($v, $mᵢ); + + // Then + $this->assertEquals($expectedMatrix, $R); + } + + /** + * @return array + */ + public function dataProviderForRowAddVector(): array + { + return [ + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 0, [1,2,3], + [ + [2, 4, 6], + [2, 3, 4], + [3, 4, 5], + ] + ], + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 2, [6,9,12], + [ + [1, 2, 3], + [2, 3, 4], + [9, 13, 17], + ] + ], + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 2, [4,8,12], + [ + [1, 2, 3], + [2, 3, 4], + [7, 12, 17], + ] + ], + [ + [ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ], 1, [2.2,3.3,4.4], + [ + [1, 2, 3], + [4.2, 6.3, 8.4], + [3, 4, 5], + ] + ], + ]; + } + + /** + * @test rowAddVector test row m exists + * @throws \Exception + */ + public function testRowAddVectorExceptionRowExists() + { + // Given + $A = MatrixFactory::createNumeric([ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ]); + + $b = new Vector([1,2,3]); + + // Then + $this->expectException(Exception\MatrixException::class); + + // When + $A->rowAddVector($b, 4); + } + + /** + * @test rowAddVector test vector->count() === matrix m + * @throws \Exception + */ + public function testRowAddVectorExceptionElementMismatch() + { + // Given + $A = MatrixFactory::createNumeric([ + [1, 2, 3], + [2, 3, 4], + [3, 4, 5], + ]); + + $b = new Vector([1,2,3,4]); + + // Then + $this->expectException(Exception\BadParameterException::class); + + // When + $A->rowAddVector($b, 1); + } + /** * @test rowSubtract * @dataProvider dataProviderForRowSubtract From a435498b0ca1374909ca7f2a1a20d44741bd538e Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 31 Dec 2022 14:06:43 -0800 Subject: [PATCH 26/66] Minor style fix. --- .../LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php index de870fafa..5eaf28098 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php @@ -362,4 +362,4 @@ public function testColumnAddVectorExceptionElementMismatch() // When $A->columnAddVector($b, 1); } -} \ No newline at end of file +} From 21e217c3d056816b44f9965207d5037f60e48ae2 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 31 Dec 2022 14:21:32 -0800 Subject: [PATCH 27/66] Fix precondition column count in rowAddVector. Add additional unit tests. --- src/LinearAlgebra/NumericMatrix.php | 2 +- .../Numeric/MatrixColumnOperationsTest.php | 64 +++++++++++++++-- .../Numeric/MatrixRowOperationsTest.php | 68 +++++++++++++++++-- 3 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index 173b61771..152f0067a 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -2511,7 +2511,7 @@ public function rowAddVector(Vector $v, int $mᵢ): NumericMatrix if ($mᵢ < 0 || $mᵢ >= $this->m) { throw new Exception\MatrixException('Row to add does not exist'); } - if ($v->count() !== $this->m) { + if ($v->count() !== $this->n) { throw new Exception\BadParameterException('Vector is not the same length as matrix columns'); } diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php index 5eaf28098..ebc522b43 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php @@ -244,19 +244,19 @@ public function testColumnAddExceptionKIsZero() * @dataProvider dataProviderForColumnAddVector * @param array $A * @param int $nᵢ - * @param array $v + * @param array $vector * @param array $expectedMatrix * @throws \Exception */ - public function testColumnAddVector(array $A, int $nᵢ, array $v, array $expectedMatrix) + public function testColumnAddVector(array $A, int $nᵢ, array $vector, array $expectedMatrix) { // Given $A = MatrixFactory::createNumeric($A); - $v = new Vector($v); - $expectedMatrix = MatrixFactory::createNumeric($expectedMatrix); + $V = new Vector($vector); + $expectedMatrix = MatrixFactory::create($expectedMatrix); // When - $R = $A->columnAddVector($v, $nᵢ); + $R = $A->columnAddVector($V, $nᵢ); // Then $this->assertEquals($expectedMatrix, $R); @@ -268,6 +268,60 @@ public function testColumnAddVector(array $A, int $nᵢ, array $v, array $expect public function dataProviderForColumnAddVector(): array { return [ + [ + [ + [1], + ], 0, [2], + [ + [3], + ] + ], + [ + [ + [1], + [2], + ], 0, [2, 5], + [ + [3], + [7], + ] + ], + [ + [ + [1, 2], + ], 0, [2], + [ + [3, 2], + ] + ], + [ + [ + [1, 2], + ], 1, [2], + [ + [1, 4], + ] + ], + [ + [ + [1, 2], + [3, 4], + ], 0, [2, 5], + [ + [3, 2], + [8, 4], + ] + ], + [ + [ + [1, 2], + [3, 4], + ], 1, [2, 5], + [ + [1, 4], + [3, 9], + ] + ], [ [ [1, 2, 3], diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php index 02657c004..4ae92692b 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php @@ -411,22 +411,22 @@ public function testRowAddScalarExceptionRowGreaterThanM() /** * @test rowAddVector - * @dataProvider dataProviderForrowAddVector + * @dataProvider dataProviderForRowAddVector * @param array $A * @param int $mᵢ - * @param array $v + * @param array $vector * @param array $expectedMatrix * @throws \Exception */ - public function testRowAddVector(array $A, int $mᵢ, array $v, array $expectedMatrix) + public function testRowAddVector(array $A, int $mᵢ, array $vector, array $expectedMatrix) { // Given $A = MatrixFactory::createNumeric($A); - $v = new Vector($v); - $expectedMatrix = MatrixFactory::createNumeric($expectedMatrix); + $V = new Vector($vector); + $expectedMatrix = MatrixFactory::create($expectedMatrix); // When - $R = $A->rowAddVector($v, $mᵢ); + $R = $A->rowAddVector($V, $mᵢ); // Then $this->assertEquals($expectedMatrix, $R); @@ -438,6 +438,62 @@ public function testRowAddVector(array $A, int $mᵢ, array $v, array $expectedM public function dataProviderForRowAddVector(): array { return [ + [ + [ + [1], + ], 0, [2], + [ + [3], + ] + ], + [ + [ + [1, 2], + ], 0, [2, 5], + [ + [3, 7], + ] + ], + [ + [ + [1], + [2], + ], 0, [2], + [ + [3], + [2], + ] + ], + [ + [ + [1], + [2], + ], 1, [2], + [ + [1], + [4], + ] + ], + [ + [ + [1, 2], + [4, 5], + ], 0, [2, 4], + [ + [3, 6], + [4, 5], + ] + ], + [ + [ + [1, 2], + [4, 5], + ], 1, [2, 4], + [ + [1, 2], + [6, 9], + ] + ], [ [ [1, 2, 3], From cce6f6ba7b723bf47725ab2e88a4e2a9cc42ceb4 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 31 Dec 2022 14:28:26 -0800 Subject: [PATCH 28/66] Minor refactorings. --- src/LinearAlgebra/NumericMatrix.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index 152f0067a..e1ff5387b 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -2497,7 +2497,7 @@ public function rowAddScalar(int $mᵢ, float $k): NumericMatrix /** * Add components of vector v to row mᵢ * - * @param Vector $v Vector to add to row mᵢ + * @param Vector $V Vector to add to row mᵢ * @param int $mᵢ Row to add vector $v to * * @return NumericMatrix @@ -2506,12 +2506,12 @@ public function rowAddScalar(int $mᵢ, float $k): NumericMatrix * @throws Exception\BadParameterException if the vector has a different # of components to the # of columns * @throws Exception\IncorrectTypeException */ - public function rowAddVector(Vector $v, int $mᵢ): NumericMatrix + public function rowAddVector(Vector $V, int $mᵢ): NumericMatrix { if ($mᵢ < 0 || $mᵢ >= $this->m) { - throw new Exception\MatrixException('Row to add does not exist'); + throw new Exception\MatrixException("Row to add to ($mᵢ) does not exist"); } - if ($v->count() !== $this->n) { + if (count($V) !== $this->n) { throw new Exception\BadParameterException('Vector is not the same length as matrix columns'); } @@ -2519,7 +2519,7 @@ public function rowAddVector(Vector $v, int $mᵢ): NumericMatrix $R = $this->A; for ($j = 0; $j < $n; $j++) { - $R[$mᵢ][$j] += $v[$j]; + $R[$mᵢ][$j] += $V[$j]; } return MatrixFactory::createNumeric($R, $this->ε); @@ -2653,7 +2653,7 @@ public function columnAdd(int $nᵢ, int $nⱼ, float $k): NumericMatrix /** * Add components of vector v to column nᵢ * - * @param Vector $v Vector to add to column nᵢ + * @param Vector $V Vector to add to column nᵢ * @param int $nᵢ Column to add vector $v to * * @return NumericMatrix @@ -2662,12 +2662,12 @@ public function columnAdd(int $nᵢ, int $nⱼ, float $k): NumericMatrix * @throws Exception\BadParameterException if the vector has a different # of components to the # of rows * @throws Exception\IncorrectTypeException */ - public function columnAddVector(Vector $v, int $nᵢ): NumericMatrix + public function columnAddVector(Vector $V, int $nᵢ): NumericMatrix { if ($nᵢ < 0 || $nᵢ >= $this->n) { - throw new Exception\MatrixException('Column to add does not exist'); + throw new Exception\MatrixException("Column to add to ($nᵢ) does not exist"); } - if ($v->count() !== $this->m) { + if (count($V) !== $this->m) { throw new Exception\BadParameterException('Vector is not the same length as matrix rows'); } @@ -2675,7 +2675,7 @@ public function columnAddVector(Vector $v, int $nᵢ): NumericMatrix $R = $this->A; for ($i = 0; $i < $m; $i++) { - $R[$i][$nᵢ] += $v[$i]; + $R[$i][$nᵢ] += $V[$i]; } return MatrixFactory::createNumeric($R, $this->ε); From e44a7f8361b74817d743a8275d366b10586ee2b1 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 31 Dec 2022 14:34:27 -0800 Subject: [PATCH 29/66] Change order of parameters in rowAddVector and columnAddVector to be consistent with other row and column operations. --- src/LinearAlgebra/NumericMatrix.php | 12 ++++++------ .../Matrix/Numeric/MatrixColumnOperationsTest.php | 6 +++--- .../Matrix/Numeric/MatrixRowOperationsTest.php | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index e1ff5387b..1c44faddb 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -2495,10 +2495,10 @@ public function rowAddScalar(int $mᵢ, float $k): NumericMatrix } /** - * Add components of vector v to row mᵢ + * Add components of vector V to row mᵢ * - * @param Vector $V Vector to add to row mᵢ * @param int $mᵢ Row to add vector $v to + * @param Vector $V Vector to add to row mᵢ * * @return NumericMatrix * @@ -2506,7 +2506,7 @@ public function rowAddScalar(int $mᵢ, float $k): NumericMatrix * @throws Exception\BadParameterException if the vector has a different # of components to the # of columns * @throws Exception\IncorrectTypeException */ - public function rowAddVector(Vector $V, int $mᵢ): NumericMatrix + public function rowAddVector(int $mᵢ, Vector $V): NumericMatrix { if ($mᵢ < 0 || $mᵢ >= $this->m) { throw new Exception\MatrixException("Row to add to ($mᵢ) does not exist"); @@ -2651,10 +2651,10 @@ public function columnAdd(int $nᵢ, int $nⱼ, float $k): NumericMatrix } /** - * Add components of vector v to column nᵢ + * Add components of vector V to column nᵢ * - * @param Vector $V Vector to add to column nᵢ * @param int $nᵢ Column to add vector $v to + * @param Vector $V Vector to add to column nᵢ * * @return NumericMatrix * @@ -2662,7 +2662,7 @@ public function columnAdd(int $nᵢ, int $nⱼ, float $k): NumericMatrix * @throws Exception\BadParameterException if the vector has a different # of components to the # of rows * @throws Exception\IncorrectTypeException */ - public function columnAddVector(Vector $V, int $nᵢ): NumericMatrix + public function columnAddVector(int $nᵢ, Vector $V): NumericMatrix { if ($nᵢ < 0 || $nᵢ >= $this->n) { throw new Exception\MatrixException("Column to add to ($nᵢ) does not exist"); diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php index ebc522b43..cc5dd7d4c 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixColumnOperationsTest.php @@ -256,7 +256,7 @@ public function testColumnAddVector(array $A, int $nᵢ, array $vector, array $e $expectedMatrix = MatrixFactory::create($expectedMatrix); // When - $R = $A->columnAddVector($V, $nᵢ); + $R = $A->columnAddVector($nᵢ, $V); // Then $this->assertEquals($expectedMatrix, $R); @@ -392,7 +392,7 @@ public function testColumnAddVectorExceptionColumnExists() $this->expectException(Exception\MatrixException::class); // When - $A->columnAddVector($b, 4); + $A->columnAddVector(4, $b); } /** @@ -414,6 +414,6 @@ public function testColumnAddVectorExceptionElementMismatch() $this->expectException(Exception\BadParameterException::class); // When - $A->columnAddVector($b, 1); + $A->columnAddVector(1, $b); } } diff --git a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php index 4ae92692b..ddcf33fab 100644 --- a/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php +++ b/tests/LinearAlgebra/Matrix/Numeric/MatrixRowOperationsTest.php @@ -426,7 +426,7 @@ public function testRowAddVector(array $A, int $mᵢ, array $vector, array $expe $expectedMatrix = MatrixFactory::create($expectedMatrix); // When - $R = $A->rowAddVector($V, $mᵢ); + $R = $A->rowAddVector($mᵢ, $V); // Then $this->assertEquals($expectedMatrix, $R); @@ -564,7 +564,7 @@ public function testRowAddVectorExceptionRowExists() $this->expectException(Exception\MatrixException::class); // When - $A->rowAddVector($b, 4); + $A->rowAddVector(4, $b); } /** @@ -586,7 +586,7 @@ public function testRowAddVectorExceptionElementMismatch() $this->expectException(Exception\BadParameterException::class); // When - $A->rowAddVector($b, 1); + $A->rowAddVector(1, $b); } /** From e20d66b31bf8afff19500072c57b00de79e54462 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 31 Dec 2022 14:36:34 -0800 Subject: [PATCH 30/66] Update README: Add rowAddVector and columnAddVector to Matrix. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index faa3741d5..6f0c29298 100644 --- a/README.md +++ b/README.md @@ -449,6 +449,7 @@ $R = $A->rowMultiply($mᵢ, $k); // Multiply row mᵢ by k $R = $A->rowDivide($mᵢ, $k); // Divide row mᵢ by k $R = $A->rowAdd($mᵢ, $mⱼ, $k); // Add k * row mᵢ to row mⱼ $R = $A->rowAddScalar($mᵢ, $k); // Add k to each item of row mᵢ +$R = $A->rowAddVector($mᵢ, $V); // Add Vector V to row mᵢ $R = $A->rowSubtract($mᵢ, $mⱼ, $k); // Subtract k * row mᵢ from row mⱼ $R = $A->rowSubtractScalar($mᵢ, $k); // Subtract k from each item of row mᵢ @@ -458,6 +459,7 @@ $R = $A->columnInterchange($nᵢ, $nⱼ); $R = $A->columnExclude($nᵢ); // Exclude column $nᵢ $R = $A->columnMultiply($nᵢ, $k); // Multiply column nᵢ by k $R = $A->columnAdd($nᵢ, $nⱼ, $k); // Add k * column nᵢ to column nⱼ +$R = $A->columnAddVector($nᵢ, $V); // Add Vector V to column nᵢ // Matrix augmentations - return a new Matrix $⟮A∣B⟯ = $A->augment($B); // Augment on the right - standard augmentation From b55d8d619cb6f355073a664cf5a939b78b95af73 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 31 Dec 2022 14:44:10 -0800 Subject: [PATCH 31/66] Update CHANGELOG for v2.8.0. --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43ead575b..04d0f3181 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # MathPHP Change Log +## v2.8.0 - TBD + +### New Features +* Matrix `rowAddVector` +* Matrix `columnAddVector` + +### Improvements + ## v2.7.0 - 2022-12-31 ### Improvements From 5fea15afd4394dcc39a8b4e405ac8fd801ffe5db Mon Sep 17 00:00:00 2001 From: Smoren Date: Wed, 1 Feb 2023 10:02:56 +0300 Subject: [PATCH 32/66] NonInteger::hyperharmonic(): bug fix (#463) * `NonInteger::hyperharmonic()` catch \Error for maximum function nesting level recursion errors. --- src/Sequence/NonInteger.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Sequence/NonInteger.php b/src/Sequence/NonInteger.php index 4d8c4cd30..a11b4cf64 100644 --- a/src/Sequence/NonInteger.php +++ b/src/Sequence/NonInteger.php @@ -79,6 +79,8 @@ public static function generalizedHarmonic(int $n, float $m): array * @param bool $rational return results as a Rational object * * @return float[]|Rational[] + * + * @throws Exception\OutOfBoundsException */ public static function hyperharmonic(int $n, int $r, $rational = false): array { @@ -106,6 +108,8 @@ public static function hyperharmonic(int $n, int $r, $rational = false): array } } catch (\TypeError $e) { throw new Exception\OutOfBoundsException('Numbers too large to maintain integer precision', -1, $e); + } catch (\Error $e) { + throw new Exception\OutOfBoundsException("Recursion depth level error: {$e->getMessage()}", -2, $e); } if ($rational == true) { From 7795af2a20cc24af11766c56356fe003689a9ede Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 31 Jan 2023 23:15:16 -0800 Subject: [PATCH 33/66] Consolidate exception and error messages. --- CHANGELOG.md | 3 +++ src/Sequence/NonInteger.php | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d0f3181..0c0e89e65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ * Matrix `rowAddVector` * Matrix `columnAddVector` +### Improvements +* Better error handling and exception message in `Sequence\NonIntenger::hyperharmonic` + ### Improvements ## v2.7.0 - 2022-12-31 diff --git a/src/Sequence/NonInteger.php b/src/Sequence/NonInteger.php index a11b4cf64..e7445c0c7 100644 --- a/src/Sequence/NonInteger.php +++ b/src/Sequence/NonInteger.php @@ -106,10 +106,8 @@ public static function hyperharmonic(int $n, int $r, $rational = false): array $sequence[$k] = $∑; } } - } catch (\TypeError $e) { - throw new Exception\OutOfBoundsException('Numbers too large to maintain integer precision', -1, $e); - } catch (\Error $e) { - throw new Exception\OutOfBoundsException("Recursion depth level error: {$e->getMessage()}", -2, $e); + } catch (\TypeError|\Error $e) { + throw new Exception\OutOfBoundsException("Numbers too large to maintain integer precision for hyperharmonic, or recursion depth level exceeded (n:$n, r:$r): " . $e->getMessage(), -1, $e); } if ($rational == true) { From 9ca59962425a8913c01b5edaa1eeec23130e51c6 Mon Sep 17 00:00:00 2001 From: Smoren Date: Wed, 26 Apr 2023 06:11:40 +0300 Subject: [PATCH 34/66] PHPdoc annotations added, phpstan works without errors now (#465) --- .github/workflows/test_develop_and_master.yml | 3 + .github/workflows/test_other_branches.yml | 3 + .github/workflows/test_pull_request.yml | 3 + src/Algebra.php | 29 +++- src/Arithmetic.php | 8 +- src/Expression/Piecewise.php | 17 ++- src/Expression/Polynomial.php | 28 ++-- src/Finance.php | 24 +-- src/Functions/BaseEncoderDecoder.php | 9 -- src/Functions/Bitwise.php | 2 +- src/Functions/Map/Multi.php | 26 ++-- src/Functions/Map/Single.php | 62 ++++---- src/Functions/Support.php | 10 +- src/InformationTheory/Entropy.php | 20 +-- src/LinearAlgebra/ComplexMatrix.php | 6 +- src/LinearAlgebra/Decomposition/Cholesky.php | 1 + src/LinearAlgebra/Decomposition/Crout.php | 2 + .../Decomposition/Decomposition.php | 4 + src/LinearAlgebra/Decomposition/LU.php | 25 ++-- src/LinearAlgebra/Decomposition/QR.php | 4 +- src/LinearAlgebra/Eigenvalue.php | 8 +- src/LinearAlgebra/Eigenvector.php | 15 +- src/LinearAlgebra/FunctionMatrix.php | 10 +- src/LinearAlgebra/Matrix.php | 121 +++++++++------ src/LinearAlgebra/MatrixCatalog.php | 37 +++-- src/LinearAlgebra/MatrixFactory.php | 40 +++-- src/LinearAlgebra/NumericDiagonalMatrix.php | 2 +- src/LinearAlgebra/NumericMatrix.php | 28 +++- src/LinearAlgebra/NumericSquareMatrix.php | 2 +- src/LinearAlgebra/ObjectMatrix.php | 31 +++- .../Reduction/ReducedRowEchelonForm.php | 2 +- .../Reduction/RowEchelonForm.php | 8 +- src/LinearAlgebra/Vector.php | 59 +++++--- src/Number/Complex.php | 3 +- src/Number/ObjectArithmetic.php | 4 +- src/Number/Quaternion.php | 4 + src/Number/Rational.php | 13 +- src/NumberTheory/Integer.php | 6 +- .../Interpolation/ClampedCubicSpline.php | 61 ++++---- .../Interpolation/Interpolation.php | 26 ++-- .../Interpolation/LagrangePolynomial.php | 22 +-- .../Interpolation/NaturalCubicSpline.php | 25 ++-- .../Interpolation/NevillesMethod.php | 25 ++-- .../Interpolation/NewtonPolynomialForward.php | 22 +-- .../Interpolation/RegularGridInterpolator.php | 42 +++--- .../FivePointFormula.php | 28 ++-- .../NumericalDifferentiation.php | 48 +++--- .../SecondDerivativeMidpointFormula.php | 28 ++-- .../ThreePointFormula.php | 28 ++-- .../NumericalIntegration/BoolesRule.php | 22 +-- .../NumericalIntegration/MidpointRule.php | 22 +-- .../NumericalIntegration.php | 35 +++-- .../NumericalIntegration/RectangleMethod.php | 22 +-- .../NumericalIntegration/SimpsonsRule.php | 22 +-- .../SimpsonsThreeEighthsRule.php | 22 +-- .../NumericalIntegration/TrapezoidalRule.php | 22 +-- .../NumericalIntegration/Validation.php | 10 +- .../RootFinding/BisectionMethod.php | 2 +- .../RootFinding/FixedPointIteration.php | 2 +- .../RootFinding/NewtonsMethod.php | 14 +- .../RootFinding/Validation.php | 4 +- .../Distribution/Continuous/Beta.php | 4 +- .../Distribution/Continuous/Cauchy.php | 4 +- .../Distribution/Continuous/ChiSquared.php | 4 +- .../Distribution/Continuous/Continuous.php | 3 + .../Continuous/ContinuousDistribution.php | 2 +- .../Distribution/Continuous/DiracDelta.php | 4 +- .../Distribution/Continuous/Exponential.php | 4 +- src/Probability/Distribution/Continuous/F.php | 4 +- .../Distribution/Continuous/Gamma.php | 4 +- .../Distribution/Continuous/Laplace.php | 4 +- .../Distribution/Continuous/LogLogistic.php | 4 +- .../Distribution/Continuous/LogNormal.php | 4 +- .../Distribution/Continuous/Logistic.php | 4 +- .../Distribution/Continuous/NoncentralT.php | 4 +- .../Distribution/Continuous/Normal.php | 4 +- .../Distribution/Continuous/Pareto.php | 4 +- .../Continuous/StandardNormal.php | 6 +- .../Distribution/Continuous/StudentT.php | 4 +- .../Distribution/Continuous/Uniform.php | 4 +- .../Distribution/Continuous/Weibull.php | 4 +- .../Distribution/Discrete/Bernoulli.php | 4 +- .../Distribution/Discrete/Binomial.php | 4 +- .../Distribution/Discrete/Categorical.php | 10 +- .../Distribution/Discrete/Geometric.php | 4 +- .../Distribution/Discrete/Hypergeometric.php | 4 +- .../Discrete/NegativeBinomial.php | 4 +- .../Distribution/Discrete/Poisson.php | 10 +- .../Discrete/ShiftedGeometric.php | 4 +- .../Distribution/Discrete/Uniform.php | 4 +- .../Distribution/Multivariate/Dirichlet.php | 4 +- .../Multivariate/Hypergeometric.php | 13 +- .../Distribution/Multivariate/Multinomial.php | 6 +- .../Distribution/Multivariate/Normal.php | 7 +- .../Distribution/Table/ChiSquared.php | 3 +- .../Distribution/Table/StandardNormal.php | 140 +++++++++--------- .../Distribution/Table/TDistribution.php | 8 +- src/SampleData/Cereal.php | 13 +- src/SampleData/Iris.php | 3 +- src/SampleData/MtCars.php | 11 +- src/SampleData/People.php | 41 +++-- src/SampleData/PlantGrowth.php | 7 +- src/SampleData/ToothGrowth.php | 9 +- src/SampleData/UsArrests.php | 16 +- src/Search.php | 29 +++- src/Sequence/Advanced.php | 37 +++-- src/Sequence/Basic.php | 18 +-- src/SetTheory/ImmutableSet.php | 4 +- src/SetTheory/Set.php | 23 ++- src/Statistics/ANOVA.php | 8 +- src/Statistics/Average.php | 40 +++-- src/Statistics/Circular.php | 21 ++- src/Statistics/Correlation.php | 70 +++++---- src/Statistics/Descriptive.php | 62 ++++++-- src/Statistics/Distance.php | 20 +-- src/Statistics/Distribution.php | 41 ++--- src/Statistics/Divergence.php | 8 +- src/Statistics/Experiment.php | 24 ++- src/Statistics/KernelDensityEstimation.php | 4 +- src/Statistics/Multivariate/PCA.php | 8 +- src/Statistics/Multivariate/PLS.php | 68 ++++++--- src/Statistics/Outlier.php | 2 +- src/Statistics/RandomVariable.php | 14 +- src/Statistics/Regression/LOESS.php | 12 +- src/Statistics/Regression/Linear.php | 24 --- .../Regression/LinearThroughPoint.php | 4 +- .../Regression/Methods/LeastSquares.php | 53 +++++-- .../Methods/WeightedLeastSquares.php | 8 +- .../Regression/Models/LinearModel.php | 8 +- .../Regression/Models/MichaelisMenten.php | 8 +- .../Regression/Models/PowerModel.php | 11 +- .../Regression/ParametricRegression.php | 15 +- src/Statistics/Regression/Regression.php | 16 +- src/Statistics/Regression/WeightedLinear.php | 6 +- src/Statistics/Significance.php | 100 ++++++++++--- src/Trigonometry.php | 2 +- src/Util/Iter.php | 6 +- 137 files changed, 1483 insertions(+), 932 deletions(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index 259399561..f9a5a0451 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -56,6 +56,9 @@ jobs: - name: PHP Code Sniffer run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + - name: Static analysis + run: ./vendor/bin/phpstan analyze --level max src/ + code-coverage: name: Code coverage runs-on: ubuntu-latest diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index cd82afd7b..c198d4f28 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -54,3 +54,6 @@ jobs: - name: PHP Code Sniffer run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + + - name: Static analysis + run: ./vendor/bin/phpstan analyze --level max src/ diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index 4c0150702..bff052c4b 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -52,6 +52,9 @@ jobs: - name: PHP Code Sniffer run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + - name: Static analysis + run: ./vendor/bin/phpstan analyze --level max src/ + code-coverage: name: Code coverage runs-on: ubuntu-latest diff --git a/src/Algebra.php b/src/Algebra.php index e57a223e8..6da542a37 100644 --- a/src/Algebra.php +++ b/src/Algebra.php @@ -48,7 +48,7 @@ public static function gcd(int $a, int $b): int * @param int $a * @param int $b * - * @return array [gcd, a', b'] + * @return array{int, int, int} [gcd, a', b'] */ public static function extendedGcd(int $a, int $b): array { @@ -120,7 +120,7 @@ public static function lcm(int $a, int $b): int * - push on the product of each set * * @param int $x - * @return array of factors + * @return array of factors * * @throws Exception\OutOfBoundsException if n is < 1 */ @@ -236,10 +236,11 @@ public static function linear(float $a, float $b): ?float * @param float $c constant coefficient * @param bool $return_complex Whether to return complex numbers or NANs if imaginary roots * - * @return float[]|Complex[] [x₁, x₂] roots of the equation, or - * [NAN, NAN] if discriminant is negative, or - * [Complex, Complex] if discriminant is negative and complex option is on or - * [x] if a = 0 and formula isn't quadratics + * @return array{0: float|Complex, 1?: float|Complex} + * [x₁, x₂] roots of the equation, or + * [NAN, NAN] if discriminant is negative, or + * [Complex, Complex] if discriminant is negative and complex option is on or + * [x] if a = 0 and formula isn't quadratics * * @throws Exception\IncorrectTypeException */ @@ -366,8 +367,9 @@ public static function discriminant(float $a, float $b, float $c): float * @param float $a₀ constant coefficient * @param bool $return_complex whether to return complex numbers * - * @return float[]|Complex[] array of roots (three real roots, or one real root and two NANs because complex numbers not yet supported) - * (If $a₃ = 0, then only two roots of quadratic equation) + * @return array{0: float|Complex, 1?: float|Complex, 2?: float|Complex} + * array of roots (three real roots, or one real root and two NANs because complex numbers not yet supported) + * (If $a₃ = 0, then only two roots of quadratic equation) * * @throws Exception\IncorrectTypeException */ @@ -473,6 +475,7 @@ public static function quartic(float $a₄, float $a₃, float $a₂, float $a // Sort so any complex roots are at the end of the array. \rsort($quadratic_roots); + /** @var array{float, float} $quadratic_roots */ $z₊ = $quadratic_roots[0]; $z₋ = $quadratic_roots[1]; if (!$return_complex) { @@ -482,8 +485,10 @@ public static function quartic(float $a₄, float $a₃, float $a₂, float $a $Cz₊ = new Complex($z₊, 0); $Cz₋ = new Complex($z₋, 0); $z₁ = $z₊ < 0 ? $Cz₊->sqrt() : \sqrt($z₊); + // @phpstan-ignore-next-line $z₂ = $z₊ < 0 ? $z₁->negate() : $z₁ * -1; $z₃ = $z₋ < 0 ? $Cz₋->sqrt() : \sqrt($z₋); + // @phpstan-ignore-next-line $z₄ = $z₋ < 0 ? $z₃->negate() : $z₃ * -1; return [$z₁, $z₂, $z₃, $z₄]; @@ -501,9 +506,13 @@ public static function quartic(float $a₄, float $a₃, float $a₂, float $a // $z₁ will always be a real number, so select it. $m = $cubic_roots[0]; + // @phpstan-ignore-next-line (because $m is real) $roots1 = self::quadratic(1, \sqrt(2 * $m), $p / 2 + $m - $q / 2 / \sqrt(2 * $m), $return_complex); + // @phpstan-ignore-next-line (because $m is real) $roots2 = self::quadratic(1, -1 * \sqrt(2 * $m), $p / 2 + $m + $q / 2 / \sqrt(2 * $m), $return_complex); + // @phpstan-ignore-next-line (because $m is real) $discriminant1 = self::discriminant(1, \sqrt(2 * $m), $p / 2 + $m - $q / 2 / \sqrt(2 * $m)); + // @phpstan-ignore-next-line (because $m is real) $discriminant2 = self::discriminant(1, -1 * \sqrt(2 * $m), $p / 2 + $m + $q / 2 / \sqrt(2 * $m)); // sort the real roots first. @@ -522,6 +531,10 @@ public static function quartic(float $a₄, float $a₃, float $a₂, float $a // The roots for this polynomial are the roots of the depressed polynomial minus a₃/4. if (!$return_complex) { + /** + * FIXME: are the roots real? Single::subtract() works with real numbers only. + * @phpstan-ignore-next-line + */ return Single::subtract($depressed_quartic_roots, $a₃ / 4); } diff --git a/src/Arithmetic.php b/src/Arithmetic.php index 539fa6276..39e582370 100644 --- a/src/Arithmetic.php +++ b/src/Arithmetic.php @@ -2,6 +2,8 @@ namespace MathPHP; +use MathPHP\Exception\BadParameterException; + class Arithmetic { /** @@ -49,13 +51,15 @@ public static function cubeRoot(float $x): float * @param float $x * * @return int + * + * @throws BadParameterException */ public static function isqrt(float $x): int { if ($x < 0) { throw new Exception\BadParameterException("x must be non-negative for isqrt - got $x"); } - return \floor(\sqrt($x)); + return (int)\floor(\sqrt($x)); } /** @@ -174,6 +178,6 @@ public static function modulo(int $a, int $n): int return $a; } - return $a - $n * \floor($a / $n); + return (int)($a - $n * \floor($a / $n)); } } diff --git a/src/Expression/Piecewise.php b/src/Expression/Piecewise.php index 3766a4579..22dd13015 100644 --- a/src/Expression/Piecewise.php +++ b/src/Expression/Piecewise.php @@ -11,10 +11,10 @@ */ class Piecewise { - /** @var array */ + /** @var array */ private $intervals; - /** @var array */ + /** @var array */ private $functions; /** @@ -41,9 +41,10 @@ class Piecewise * a start and end-point, the point must be closed on both sides. Also, * we cannot start or end an interval in the middle of another interval. * - * @param array $intervals Array of intervals - * Example: [[-10, 0, false, true], [0, 2], [3, 10]] - * @param array $functions Array of callback functions + * @param array $intervals + * Array of intervals + * Example: [[-10, 0, false, true], [0, 2], [3, 10]] + * @param array $functions Array of callback functions * * @throws Exception\BadDataException if the number of intervals and functions are not the same * @throws Exception\BadDataException if any function in $functions is not callable @@ -70,6 +71,7 @@ public function __construct(array $intervals, array $functions) $lastB = $b ?? -\INF; $lastBOpen = $bOpen ?? false; + // @phpstan-ignore-next-line (Strict comparison using !== between 2 and 2 will always evaluate to false.) if (\count(\array_filter($interval, '\is_numeric')) !== 2) { throw new Exception\BadDataException('Each interval must contain two numbers.'); } @@ -198,8 +200,8 @@ private function closedClosed(bool $aOpen, bool $bOpen): bool * - Same number of intervals as functions * - All functions are callable * - * @param array $intervals - * @param array $functions + * @param array $intervals + * @param array $functions * * @return void * @@ -212,6 +214,7 @@ private function constructorPreconditions(array $intervals, array $functions) throw new Exception\BadDataException('For a piecewise function you must provide the same number of intervals as functions.'); } + // @phpstan-ignore-next-line (Parameter #2 $callback of function array_filter expects callable(callable(): mixed): mixed, '\\is_callable' given.) if (\count(\array_filter($functions, '\is_callable')) !== \count($intervals)) { throw new Exception\BadDataException('Not every function provided is valid. Ensure that each function is callable.'); } diff --git a/src/Expression/Polynomial.php b/src/Expression/Polynomial.php index 0ee6d237a..e81612523 100644 --- a/src/Expression/Polynomial.php +++ b/src/Expression/Polynomial.php @@ -9,6 +9,7 @@ use MathPHP\LinearAlgebra\MatrixFactory; use MathPHP\LinearAlgebra\NumericSquareMatrix; use MathPHP\LinearAlgebra\Vector; +use MathPHP\Number\Complex; use MathPHP\Number\ObjectArithmetic; /** @@ -55,14 +56,14 @@ class Polynomial implements ObjectArithmetic /** @var int */ private $degree; - /** @var array */ + /** @var array */ private $coefficients; /** @var string */ private $variable; /** - * @var array Unicode characters for exponents + * @var array Unicode characters for exponents */ private const SYMBOLS = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹']; @@ -70,7 +71,7 @@ class Polynomial implements ObjectArithmetic * When a polynomial is instantiated, set the coefficients and degree of * that polynomial as its object parameters. * - * @param array $coefficients An array of coefficients in decreasing powers + * @param array $coefficients An array of coefficients in decreasing powers * Example: new Polynomial([1, 2, 3]) will create * a polynomial that looks like x² + 2x + 3. * @param string $variable @@ -214,11 +215,13 @@ private function checkNumericOrPolynomial($input): Polynomial if ($input instanceof Polynomial) { return $input; } elseif (\is_numeric($input)) { + /** @var number $input */ return new Polynomial([$input]); } else { throw new Exception\IncorrectTypeException('Input must be a Polynomial or a number'); } } + /** * Getter method for the degree of a polynomial * @@ -232,7 +235,7 @@ public function getDegree(): int /** * Getter method for the coefficients of a polynomial * - * @return array The coefficients array of a polynomial object + * @return array The coefficients array of a polynomial object */ public function getCoefficients(): array { @@ -254,7 +257,7 @@ public function getVariable(): string * * @param string $variable The new dependent variable of a polynomial object */ - public function setVariable(string $variable) + public function setVariable(string $variable): void { $this->variable = $variable; } @@ -386,6 +389,7 @@ public function multiply($polynomial): Polynomial $coefficientsB = \array_reverse($polynomial->coefficients); // Start with an array of coefficients that all equal 0 + /** @var array $productCoefficients */ $productCoefficients = \array_fill(0, $productDegree + 1, 0); // Iterate through the product of terms component-wise @@ -422,23 +426,27 @@ public function negate(): Polynomial * * Closed form solutions only exist if the degree is less than 5 * - * @return array of roots + * @return array of roots * * @throws Exception\IncorrectTypeException */ public function roots(): array { + $floatCoefficients = array_map(static function ($coefficient) { + return (float)$coefficient; + }, $this->coefficients); + switch ($this->degree) { case 0: return [null]; case 1: - return [Algebra::linear(...$this->coefficients)]; + return [Algebra::linear(...$floatCoefficients)]; case 2: - return Algebra::quadratic(...$this->coefficients); + return Algebra::quadratic(...$floatCoefficients); case 3: - return Algebra::cubic(...$this->coefficients); + return Algebra::cubic(...$floatCoefficients); case 4: - return Algebra::quartic(...$this->coefficients); + return Algebra::quartic(...$floatCoefficients); default: return [\NAN]; } diff --git a/src/Finance.php b/src/Finance.php index 6d2abfce6..f40d12837 100644 --- a/src/Finance.php +++ b/src/Finance.php @@ -2,6 +2,8 @@ namespace MathPHP; +use MathPHP\Exception\OutOfBoundsException; + /** * General references on financial functions and formulas: * - Open Document Format for Office Applications (OpenDocument) Version 1.2 Part 2: @@ -449,7 +451,7 @@ public static function pv(float $rate, int $periods, float $payment, float $futu * npv(0.03, [-1000, 100, 500, 300, 700, 700]) * * @param float $rate - * @param array $values + * @param array $values * * @return float */ @@ -519,13 +521,15 @@ public static function rate(float $periods, float $payment, float $present_value * irr([-100, 50, 40, 30]) * * Solves for NPV=0 using Newton's Method. - * @todo: Use eigenvalues to find the roots of a characteristic polynomial. - * This will allow finding all solutions and eliminate the need of the initial_guess. - * - * @param array $values - * @param float $initial_guess + * @param array $values + * @param float $initial_guess * * @return float + * + * @throws OutOfBoundsException + * + * @todo: Use eigenvalues to find the roots of a characteristic polynomial. + * This will allow finding all solutions and eliminate the need of the initial_guess. */ public static function irr(array $values, float $initial_guess = 0.1): float { @@ -551,7 +555,7 @@ public static function irr(array $values, float $initial_guess = 0.1): float * * Based off of Better: https://github.com/better/irr * - * @param array $values + * @param array $values * * @return float */ @@ -606,7 +610,7 @@ private static function alternateIrr(array $values): float * with returns of $50, $40, and $30 reinvested at 10%: * mirr([-100, 50, 40, 30], 0.05, 0.10) * - * @param array $values + * @param array $values * @param float $finance_rate * @param float $reinvestment_rate * @@ -674,7 +678,7 @@ public static function mirr(array $values, float $finance_rate, float $reinvestm * of $100, $200, $300, $400, $500, and a discount rate of 0.10: * payback([-1000, 100, 200, 300, 400, 500], 0.1) * - * @param array $values + * @param array $values * @param float $rate * * @return float @@ -740,7 +744,7 @@ public static function payback(array $values, float $rate = 0.0): float * returns of $50, $50, $50 with a 10% discount rate: * profitabilityIndex([-100, 50, 50, 50], 0.10) * - * @param array $values + * @param array $values * @param float $rate * * @return float diff --git a/src/Functions/BaseEncoderDecoder.php b/src/Functions/BaseEncoderDecoder.php index 87f261079..7f9a0ac58 100644 --- a/src/Functions/BaseEncoderDecoder.php +++ b/src/Functions/BaseEncoderDecoder.php @@ -10,15 +10,6 @@ */ class BaseEncoderDecoder { - /** string alphabet of base 64 numbers */ - private const RFC3548_BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - - /** string alphabet of file safe base 64 numbers */ - private const RFC3548_BASE64_FILE_SAFE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; - - /** string alphabet of base 32 numbers */ - private const RFC3548_BASE32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; - /** * Get the default alphabet for a given number base * diff --git a/src/Functions/Bitwise.php b/src/Functions/Bitwise.php index 14d778a8b..3486dff9f 100644 --- a/src/Functions/Bitwise.php +++ b/src/Functions/Bitwise.php @@ -40,7 +40,7 @@ class Bitwise * @param int $a * @param int $b * - * @return array + * @return array{overflow: bool, value: int|float} * 'overflow' is true if the result is larger than the bits in an int * 'value' is the result of the addition ignoring any overflow. */ diff --git a/src/Functions/Map/Multi.php b/src/Functions/Map/Multi.php index 69c65e649..023c5d380 100644 --- a/src/Functions/Map/Multi.php +++ b/src/Functions/Map/Multi.php @@ -14,9 +14,9 @@ class Multi * * [x₁ + y₁, x₂ + y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -42,9 +42,9 @@ public static function add(array ...$arrays): array * * [x₁ - y₁, x₂ - y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -75,9 +75,9 @@ function ($x) { * * [x₁ * y₁, x₂ * y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -103,9 +103,9 @@ public static function multiply(array ...$arrays): array * * [x₁ / y₁, x₂ / y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -136,9 +136,9 @@ function ($x) { * * [max(x₁, y₁), max(x₂, y₂), ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -169,9 +169,9 @@ function ($x) { * * [max(x₁, y₁), max(x₂, y₂), ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -204,7 +204,7 @@ function ($x) { /** * Check that two or more arrays are all the same length * - * @param array[] $arrays + * @param array> $arrays * * @return bool * diff --git a/src/Functions/Map/Single.php b/src/Functions/Map/Single.php index 37407227d..f9a20feb6 100644 --- a/src/Functions/Map/Single.php +++ b/src/Functions/Map/Single.php @@ -12,10 +12,10 @@ class Single /** * Map addition * - * @param array $xs - * @param int|float $k Number to add to each element + * @param array $xs + * @param int|float $k Number to add to each element * - * @return array + * @return array */ public static function add(array $xs, $k): array { @@ -30,10 +30,10 @@ function ($x) use ($k) { /** * Map subtract * - * @param array $xs - * @param int|float $k Number to subtract from each element + * @param array $xs + * @param int|float $k Number to subtract from each element * - * @return array + * @return array */ public static function subtract(array $xs, $k): array { @@ -48,10 +48,10 @@ function ($x) use ($k) { /** * Map multiply * - * @param array $xs - * @param int|float $k Number to multiply to each element + * @param array $xs + * @param int|float $k Number to multiply to each element * - * @return array + * @return array */ public static function multiply(array $xs, $k): array { @@ -66,10 +66,10 @@ function ($x) use ($k) { /** * Map Divide * - * @param array $xs - * @param int|float $k Number to divide each element by + * @param array $xs + * @param int|float $k Number to divide each element by * - * @return array + * @return array */ public static function divide(array $xs, $k): array { @@ -84,9 +84,9 @@ function ($x) use ($k) { /** * Map square * - * @param array $xs + * @param array $xs * - * @return array + * @return array */ public static function square(array $xs): array { @@ -101,9 +101,9 @@ function ($x) { /** * Map cube * - * @param array $xs + * @param array $xs * - * @return array + * @return array */ public static function cube(array $xs): array { @@ -119,9 +119,9 @@ function ($x) { * Map reciprocal * x := 1/x * - * @param array $xs + * @param array $xs * - * @return array + * @return array * * @throws Exception\BadDataException if 0 is one of the numbers */ @@ -148,10 +148,10 @@ function ($x) { /** * Map raise to a power * - * @param array $xs - * @param int|float $n + * @param array $xs + * @param int|float $n * - * @return array + * @return array */ public static function pow(array $xs, $n): array { @@ -166,9 +166,9 @@ function ($x) use ($n) { /** * Map square root * - * @param array $xs + * @param array $xs * - * @return array + * @return array */ public static function sqrt(array $xs): array { @@ -183,9 +183,9 @@ function ($x) { /** * Map absolute value * - * @param array $xs + * @param array $xs * - * @return array + * @return array */ public static function abs(array $xs): array { @@ -202,10 +202,10 @@ function ($x) { * Each element in array is compared against the value, * and the min of each is returned. * - * @param array $xs - * @param int|float $value + * @param array $xs + * @param int|float $value * - * @return array + * @return array */ public static function min(array $xs, $value): array { @@ -222,10 +222,10 @@ function ($x) use ($value) { * Each element in the array is compared against the value, * and the max of each is returned. * - * @param array $xs - * @param int|float $value + * @param array $xs + * @param int|float $value * - * @return array + * @return array */ public static function max(array $xs, $value): array { diff --git a/src/Functions/Support.php b/src/Functions/Support.php index b7734ec68..6694367ad 100644 --- a/src/Functions/Support.php +++ b/src/Functions/Support.php @@ -19,10 +19,10 @@ class Support * (a,b] = a < x <= b * [a,b] = a <= x <= b * - * @param array $limits Boundary limit definitions for each parameter - * ['var1' => limit, 'var2' => limit, ...] - * @param array $params Parameters and their value to check against the defined limits - * ['var1' => value, 'var2' => value, ...] + * @param array $limits Boundary limit definitions for each parameter + * ['var1' => limit, 'var2' => limit, ...] + * @param array $params Parameters and their value to check against the defined limits + * ['var1' => value, 'var2' => value, ...] * * @return bool True if all parameters are within defined limits * @@ -30,7 +30,7 @@ class Support * @throws Exception\OutOfBoundsException if any parameter is outside the defined limits * @throws Exception\BadDataException if an unknown bounds character is used */ - public static function checkLimits(array $limits, array $params) + public static function checkLimits(array $limits, array $params): bool { // All parameters should have limit bounds defined $undefined_limits = \array_diff_key($params, $limits); diff --git a/src/InformationTheory/Entropy.php b/src/InformationTheory/Entropy.php index 393e81391..8a707b115 100644 --- a/src/InformationTheory/Entropy.php +++ b/src/InformationTheory/Entropy.php @@ -31,13 +31,13 @@ class Entropy * * H is in shannons, or bits. * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float average minimum number of bits * * @throws Exception\BadDataException if probability distribution p does not add up to 1 */ - public static function shannonEntropy(array $p) + public static function shannonEntropy(array $p): float { // Probability distribution must add up to 1.0 if (\abs(\array_sum($p) - 1) > self::ONE_TOLERANCE) { @@ -74,7 +74,7 @@ function ($pᵢ) { * 1 nat = 1/ln(2) shannons or bits. * https://en.wikipedia.org/wiki/Nat_(unit) * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float average minimum number of nats * @@ -117,7 +117,7 @@ function ($pᵢ) { * 1 hartley = log₂(10) bit = ln(10) nat, or approximately 3.322 Sh, or 2.303 nat. * https://en.wikipedia.org/wiki/Hartley_(unit) * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float average minimum number of hartleys * @@ -158,8 +158,8 @@ function ($pᵢ) { * * H(p,q) = -∑ p(x) log₂ q(x) * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float entropy between distributions * @@ -213,7 +213,7 @@ function ($pᵢ, $qᵢ) { * Joint entropy is basically just shannonEntropy but the probability distribution input * represents the probability of two variables happening at the same time. * - * @param array $P⟮x、y⟯ probability distribution of x and y occuring together + * @param array $P⟮x、y⟯ probability distribution of x and y occuring together * * @return float uncertainty * @@ -236,8 +236,8 @@ public static function jointEntropy(array $P⟮x、y⟯) * * H is in shannons, or bits. * - * @param array $p probability distribution - * @param int|float $α order α + * @param array $p probability distribution + * @param int|float $α order α * * @return float * @@ -274,7 +274,7 @@ public static function renyiEntropy(array $p, $α) * * Perplexity is in shannons, or bits. * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float perplexity * diff --git a/src/LinearAlgebra/ComplexMatrix.php b/src/LinearAlgebra/ComplexMatrix.php index 39382a31c..94e22b35d 100644 --- a/src/LinearAlgebra/ComplexMatrix.php +++ b/src/LinearAlgebra/ComplexMatrix.php @@ -21,9 +21,11 @@ public function __construct(array $A) /** * Validate the matrix is entirely complex * + * @param array> $A + * * @throws Exception\IncorrectTypeException if all elements are not complex */ - protected function validateComplexData(array $A) + protected function validateComplexData(array $A): void { foreach ($A as $i => $row) { foreach ($row as $object) { @@ -41,7 +43,7 @@ protected function validateComplexData(array $A) */ public static function createZeroValue(): ObjectArithmetic { - return new ObjectMatrix([[new Complex(0, 0)]]); + return new ComplexMatrix([[new Complex(0, 0)]]); } /** diff --git a/src/LinearAlgebra/Decomposition/Cholesky.php b/src/LinearAlgebra/Decomposition/Cholesky.php index ee5782a76..84cd09825 100644 --- a/src/LinearAlgebra/Decomposition/Cholesky.php +++ b/src/LinearAlgebra/Decomposition/Cholesky.php @@ -95,6 +95,7 @@ public static function decompose(NumericMatrix $A): Cholesky } } + /** @var NumericMatrix $L */ $L = MatrixFactory::create($L); $Lᵀ = $L->transpose(); diff --git a/src/LinearAlgebra/Decomposition/Crout.php b/src/LinearAlgebra/Decomposition/Crout.php index ddd9c8f98..091e22cb4 100644 --- a/src/LinearAlgebra/Decomposition/Crout.php +++ b/src/LinearAlgebra/Decomposition/Crout.php @@ -83,7 +83,9 @@ public static function decompose(NumericMatrix $A): Crout } } + /** @var NumericMatrix $L */ $L = MatrixFactory::create($L); + /** @var NumericMatrix $U */ $U = MatrixFactory::create($U); return new Crout($L, $U); diff --git a/src/LinearAlgebra/Decomposition/Decomposition.php b/src/LinearAlgebra/Decomposition/Decomposition.php index b59b1e177..b636c1735 100644 --- a/src/LinearAlgebra/Decomposition/Decomposition.php +++ b/src/LinearAlgebra/Decomposition/Decomposition.php @@ -6,5 +6,9 @@ abstract class Decomposition { + /** + * @param NumericMatrix $M + * @return static + */ abstract public static function decompose(NumericMatrix $M); } diff --git a/src/LinearAlgebra/Decomposition/LU.php b/src/LinearAlgebra/Decomposition/LU.php index 5f83d7172..a88c63812 100644 --- a/src/LinearAlgebra/Decomposition/LU.php +++ b/src/LinearAlgebra/Decomposition/LU.php @@ -3,6 +3,11 @@ namespace MathPHP\LinearAlgebra\Decomposition; use MathPHP\Exception; +use MathPHP\Exception\BadDataException; +use MathPHP\Exception\DivisionByZeroException; +use MathPHP\Exception\IncorrectTypeException; +use MathPHP\Exception\MathException; +use MathPHP\Exception\MatrixException; use MathPHP\LinearAlgebra\NumericMatrix; use MathPHP\LinearAlgebra\MatrixFactory; use MathPHP\LinearAlgebra\Vector; @@ -97,7 +102,9 @@ public static function decompose(NumericMatrix $A): LU $n = $A->getN(); // Initialize L as diagonal ones matrix, and U as zero matrix - $L = MatrixFactory::diagonal(\array_fill(0, $n, 1))->getMatrix(); + /** @var array $fill */ + $fill = \array_fill(0, $n, 1); + $L = MatrixFactory::diagonal($fill)->getMatrix(); $U = MatrixFactory::zero($n, $n)->getMatrix(); // Create permutation matrix P and pivoted PA @@ -125,7 +132,7 @@ public static function decompose(NumericMatrix $A): LU } } - // Create LU decomposition + // Create LU decomposition @phpstan-ignore-next-line return new LU(MatrixFactory::create($L), MatrixFactory::create($U), $P); } @@ -217,19 +224,19 @@ protected static function pivotize(NumericMatrix $A): NumericMatrix * xᵢ = --- | yᵢ - ∑ Uᵢⱼxⱼ | * Uᵢᵢ \ ʲ⁼ⁱ⁺¹ / * - * @param Vector|array $b solution to Ax = b + * @param Vector|array $b solution to Ax = b * * @return Vector x * - * @throws Exception\IncorrectTypeException if b is not a Vector or array - * @throws Exception\MatrixException - * @throws Exception\VectorException - * @throws Exception\OutOfBoundsException - * @throws Exception\BadParameterException + * @throws BadDataException + * @throws DivisionByZeroException + * @throws IncorrectTypeException if b is not a Vector or array + * @throws MathException + * @throws MatrixException */ public function solve($b): Vector { - // Input must be a Vector or array. + // Input must be a Vector or array. @phpstan-ignore-next-line if (!($b instanceof Vector || \is_array($b))) { throw new Exception\IncorrectTypeException('b in Ax = b must be a Vector or array'); } diff --git a/src/LinearAlgebra/Decomposition/QR.php b/src/LinearAlgebra/Decomposition/QR.php index 641a5406a..f45546024 100644 --- a/src/LinearAlgebra/Decomposition/QR.php +++ b/src/LinearAlgebra/Decomposition/QR.php @@ -120,7 +120,7 @@ public static function decompose(NumericMatrix $A): QR * - R⁻¹R = I, so we get x = R⁻¹Qᵀb * Solve x = R⁻¹Qᵀb * - * @param Vector|array $b solution to Ax = b + * @param Vector|array $b solution to Ax = b * * @return Vector x * @@ -128,7 +128,7 @@ public static function decompose(NumericMatrix $A): QR */ public function solve($b): Vector { - // Input must be a Vector or array. + // Input must be a Vector or array. @phpstan-ignore-next-line if (!($b instanceof Vector || \is_array($b))) { throw new Exception\IncorrectTypeException('b in Ax = b must be a Vector or array'); } diff --git a/src/LinearAlgebra/Eigenvalue.php b/src/LinearAlgebra/Eigenvalue.php index 2aff8a17c..46e71bf0b 100644 --- a/src/LinearAlgebra/Eigenvalue.php +++ b/src/LinearAlgebra/Eigenvalue.php @@ -37,7 +37,7 @@ public static function isAvailableMethod(string $method): bool * * @throws Exception\BadDataException if the matrix is not square */ - private static function checkMatrix(NumericMatrix $A) + private static function checkMatrix(NumericMatrix $A): void { if (!$A->isSquare()) { throw new Exception\BadDataException('Matrix must be square'); @@ -82,6 +82,8 @@ public static function closedFormPolynomialRootMethod(NumericMatrix $A): array $B_array[$i][$j] = new Polynomial([$A[$i][$j]], 'λ'); } } + + /** @var ObjectSquareMatrix $B */ $B = MatrixFactory::create($B_array); // Create a diagonal Matrix of lambda (Iλ) @@ -106,10 +108,13 @@ public static function closedFormPolynomialRootMethod(NumericMatrix $A): array $det = $⟮B − λ⟯->det(); // Calculate the roots of the determinant. + /** @var array $eigenvalues */ $eigenvalues = $det->roots(); \usort($eigenvalues, function ($a, $b) { + /** @var number $a */ /** @var number $b */ return \abs($b) <=> \abs($a); }); + return $eigenvalues; } @@ -244,6 +249,7 @@ public static function powerIteration(NumericMatrix $A, int $iterations = 1000): for ($i = 0; $i < \count($newb); $i++) { $newb[$i][0] = $newb[1][0] + \rand() / 10; } + /** @var NumericMatrix $b */ $b = MatrixFactory::create($newb); $b = $b->scalarDivide($b->frobeniusNorm()); // Scale to a unit vector $newμ = 0; diff --git a/src/LinearAlgebra/Eigenvector.php b/src/LinearAlgebra/Eigenvector.php index cbc501026..abed66e87 100644 --- a/src/LinearAlgebra/Eigenvector.php +++ b/src/LinearAlgebra/Eigenvector.php @@ -3,6 +3,7 @@ namespace MathPHP\LinearAlgebra; use MathPHP\Exception; +use MathPHP\Exception\MatrixException; use MathPHP\Functions\Map\Single; use MathPHP\Functions\Special; @@ -94,7 +95,7 @@ public static function eigenvectors(NumericMatrix $A, array $eigenvalues = []): $solution = \array_fill(0, $number, 0); $solution[$column] = 1; $solution_array[] = ['eigenvalue' => $eigenvalue, 'vector' => $solution]; - // Add the solution to rref. + // Add the solution to rref. @phpstan-ignore-next-line $rref = $rref->augmentBelow(MatrixFactory::create([$solution]))->rref(); $number_of_solutions--; } @@ -108,7 +109,9 @@ public static function eigenvectors(NumericMatrix $A, array $eigenvalues = []): $forced_variables = []; $n = $rref->getN(); // The solution vector is a column vector. - $solution = new Vector(\array_fill(0, $n - $number_to_force, 0)); + /** @var array $fill */ + $fill = \array_fill(0, $n - $number_to_force, 0); + $solution = new Vector($fill); $matrix = $rref; for ($i = 0; $i < $n && \count($forced_variables) < $number_to_force; $i++) { // Make sure that removing column $i does not leave behind a row of zeros @@ -146,6 +149,7 @@ public static function eigenvectors(NumericMatrix $A, array $eigenvalues = []): // of $rref. Doing this will set the constraint that the dot product between the next // solution and this solution be zero, or that they are orthoganol. if ($vectors_found < $number_of_solutions) { + // @phpstan-ignore-next-line $rref = $rref->augmentBelow(MatrixFactory::create([$eigenvector]))->rref(); } } @@ -156,6 +160,7 @@ public static function eigenvectors(NumericMatrix $A, array $eigenvalues = []): // Reset the array keys. $solution_array = \array_values($solution_array); } + /** @var NumericMatrix $matrix */ $matrix = MatrixFactory::create($M); return $matrix->transpose(); } @@ -190,9 +195,11 @@ private static function countSolutions(NumericMatrix $M): int /** * Find the zero columns * - * @param NumericMatrix $M + * @param NumericMatrix $M + * + * @return array * - * @return array + * @throws MatrixException */ private static function findZeroColumns(NumericMatrix $M): array { diff --git a/src/LinearAlgebra/FunctionMatrix.php b/src/LinearAlgebra/FunctionMatrix.php index d09f17fdb..ca63dd16e 100644 --- a/src/LinearAlgebra/FunctionMatrix.php +++ b/src/LinearAlgebra/FunctionMatrix.php @@ -12,11 +12,11 @@ class FunctionMatrix /** @var int Number of columns */ protected $n; - /** @var array[] Matrix array of arrays */ + /** @var array> Matrix array of arrays */ protected $A; /** - * @param array[] $A of arrays $A m x n matrix + * @param array> $A of arrays $A m x n matrix * * @throws Exception\BadDataException if any rows have a different column count */ @@ -34,7 +34,7 @@ public function __construct(array $A) * * @throws Exception\BadDataException */ - protected function validateMatrixDimensions() + protected function validateMatrixDimensions(): void { foreach ($this->A as $i => $row) { if (\count($row) !== $this->n) { @@ -46,7 +46,7 @@ protected function validateMatrixDimensions() /** * Evaluate * - * @param array $params + * @param array $params * * @return NumericMatrix * @@ -66,6 +66,8 @@ public function evaluate(array $params): NumericMatrix $R[$i][$j] = $func($params); } } + + /** @var NumericMatrix */ return MatrixFactory::create($R); } } diff --git a/src/LinearAlgebra/Matrix.php b/src/LinearAlgebra/Matrix.php index 4232e86fb..085d6dadb 100644 --- a/src/LinearAlgebra/Matrix.php +++ b/src/LinearAlgebra/Matrix.php @@ -6,6 +6,9 @@ /** * m x n Matrix + * + * @template T + * @implements \ArrayAccess> */ abstract class Matrix implements \ArrayAccess, \JsonSerializable { @@ -15,10 +18,10 @@ abstract class Matrix implements \ArrayAccess, \JsonSerializable /** @var int Number of columns */ protected $n; - /** @var array[] Matrix array of arrays */ + /** @var array> Matrix array of arrays */ protected $A; - /** @var MatrixCatalog */ + /** @var MatrixCatalog */ protected $catalog; /** @var float|null Error/zero tolerance */ @@ -52,7 +55,7 @@ abstract public function getObjectType(): string; /** * Get matrix - * @return array[] of arrays + * @return array> of arrays */ public function getMatrix(): array { @@ -80,8 +83,8 @@ public function getN(): int /** * Get single row from the matrix * - * @param int $i row index (from 0 to m - 1) - * @return array + * @param int $i row index (from 0 to m - 1) + * @return array * * @throws Exception\MatrixException if row i does not exist */ @@ -97,8 +100,8 @@ public function getRow(int $i): array /** * Get single column from the matrix * - * @param int $j column index (from 0 to n - 1) - * @return array + * @param int $j column index (from 0 to n - 1) + * @return array * * @throws Exception\MatrixException if column j does not exist */ @@ -116,7 +119,7 @@ public function getColumn(int $j): array * * @param int $i row index * @param int $j column index - * @return number + * @return T * * @throws Exception\MatrixException if row i or column j does not exist */ @@ -140,7 +143,7 @@ public function get(int $i, int $j) * * getDiagonalElements($A) = [1, 5, 9] * - * @return array + * @return array */ public function getDiagonalElements(): array { @@ -162,7 +165,7 @@ public function getDiagonalElements(): array * * http://mathworld.wolfram.com/Superdiagonal.html * - * @return array + * @return array */ public function getSuperdiagonalElements(): array { @@ -185,7 +188,7 @@ public function getSuperdiagonalElements(): array * * http://mathworld.wolfram.com/Subdiagonal.html * - * @return array + * @return array */ public function getSubdiagonalElements(): array { @@ -218,6 +221,10 @@ public function asVectors(): array $vectors = []; for ($j = 0; $j < $n; $j++) { + /** + * FIXME: maybe define vector as a generic class of T type? + * @phpstan-ignore-next-line + */ $vectors[] = new Vector(\array_column($this->A, $j)); } @@ -242,6 +249,10 @@ public function asRowVectors(): array { return \array_map( function (array $row) { + /** + * FIXME: maybe define vector as a generic class of T type? + * @phpstan-ignore-next-line + */ return new Vector($row); }, $this->A @@ -256,7 +267,7 @@ function (array $row) { /** * Is this matrix the same size and type as some other matrix? * - * @param Matrix $B + * @param Matrix $B * * @return bool */ @@ -317,9 +328,9 @@ public function isSquare(): bool * (A|B) = [2, 3, 4 | 5] * [3, 4, 5 | 6] * - * @param Matrix $B Matrix columns to add to matrix A + * @param Matrix $B Matrix columns to add to matrix A * - * @return Matrix + * @return static * * @throws Exception\MatrixException if matrices do not have the same number of rows * @throws Exception\IncorrectTypeException @@ -342,6 +353,8 @@ public function augment(Matrix $B): Matrix $⟮A∣B⟯[$i] = \array_merge($A[$i], $B[$i]); } + /** @var array> $⟮A∣B⟯ */ + /** @var static */ return MatrixFactory::create($⟮A∣B⟯, $this->ε); } @@ -361,9 +374,9 @@ public function augment(Matrix $B): Matrix * (A|B) = [5 | 2, 3, 4] * [6 | 3, 4, 5] * - * @param Matrix $B Matrix columns to add to matrix A + * @param Matrix $B Matrix columns to add to matrix A * - * @return Matrix + * @return static * * @throws Exception\MatrixException if matrices do not have the same number of rows * @throws Exception\IncorrectTypeException @@ -386,6 +399,8 @@ public function augmentLeft(Matrix $B): Matrix $⟮B∣A⟯[$i] = \array_merge($B[$i], $A[$i]); } + /** @var array> $⟮B∣A⟯ */ + /** @var static */ return MatrixFactory::create($⟮B∣A⟯, $this->ε); } @@ -404,9 +419,9 @@ public function augmentLeft(Matrix $B): Matrix * [3, 4, 5] * [4, 5, 6] * - * @param Matrix $B Matrix rows to add to matrix A + * @param Matrix $B Matrix rows to add to matrix A * - * @return Matrix + * @return static * * @throws Exception\MatrixException if matrices do not have the same number of columns * @throws Exception\IncorrectTypeException @@ -420,8 +435,10 @@ public function augmentBelow(Matrix $B): Matrix throw new Exception\MatrixException('Matrices to augment do not have the same number of columns'); } + /** @var array> $⟮A∣B⟯ */ $⟮A∣B⟯ = \array_merge($this->A, $B->getMatrix()); + /** @var static */ return MatrixFactory::create($⟮A∣B⟯, $this->ε); } @@ -440,9 +457,9 @@ public function augmentBelow(Matrix $B): Matrix * (A_B) = [2, 3, 4] * [3, 4, 5] * - * @param Matrix $B Matrix rows to add to matrix A + * @param Matrix $B Matrix rows to add to matrix A * - * @return Matrix + * @return static * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException @@ -458,8 +475,10 @@ public function augmentAbove(Matrix $B): Matrix throw new Exception\MatrixException('Matrices to augment do not have the same number of columns'); } + /** @var array> $⟮A∣B⟯ */ $⟮A∣B⟯ = \array_merge($B->getMatrix(), $this->A); + /** @var static */ return MatrixFactory::create($⟮A∣B⟯, $this->ε); } @@ -481,7 +500,7 @@ public function augmentAbove(Matrix $B): Matrix * If A is an m × n matrix then Aᵀ is an n × m matrix. * https://en.wikipedia.org/wiki/Transpose * - * @return Matrix + * @return static * * @throws Exception\MatrixException * @throws Exception\IncorrectTypeException @@ -489,6 +508,7 @@ public function augmentAbove(Matrix $B): Matrix public function transpose(): Matrix { if ($this->catalog->hasTranspose()) { + /** @var static */ return $this->catalog->getTranspose(); } @@ -497,7 +517,9 @@ public function transpose(): Matrix $Aᵀ[$i] = $this->getColumn($i); } + // @phpstan-ignore-next-line $this->catalog->addTranspose(MatrixFactory::create($Aᵀ, $this->ε)); + /** @var static */ return $this->catalog->getTranspose(); } @@ -511,7 +533,7 @@ public function transpose(): Matrix * @param int $m₂ Ending row * @param int $n₂ Ending column * - * @return Matrix + * @return static * * @throws Exception\MatrixException */ @@ -537,6 +559,7 @@ public function submatrix(int $m₁, int $n₁, int $m₂, int $n₂): Matrix } } + /** @var static */ return MatrixFactory::create($A, $this->ε); } @@ -544,11 +567,11 @@ public function submatrix(int $m₁, int $n₁, int $m₂, int $n₂): Matrix * Insert * Insert a smaller matrix within a larger matrix starting at a specified position * - * @param Matrix $small the smaller matrix to embed - * @param int $m Starting row - * @param int $n Starting column + * @param Matrix $small the smaller matrix to embed + * @param int $m Starting row + * @param int $n Starting column * - * @return Matrix + * @return static * * @throws Exception\MatrixException */ @@ -567,6 +590,7 @@ public function insert(Matrix $small, int $m, int $n): Matrix $new_array[$i + $m][$j + $n] = $small[$i][$j]; } } + /** @var static */ return MatrixFactory::create($new_array, $this->ε); } @@ -581,7 +605,7 @@ public function insert(Matrix $small, int $m, int $n): Matrix * * @param callable $func takes a matrix item as input * - * @return Matrix + * @return static * * @throws Exception\IncorrectTypeException */ @@ -597,6 +621,7 @@ public function map(callable $func): Matrix } } + /** @var static */ return MatrixFactory::create($R, $this->ε); } @@ -605,7 +630,7 @@ public function map(callable $func): Matrix * * @param callable $func * - * @return array|array[] Depends on the function + * @return array|array> Depends on the function */ public function mapRows(callable $func): array { @@ -647,7 +672,7 @@ public function walk(callable $func): void * @param int $mᵢ Row to swap into row position mⱼ * @param int $mⱼ Row to swap into row position mᵢ * - * @return Matrix with rows mᵢ and mⱼ interchanged + * @return static with rows mᵢ and mⱼ interchanged * * @throws Exception\MatrixException if row to interchange does not exist * @throws Exception\IncorrectTypeException @@ -674,6 +699,7 @@ public function rowInterchange(int $mᵢ, int $mⱼ): Matrix } } + /** @var static */ return MatrixFactory::create($R, $this->ε); } @@ -682,7 +708,7 @@ public function rowInterchange(int $mᵢ, int $mⱼ): Matrix * * @param int $mᵢ Row to exclude * - * @return Matrix with row mᵢ excluded + * @return static with row mᵢ excluded * * @throws Exception\MatrixException if row to exclude does not exist * @throws Exception\IncorrectTypeException @@ -703,6 +729,7 @@ public function rowExclude(int $mᵢ): Matrix $R[$i] = $this->A[$i]; } + /** @var static */ return MatrixFactory::create(\array_values($R), $this->ε); } @@ -721,7 +748,7 @@ public function rowExclude(int $mᵢ): Matrix * @param int $nᵢ Column to swap into column position nⱼ * @param int $nⱼ Column to swap into column position nᵢ * - * @return Matrix with columns nᵢ and nⱼ interchanged + * @return static with columns nᵢ and nⱼ interchanged * * @throws Exception\MatrixException if column to interchange does not exist * @throws Exception\IncorrectTypeException @@ -751,6 +778,7 @@ public function columnInterchange(int $nᵢ, int $nⱼ): Matrix } } + /** @var static */ return MatrixFactory::create($R, $this->ε); } @@ -759,7 +787,7 @@ public function columnInterchange(int $nᵢ, int $nⱼ): Matrix * * @param int $nᵢ Column to exclude * - * @return Matrix with column nᵢ excluded + * @return static with column nᵢ excluded * * @throws Exception\MatrixException if column to exclude does not exist * @throws Exception\IncorrectTypeException @@ -788,6 +816,7 @@ public function columnExclude(int $nᵢ): Matrix $R[$i] = \array_values($R[$i]); } + /** @var static */ return MatrixFactory::create($R, $this->ε); } @@ -805,7 +834,7 @@ public function columnExclude(int $nᵢ): Matrix * * https://en.wikipedia.org/wiki/Conjugate_transpose * - * @return Matrix + * @return static */ public function conjugateTranspose(): Matrix { @@ -820,7 +849,7 @@ public function conjugateTranspose(): Matrix * @param int $mᵢ Row to exclude * @param int $nⱼ Column to exclude * - * @return Matrix with row mᵢ and column nⱼ removed + * @return static with row mᵢ and column nⱼ removed * * @throws Exception\MatrixException if matrix is not square * @throws Exception\MatrixException if row to exclude for minor matrix does not exist @@ -864,7 +893,7 @@ public function minorMatrix(int $mᵢ, int $nⱼ): Matrix * * @param int $k Order of the leading principal minor * - * @return Matrix + * @return static * * @throws Exception\OutOfBoundsException if k ≤ 0 * @throws Exception\OutOfBoundsException if k > n @@ -890,6 +919,7 @@ public function leadingPrincipalMinor(int $k): Matrix } } + /** @var static */ return MatrixFactory::create($R, $this->ε); } @@ -915,7 +945,7 @@ public function leadingPrincipalMinor(int $k): Matrix * @param int $mᵢ Row to exclude * @param int $nⱼ Column to exclude * - * @return number + * @return T * * @throws Exception\MatrixException if matrix is not square * @throws Exception\MatrixException if row to exclude for minor does not exist @@ -935,7 +965,10 @@ public function minor(int $mᵢ, int $nⱼ) throw new Exception\MatrixException('Column to exclude for minor does not exist'); } - return $this->minorMatrix($mᵢ, $nⱼ)->det(); + /** @var ObjectMatrix|NumericMatrix $minorMatrix */ + $minorMatrix = $this->minorMatrix($mᵢ, $nⱼ); + /** @var T */ + return $minorMatrix->det(); } /************************************************************************** @@ -943,7 +976,7 @@ public function minor(int $mᵢ, int $nⱼ) **************************************************************************/ /** - * @param mixed $i + * @param int $i * @return bool */ public function offsetExists($i): bool @@ -952,8 +985,8 @@ public function offsetExists($i): bool } /** - * @param mixed $i - * @return mixed + * @param int $i + * @return array */ #[\ReturnTypeWillChange] public function offsetGet($i) @@ -962,8 +995,8 @@ public function offsetGet($i) } /** - * @param mixed $i - * @param mixed $value + * @param int $i + * @param array $value * @throws Exception\MatrixException */ public function offsetSet($i, $value): void @@ -972,7 +1005,7 @@ public function offsetSet($i, $value): void } /** - * @param mixed $i + * @param int $i * @throws Exception\MatrixException */ public function offsetUnset($i): void @@ -984,7 +1017,7 @@ public function offsetUnset($i): void * JsonSerializable INTERFACE **************************************************************************/ /** - * @return array + * @return array> */ public function jsonSerialize(): array { diff --git a/src/LinearAlgebra/MatrixCatalog.php b/src/LinearAlgebra/MatrixCatalog.php index 07d5ec1d8..d015003b5 100644 --- a/src/LinearAlgebra/MatrixCatalog.php +++ b/src/LinearAlgebra/MatrixCatalog.php @@ -2,12 +2,17 @@ namespace MathPHP\LinearAlgebra; +use MathPHP\Number\ObjectArithmetic; + +/** + * @template T + */ class MatrixCatalog { - /** @var NumericMatrix transpose */ + /** @var Matrix transpose */ private $Aᵀ; - /** @var NumericMatrix inverse */ + /** @var Matrix inverse */ private $A⁻¹; /** @var Reduction\RowEchelonForm */ @@ -31,7 +36,7 @@ class MatrixCatalog /** @var Decomposition\SVD */ private $SVD; - /** @var float determinant */ + /** @var int|float|ObjectArithmetic determinant */ private $det; /************************************************************************** @@ -43,7 +48,7 @@ class MatrixCatalog // TRANSPOSE /** - * @param Matrix $Aᵀ + * @param Matrix $Aᵀ */ public function addTranspose(Matrix $Aᵀ): void { @@ -55,11 +60,12 @@ public function addTranspose(Matrix $Aᵀ): void */ public function hasTranspose(): bool { + // @phpstan-ignore-next-line return isset($this->Aᵀ); } /** - * @return Matrix + * @return Matrix */ public function getTranspose(): Matrix { @@ -69,7 +75,7 @@ public function getTranspose(): Matrix // INVERSE /** - * @param Matrix $A⁻¹ + * @param Matrix $A⁻¹ */ public function addInverse(Matrix $A⁻¹): void { @@ -81,11 +87,12 @@ public function addInverse(Matrix $A⁻¹): void */ public function hasInverse(): bool { + // @phpstan-ignore-next-line return isset($this->A⁻¹); } /** - * @return Matrix + * @return Matrix */ public function getInverse(): Matrix { @@ -113,6 +120,7 @@ public function addRowEchelonForm(Reduction\RowEchelonForm $REF): void */ public function hasRowEchelonForm(): bool { + // @phpstan-ignore-next-line return isset($this->REF); } @@ -139,6 +147,7 @@ public function addReducedRowEchelonForm(Reduction\ReducedRowEchelonForm $RREF): */ public function hasReducedRowEchelonForm(): bool { + // @phpstan-ignore-next-line return isset($this->RREF); } @@ -175,6 +184,7 @@ public function addLuDecomposition(Decomposition\LU $LU): void */ public function hasLuDecomposition(): bool { + // @phpstan-ignore-next-line return isset($this->LU); } @@ -201,6 +211,7 @@ public function addQrDecomposition(Decomposition\QR $QR): void */ public function hasQrDecomposition(): bool { + // @phpstan-ignore-next-line return isset($this->QR); } @@ -227,6 +238,7 @@ public function addCholeskyDecomposition(Decomposition\Cholesky $cholesky): void */ public function hasCholeskyDecomposition(): bool { + // @phpstan-ignore-next-line return isset($this->cholesky); } @@ -253,6 +265,7 @@ public function addCroutDecomposition(Decomposition\Crout $crout): void */ public function hasCroutDecomposition(): bool { + // @phpstan-ignore-next-line return isset($this->crout); } @@ -269,7 +282,7 @@ public function getCroutDecomposition(): Decomposition\Crout /** * @param Decomposition\SVD $SVD */ - public function addSVD(Decomposition\SVD $SVD) + public function addSVD(Decomposition\SVD $SVD): void { $this->SVD = $SVD; } @@ -277,8 +290,9 @@ public function addSVD(Decomposition\SVD $SVD) /** * @return bool */ - public function hasSVD() + public function hasSVD(): bool { + // @phpstan-ignore-next-line return isset($this->SVD); } @@ -297,7 +311,7 @@ public function getSVD(): Decomposition\SVD // DETERMINANT /** - * @param int|float $det + * @param int|float|ObjectArithmetic $det */ public function addDeterminant($det): void { @@ -309,11 +323,12 @@ public function addDeterminant($det): void */ public function hasDeterminant(): bool { + // @phpstan-ignore-next-line return isset($this->det); } /** - * @return number + * @return int|float|ObjectArithmetic */ public function getDeterminant() { diff --git a/src/LinearAlgebra/MatrixFactory.php b/src/LinearAlgebra/MatrixFactory.php index 12235ffff..273b75761 100644 --- a/src/LinearAlgebra/MatrixFactory.php +++ b/src/LinearAlgebra/MatrixFactory.php @@ -4,20 +4,23 @@ use MathPHP\Exception; use MathPHP\Number\Complex; +use MathPHP\Number\ObjectArithmetic; /** * Matrix factory to create matrices of all types. * Use factory instead of instantiating individual Matrix classes. + * + * @template T = int[][]|float[][]|Complex[][]|object[][] */ class MatrixFactory { /** * Factory method * - * @param int[][]|float[][]|Complex[][]|object[][] $A 2-dimensional array of Matrix data - * @param float|null $ε Optional error tolerance + * @param T[][] $A 2-dimensional array of Matrix data + * @param float|null $ε Optional error tolerance * - * @return Matrix + * @return Matrix|NumericMatrix|ComplexMatrix|ObjectMatrix|ObjectSquareMatrix * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException @@ -33,12 +36,16 @@ public static function create(array $A, ?float $ε = null): Matrix switch ($matrix_type) { case 'numeric': case 'numeric_square': + /** @var array> $A */ return self::createNumeric($A, $ε); case 'complex': + /** @var array> $A */ return new ComplexMatrix($A); case 'object': + /** @var array> $A */ return new ObjectMatrix($A); case 'object_square': + /** @var array> $A */ return new ObjectSquareMatrix($A); } @@ -82,10 +89,10 @@ public static function createNumeric(array $A, ?float $ε = null): NumericMatrix * R = [2 2 8 4] * [1 13 1 5] * - * @param Vector[] $A array of Vectors + * @param Vector[] $A array of Vectors * @param float|null $ε Optional error tolerance * - * @return Matrix + * @return NumericMatrix * * @throws Exception\MatrixException if the Vectors are not all the same length * @throws Exception\IncorrectTypeException @@ -121,9 +128,9 @@ public static function createFromVectors(array $A, ?float $ε = null): NumericMa * [⋮ ] * [xm] * - * @param array $A m × 1 vector representing the matrix + * @param T[] $A m × 1 vector representing the matrix * - * @return Matrix + * @return Matrix|NumericMatrix|ComplexMatrix|ObjectMatrix|ObjectSquareMatrix */ public static function createFromColumnVector(array $A): Matrix { @@ -147,9 +154,9 @@ public static function createFromColumnVector(array $A): Matrix * * x = [x₁ x₂ ⋯ xn] * - * @param array $A 1 × n vector representing the matrix + * @param T[] $A 1 × n vector representing the matrix * - * @return Matrix + * @return Matrix|NumericMatrix|ComplexMatrix|ObjectMatrix|ObjectSquareMatrix */ public static function createFromRowVector(array $A): Matrix { @@ -166,7 +173,7 @@ public static function createFromRowVector(array $A): Matrix /** * Factory method * - * @param array[] $A 2-dimensional array of Matrix data + * @param callable[][] $A 2-dimensional array of Matrix data * * @return FunctionMatrix */ @@ -205,7 +212,7 @@ public static function createFunctionMatrix(array $A): FunctionMatrix * A = [0 1 0] * [0 0 1] * - * @param int $n size of matrix + * @param int $n size of matrix * * @return NumericSquareMatrix * @@ -294,6 +301,7 @@ public static function downshiftPermutation(int $n): NumericSquareMatrix $bottom_row = \array_pop($I); \array_unshift($I, $bottom_row); + /** @var array> $I */ return new NumericSquareMatrix($I); } @@ -303,7 +311,7 @@ public static function downshiftPermutation(int $n): NumericSquareMatrix * * @param int $n * - * @return Matrix + * @return NumericMatrix|ComplexMatrix|ObjectMatrix|ObjectSquareMatrix * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException @@ -443,7 +451,7 @@ public static function eye(int $m, int $n, int $k, float $x = null): NumericMatr * A = [0 2 0] * [0 0 3] * - * @param array $D elements of the diagonal + * @param array $D elements of the diagonal * * @return NumericDiagonalMatrix * @@ -510,7 +518,7 @@ public static function hilbert(int $n): NumericMatrix /** * Create the Vandermonde Matrix from a simple array. * - * @param array $M (α₁, α₂, α₃ ⋯ αm) + * @param array $M (α₁, α₂, α₃ ⋯ αm) * @param int $n * * @return NumericMatrix @@ -602,7 +610,7 @@ public static function random(int $m, int $n, int $min = 0, int $max = 20): Nume /** * Check input parameters * - * @param array $A + * @param array $A * * @throws Exception\BadDataException if array data not provided for matrix creation * @throws Exception\MatrixException if any row has a different column count @@ -626,7 +634,7 @@ private static function checkParams(array $A): void /** * Determine what type of matrix to create * - * @param array[] $A 2-dimensional array of Matrix data + * @param array> $A 2-dimensional array of Matrix data * * @return string indicating what matrix type to create */ diff --git a/src/LinearAlgebra/NumericDiagonalMatrix.php b/src/LinearAlgebra/NumericDiagonalMatrix.php index f338604db..8748fad40 100644 --- a/src/LinearAlgebra/NumericDiagonalMatrix.php +++ b/src/LinearAlgebra/NumericDiagonalMatrix.php @@ -15,7 +15,7 @@ class NumericDiagonalMatrix extends NumericSquareMatrix /** * Constructor * - * @param array $A + * @param array> $A */ public function __construct(array $A) { diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index 1c44faddb..cf0637453 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -9,6 +9,8 @@ /** * m x n Matrix + * + * @extends Matrix */ class NumericMatrix extends Matrix { @@ -32,7 +34,7 @@ class NumericMatrix extends Matrix /** * Constructor * - * @param array[] $A of arrays $A m x n matrix + * @param array> $A of arrays $A m x n matrix * * @throws Exception\BadDataException if any rows have a different column count */ @@ -52,7 +54,7 @@ public function __construct(array $A) * * @throws Exception\BadDataException */ - protected function validateMatrixDimensions() + protected function validateMatrixDimensions(): void { foreach ($this->A as $i => $row) { if (\count($row) !== $this->n) { @@ -1264,6 +1266,7 @@ public function subtract($B): NumericMatrix */ public function multiply($B): NumericMatrix { + // @phpstan-ignore-next-line if ((!$B instanceof NumericMatrix) && (!$B instanceof Vector)) { throw new Exception\IncorrectTypeException('Can only do matrix multiplication with a Matrix or Vector'); } @@ -1278,6 +1281,7 @@ public function multiply($B): NumericMatrix $Bᵀ = $B->transpose()->getMatrix(); foreach ($this->A as $i => $Aʳᵒʷ⟦i⟧) { + /** @var array $R */ $R[$i] = \array_fill(0, $B->n, 0); foreach ($Bᵀ as $j => $Bᶜᵒˡ⟦j⟧) { foreach ($Aʳᵒʷ⟦i⟧ as $k => $A⟦i⟧⟦k⟧) { @@ -1440,6 +1444,7 @@ public function kroneckerProduct(NumericMatrix $B): NumericMatrix // Augment each aᵢ₁ to aᵢn block $matrices = []; foreach ($arrays as $row) { + /** @var NumericMatrix $initial_matrix */ $initial_matrix = \array_shift($row); $matrices[] = \array_reduce( $row, @@ -1451,6 +1456,7 @@ function (NumericMatrix $augmented_matrix, NumericMatrix $matrix) { } // Augment below each row block a₁ to am + /** @var NumericMatrix $initial_matrix */ $initial_matrix = \array_shift($matrices); $A⊗B = \array_reduce( $matrices, @@ -1527,6 +1533,7 @@ public function diagonal(): NumericMatrix public function inverse(): NumericMatrix { if ($this->catalog->hasInverse()) { + /** @var NumericMatrix */ return $this->catalog->getInverse(); } @@ -2189,6 +2196,7 @@ public function maxNorm() public function det() { if ($this->catalog->hasDeterminant()) { + /** @var number */ return $this->catalog->getDeterminant(); } @@ -2197,6 +2205,8 @@ public function det() } $m = $this->m; + + /** @var NumericMatrix $R */ $R = MatrixFactory::create($this->A); /* @@ -2883,8 +2893,8 @@ public function svd(): Decomposition\SVD * Otherwise, it is more efficient to decompose and then solve. * Use LU Decomposition and solve Ax = b. * - * @param Vector|array $b solution to Ax = b - * @param string $method (optional) Force a specific solve method - defaults to DEFAULT where various methods are tried + * @param Vector|array $b solution to Ax = b + * @param string $method (optional) Force a specific solve method - defaults to DEFAULT where various methods are tried * * @return Vector x * @@ -2897,6 +2907,7 @@ public function svd(): Decomposition\SVD public function solve($b, string $method = self::DEFAULT): Vector { // Input must be a Vector or array. + // @phpstan-ignore-next-line if (!($b instanceof Vector || \is_array($b))) { throw new Exception\IncorrectTypeException('b in Ax = b must be a Vector or array'); } @@ -2923,7 +2934,9 @@ public function solve($b, string $method = self::DEFAULT): Vector default: // If inverse is already calculated, solve: x = A⁻¹b if ($this->catalog->hasInverse()) { - return new Vector($this->catalog->getInverse()->multiply($b)->getColumn(0)); + /** @var NumericMatrix $inverse */ + $inverse = $this->catalog->getInverse(); + return new Vector($inverse->multiply($b)->getColumn(0)); } // If 2x2, just compute the inverse and solve: x = A⁻¹b @@ -3012,7 +3025,7 @@ private function solveRref(Vector $b): Vector * * @param string $method Algorithm used to compute the eigenvalues * - * @return array of eigenvalues + * @return array of eigenvalues * * @throws Exception\MatrixException if method is not a valid eigenvalue method * @throws Exception\MathException @@ -3083,6 +3096,7 @@ public function eigenvectors(string $method = null): NumericMatrix */ public function __toString(): string { + // @phpstan-ignore-next-line return \trim(\array_reduce(\array_map( function ($mᵢ) { return '[' . \implode(', ', $mᵢ) . ']'; @@ -3103,7 +3117,7 @@ function ($mᵢ) { * [3, 4, 5, 6] * [ε] => 1.0E-11 * - * @return array + * @return array{matrix: string, data: string, ε: float} */ public function __debugInfo(): array { diff --git a/src/LinearAlgebra/NumericSquareMatrix.php b/src/LinearAlgebra/NumericSquareMatrix.php index 6e787c84a..fcf716c11 100644 --- a/src/LinearAlgebra/NumericSquareMatrix.php +++ b/src/LinearAlgebra/NumericSquareMatrix.php @@ -14,7 +14,7 @@ class NumericSquareMatrix extends NumericMatrix /** * Constructor * - * @param array $A + * @param array> $A * * @throws Exception\MathException */ diff --git a/src/LinearAlgebra/ObjectMatrix.php b/src/LinearAlgebra/ObjectMatrix.php index 1433ed917..97da7eba1 100644 --- a/src/LinearAlgebra/ObjectMatrix.php +++ b/src/LinearAlgebra/ObjectMatrix.php @@ -12,6 +12,8 @@ * The ObjectMatrix extends Matrix functions to a matrix of objects. * The object must implement the MatrixArithmetic interface to prove * compatibility. It extends the SquareMatrix in order to use Matrix::minor(). + * + * @extends Matrix */ class ObjectMatrix extends Matrix implements ObjectArithmetic { @@ -50,10 +52,11 @@ public function __construct(array $A) * @throws Exception\IncorrectTypeException if The class does not implement the ObjectArithmetic interface * @throws Exception\MathException */ - protected function validateMatrixData() + protected function validateMatrixData(): void { if ($this->A[0][0] instanceof ObjectArithmetic) { $this->object_type = \get_class($this->A[0][0]); + // @phpstan-ignore-next-line } else { throw new Exception\IncorrectTypeException("The object must implement the interface."); } @@ -99,7 +102,7 @@ public static function createZeroValue(): ObjectArithmetic /** * Is this matrix equal to some other matrix? * - * @param Matrix $B + * @param Matrix $B * * @return bool */ @@ -126,10 +129,12 @@ public function isEqual(Matrix $B): bool /** * Check that the matrices are the same size and of the same type * + * @param Matrix $B + * * @throws Exception\MatrixException if matrices have a different number of rows or columns * @throws Exception\IncorrectTypeException if the two matricies are not the same class */ - private function checkEqualSizes(Matrix $B) + private function checkEqualSizes(Matrix $B): void { if ($B->getM() !== $this->m || $B->getN() !== $this->n) { throw new Exception\MatrixException('Matrices are different sizes'); @@ -149,6 +154,7 @@ private function checkEqualSizes(Matrix $B) /** * {@inheritDoc} + * @return ObjectMatrix */ public function add($B): Matrix { @@ -162,11 +168,13 @@ public function add($B): Matrix $R[$i][$j] = $this->A[$i][$j]->add($B[$i][$j]); } } + /** @var ObjectMatrix */ return MatrixFactory::create($R); } /** * {@inheritDoc} + * @return ObjectMatrix */ public function subtract($B): Matrix { @@ -180,11 +188,13 @@ public function subtract($B): Matrix $R[$i][$j] = $this->A[$i][$j]->subtract($B[$i][$j]); } } + /** @var ObjectMatrix */ return MatrixFactory::create($R); } /** * {@inheritDoc} + * @return ObjectMatrix */ public function multiply($B): Matrix { @@ -202,7 +212,9 @@ public function multiply($B): Matrix $R = []; for ($i = 0; $i < $m; $i++) { for ($j = 0; $j < $n; $j++) { + /** @var array $VA */ $VA = $this->getRow($i); + /** @var array $VB */ $VB = $B->getColumn($j); $R[$i][$j] = \array_reduce( \array_map( @@ -220,6 +232,7 @@ function ($sum, $item) { ); } } + /** @var ObjectMatrix */ return MatrixFactory::create($R); } @@ -229,7 +242,7 @@ function ($sum, $item) { * * @param float $λ * - * @return Matrix + * @return ObjectMatrix * * @throws Exception\BadParameterException if λ is not a number * @throws Exception\IncorrectTypeException @@ -244,6 +257,7 @@ public function scalarMultiply($λ): Matrix } } + /** @var ObjectMatrix */ return MatrixFactory::create($R); } @@ -293,6 +307,7 @@ public function trace() public function det() { if ($this->catalog->hasDeterminant()) { + /** @var ObjectArithmetic */ return $this->catalog->getDeterminant(); } @@ -301,6 +316,7 @@ public function det() } $m = $this->m; + /** @var ObjectMatrix $R */ $R = MatrixFactory::create($this->A); /* @@ -339,7 +355,12 @@ public function det() /** - * {@inheritDoc} + * @param int $mᵢ + * @param int $nⱼ + * + * @return ObjectArithmetic + * + * FIXME: maybe add return type to the method definition? */ public function cofactor(int $mᵢ, int $nⱼ) { diff --git a/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php b/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php index bc861425c..ccc8fee03 100644 --- a/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php +++ b/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php @@ -29,7 +29,7 @@ class ReducedRowEchelonForm extends NumericMatrix /** * ReducedRowEchelonForm constructor * - * @param array $A + * @param array> $A * * @throws Exception\BadDataException */ diff --git a/src/LinearAlgebra/Reduction/RowEchelonForm.php b/src/LinearAlgebra/Reduction/RowEchelonForm.php index fd500ef9a..ee49b0c32 100644 --- a/src/LinearAlgebra/Reduction/RowEchelonForm.php +++ b/src/LinearAlgebra/Reduction/RowEchelonForm.php @@ -24,8 +24,8 @@ class RowEchelonForm extends NumericMatrix /** * RowEchelonForm constructor - * @param array $A - * @param int $swaps Number of row swaps when computing REF + * @param array> $A + * @param int $swaps Number of row swaps when computing REF * * @throws Exception\BadDataException */ @@ -114,7 +114,7 @@ public static function reduce(NumericMatrix $A): RowEchelonForm * * @param NumericMatrix $A * - * @return array - matrix in row echelon form and number of row swaps + * @return array{array>, int} - matrix in row echelon form and number of row swaps * * @throws Exception\SingularMatrixException if the matrix is singular */ @@ -179,7 +179,7 @@ public static function gaussianElimination(NumericMatrix $A): array * * @param NumericMatrix $A * - * @return array - matrix in row echelon form and number of row swaps + * @return array{array>, int} - matrix in row echelon form and number of row swaps * * @throws Exception\IncorrectTypeException * @throws Exception\MatrixException diff --git a/src/LinearAlgebra/Vector.php b/src/LinearAlgebra/Vector.php index c10c90a03..da1fc1854 100644 --- a/src/LinearAlgebra/Vector.php +++ b/src/LinearAlgebra/Vector.php @@ -8,13 +8,16 @@ /** * 1 x n Vector + * + * @implements \Iterator + * @implements \ArrayAccess */ class Vector implements \Countable, \Iterator, \ArrayAccess, \JsonSerializable { /** @var int Number of elements */ private $n; - /** @var array of numbers */ + /** @var array of numbers */ private $A; /** @var int Iterator position */ @@ -23,7 +26,7 @@ class Vector implements \Countable, \Iterator, \ArrayAccess, \JsonSerializable /** * Constructor * - * @param array $A 1 x n vector + * @param array $A 1 x n vector * * @throws Exception\BadDataException if the Vector is empty */ @@ -50,7 +53,7 @@ public function __construct(array $A) /** * Get matrix * - * @return array + * @return array */ public function getVector(): array { @@ -146,7 +149,7 @@ public function asRowMatrix(): NumericMatrix /** * Sum of all elements * - * @return number + * @return float|int */ public function sum() { @@ -167,7 +170,9 @@ public function length() /** * Max of all the elements * - * @return number + * @return number|false + * + * FIXME: maybe null instead of false? */ public function max() { @@ -177,7 +182,9 @@ public function max() /** * Min of all the elements * - * @return number + * @return number|false + * + * FIXME: maybe null instead of false? */ public function min() { @@ -190,7 +197,7 @@ public function min() * * @param Vector $B * - * @return number + * @return float|int * * @throws Exception\VectorException */ @@ -214,7 +221,7 @@ function ($a, $b) { * * @param Vector $B * - * @return number + * @return float|int */ public function innerProduct(Vector $B) { @@ -229,7 +236,7 @@ public function innerProduct(Vector $B) * * @param Vector $B * - * @return number + * @return float|int * * @throws Exception\VectorException */ @@ -276,7 +283,7 @@ public function angleBetween(Vector $B, bool $inDegrees = false) * * @param Vector $B * - * @return float|int + * @return float * * @throws Exception\BadDataException */ @@ -292,7 +299,7 @@ public function l1Distance(Vector $B): float * * @param Vector $B * - * @return float|int The euclidean distance between the vectors + * @return float The euclidean distance between the vectors * * @throws Exception\BadDataException */ @@ -310,7 +317,7 @@ public function l2Distance(Vector $B): float * @param Vector $B * @param int $p * - * @return float|int + * @return float * * @throws Exception\BadDataException */ @@ -481,6 +488,7 @@ public function outerProduct(Vector $B): NumericMatrix } } + /** @var NumericMatrix */ return MatrixFactory::create($R); } @@ -660,7 +668,7 @@ public function kroneckerProduct(Vector $B): Vector * * |x|₁ = ∑|xᵢ| * - * @return number + * @return float|int */ public function l1Norm() { @@ -677,7 +685,7 @@ public function l1Norm() * ______ * |x|₂ = √∑|xᵢ|² * - * @return number + * @return float */ public function l2Norm() { @@ -706,7 +714,9 @@ public function pNorm($p) * * |x|∞ = max |x| * - * @return number + * @return number|false + * + * FIXME: maybe null instead of false? */ public function maxNorm() { @@ -757,7 +767,7 @@ public function offsetExists($i): bool /** * @param mixed $i - * @return mixed + * @return number */ #[\ReturnTypeWillChange] public function offsetGet($i) @@ -766,8 +776,8 @@ public function offsetGet($i) } /** - * @param mixed $i - * @param mixed $value + * @param int $i + * @param number $value * @throws Exception\VectorException */ public function offsetSet($i, $value): void @@ -776,7 +786,7 @@ public function offsetSet($i, $value): void } /** - * @param mixed $i + * @param int $i * @throws Exception\VectorException */ public function offsetUnset($i): void @@ -789,7 +799,7 @@ public function offsetUnset($i): void **************************************************************************/ /** - * @return array + * @return array */ public function jsonSerialize(): array { @@ -805,18 +815,27 @@ public function rewind(): void $this->i = 0; } + /** + * @return number + */ #[\ReturnTypeWillChange] public function current() { return $this->A[$this->i]; } + /** + * @return int + */ #[\ReturnTypeWillChange] public function key() { return $this->i; } + /** + * @return void + */ public function next(): void { ++$this->i; diff --git a/src/Number/Complex.php b/src/Number/Complex.php index 6fd9e2f6e..e7135f617 100644 --- a/src/Number/Complex.php +++ b/src/Number/Complex.php @@ -192,7 +192,7 @@ public function sqrt(): Complex * √ 2 * * - * @return array Complex[] (two roots) + * @return array{Complex, Complex} (two roots) */ public function roots(): array { @@ -406,6 +406,7 @@ public function pow($c): Complex return new Complex($new_r, $new_i); } + // @phpstan-ignore-next-line throw new Exception\IncorrectTypeException('Argument must be real or complex number'); } diff --git a/src/Number/ObjectArithmetic.php b/src/Number/ObjectArithmetic.php index 9180c7ae3..bef6a4b5a 100644 --- a/src/Number/ObjectArithmetic.php +++ b/src/Number/ObjectArithmetic.php @@ -13,7 +13,7 @@ interface ObjectArithmetic */ public function add($object_or_scalar); - /* + /** * Subtract one objects from another * * @param mixed $object_or_scalar the value to be subtracted @@ -22,7 +22,7 @@ public function add($object_or_scalar); */ public function subtract($object_or_scalar); - /* + /** * Multiply two objects together * * @param mixed $object_or_scalar value to be multiplied diff --git a/src/Number/Quaternion.php b/src/Number/Quaternion.php index 530b18105..fb9f54c5a 100644 --- a/src/Number/Quaternion.php +++ b/src/Number/Quaternion.php @@ -37,6 +37,7 @@ class Quaternion implements ObjectArithmetic */ public function __construct($r, $i, $j, $k) { + // @phpstan-ignore-next-line if (!\is_numeric($r) || !\is_numeric($i) || !\is_numeric($j) || !\is_numeric($k)) { throw new Exception\BadDataException('Values must be real numbers.'); } @@ -317,6 +318,9 @@ public function equals(Quaternion $q): bool /** * Stringify an additional part of the quaternion * + * @param number $q + * @param string $unit + * @param string $string * @return string */ private static function stringifyNumberPart($q, string $unit = '', string $string = ''): string diff --git a/src/Number/Rational.php b/src/Number/Rational.php index 0d20f3dd5..76cdcd5f2 100644 --- a/src/Number/Rational.php +++ b/src/Number/Rational.php @@ -4,6 +4,7 @@ use MathPHP\Algebra; use MathPHP\Exception; +use MathPHP\Exception\BadDataException; use MathPHP\Functions\Special; /** @@ -136,8 +137,8 @@ private function denominatorToSubscript(): string /** * Convert a character to an alternate script (super or subscript) * - * @param int $i number to convert - * @param array $chars conversion character map + * @param int $i number to convert + * @param array $chars conversion character map * * @return string */ @@ -459,7 +460,9 @@ public function equals(Rational $rn): bool * @param int $n numerator * @param int $d denominator * - * @return array + * @return array{int, int, int} + * + * @throws BadDataException */ private function normalize(int $w, int $n, int $d): array { @@ -479,7 +482,7 @@ private function normalize(int $w, int $n, int $d): array } $gcd = 0; while ($gcd != 1 && $n !== 0) { - $gcd = \abs(Algebra::gcd($n, $d)); + $gcd = \abs(Algebra::gcd((int)$n, (int)$d)); $n /= $gcd; $d /= $gcd; } @@ -493,6 +496,6 @@ private function normalize(int $w, int $n, int $d): array if ($n == 0) { $d = 1; } - return [$w, $n, $d]; + return [$w, (int)$n, (int)$d]; } } diff --git a/src/NumberTheory/Integer.php b/src/NumberTheory/Integer.php index 8fb35ee26..8695af2aa 100644 --- a/src/NumberTheory/Integer.php +++ b/src/NumberTheory/Integer.php @@ -106,7 +106,7 @@ public static function aliquotSum(int $n): int */ public static function radical(int $n): int { - return \array_product(\array_unique(self::primeFactorization($n))); + return (int)\array_product(\array_unique(self::primeFactorization($n))); } /** @@ -324,7 +324,7 @@ public static function isPerfectPower(int $n): bool * * @param int $n * - * @return array [m, k] + * @return array{0?: int|float, 1?: int|float} [m, k] */ public static function perfectPower(int $n): array { @@ -479,7 +479,7 @@ public static function sumOfDivisors(int $n): int $product *= $sum; } - return $product; + return (int)$product; } /** diff --git a/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php b/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php index 742b10610..ca4ba5b2d 100644 --- a/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php +++ b/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php @@ -37,20 +37,23 @@ class ClampedCubicSpline extends Interpolation /** * Interpolate * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely three numbers: x, y, and y' - * Example array: [[1,2,1], [2,3,0], [3,4,2]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args (Optional) An additional callback: our first derivative, - * and arguments of our callback functions: start, - * end, and n. - * Example: approximate($source, $derivative, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely three numbers: x, y, and y' + * Example array: [[1,2,1], [2,3,0], [3,4,2]]. + * Example callback: function($x) {return $x**2;} + * @param mixed ...$args + * (Optional) An additional callback: our first derivative, + * and arguments of our callback functions: start, + * end, and n. + * Example: approximate($source, $derivative, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return Piecewise The interpolating (piecewise) polynomial, as an - * instance of Piecewise. + * @return Piecewise + * The interpolating (piecewise) polynomial, as an + * instance of Piecewise. * * @throws Exception\BadDataException */ @@ -153,18 +156,22 @@ public static function interpolate($source, ...$args): Piecewise * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. - * @param array $args The arguments of our callback function: derivative, - * start, end, and n. Example: [$derivative, 0, 8, 5]. - * If $source is a set of arrays, $args will default to []. + * @param callable|array> $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. + * @param array{callable, number, number, number}|array $args + * The arguments of our callback function: derivative, + * start, end, and n. Example: [$derivative, 0, 8, 5]. + * If $source is a set of arrays, $args will default to []. + * + * @return array * - * @return array * @throws Exception\BadDataException if $source is not callable or a set of arrays */ public static function getSplinePoints($source, array $args = []): array { // Guard clause - source must be callable or array of points + // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -176,10 +183,11 @@ public static function getSplinePoints($source, array $args = []): array // Construct points from callable function $function = $source; + /** @var callable $derivative */ $derivative = $args[0]; - $start = $args[1]; - $end = $args[2]; - $n = $args[3]; + $start = floatval($args[1]); + $end = floatval($args[2]); + $n = intval($args[3]); return self::functionToSplinePoints($function, $derivative, $start, $end, $n); } @@ -194,7 +202,7 @@ public static function getSplinePoints($source, array $args = []): array * @param float $end the end of the interval * @param int $n the number of function evaluations * - * @return array + * @return array */ protected static function functionToSplinePoints(callable $function, callable $derivative, float $start, float $end, int $n): array { @@ -216,14 +224,14 @@ protected static function functionToSplinePoints(callable $function, callable $d * has precisely three numbers, and that no two points share the same first number * (x-component) * - * @param array $points Array of arrays (points) - * @param int $degree The minimum number of input arrays + * @param array $points Array of arrays (points) + * @param int $degree The minimum number of input arrays * * @throws Exception\BadDataException if there are less than two points * @throws Exception\BadDataException if any point does not contain three numbers * @throws Exception\BadDataException if two points share the same first number (x-component) */ - public static function validateSpline(array $points, int $degree = 2) + public static function validateSpline(array $points, int $degree = 2): void { if (\count($points) < $degree) { throw new Exception\BadDataException('You need to have at least $degree sets of coordinates (arrays) for this technique'); @@ -231,6 +239,7 @@ public static function validateSpline(array $points, int $degree = 2) $x_coordinates = []; foreach ($points as $point) { + // @phpstan-ignore-next-line if (\count($point) !== 3) { throw new Exception\BadDataException('Each array needs to have have precisely three numbers, representing x, y, and y-prime'); } diff --git a/src/NumericalAnalysis/Interpolation/Interpolation.php b/src/NumericalAnalysis/Interpolation/Interpolation.php index 63e813bff..b4c3d2b03 100644 --- a/src/NumericalAnalysis/Interpolation/Interpolation.php +++ b/src/NumericalAnalysis/Interpolation/Interpolation.php @@ -26,17 +26,20 @@ abstract class Interpolation * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array $source The source of our approximation. Should be either a callback function or a set of arrays. - * @param array $args The arguments of our callback function: start, end, and n. - * Example: [0, 8, 5]. If $source is a set of arrays, $args will default to []. + * @param callable|array $source + * The source of our approximation. Should be either a callback function or a set of arrays. + * @param array $args + * The arguments of our callback function: start, end, and n. + * Example: [0, 8, 5]. If $source is a set of arrays, $args will default to []. * - * @return array + * @return array * * @throws Exception\BadDataException if $source is not callable or a set of arrays */ public static function getPoints($source, array $args = []): array { // Guard clause - source must be callable or array of points + // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -50,7 +53,7 @@ public static function getPoints($source, array $args = []): array $function = $source; $start = $args[0]; $end = $args[1]; - $n = $args[2]; + $n = (int)$args[2]; return self::functionToPoints($function, $start, $end, $n); } @@ -64,7 +67,7 @@ public static function getPoints($source, array $args = []): array * @param float $end the end of the interval * @param int $n the number of function evaluations * - * @return array + * @return array */ protected static function functionToPoints(callable $function, float $start, float $end, int $n): array { @@ -84,14 +87,14 @@ protected static function functionToPoints(callable $function, float $start, flo * has precisely two numbers, and that no two points share the same first number * (x-component) * - * @param array $points Array of arrays (points) - * @param int $degree The minimum number of input arrays + * @param array $points Array of arrays (points) + * @param int $degree The minimum number of input arrays * * @throws Exception\BadDataException if there are less than two points * @throws Exception\BadDataException if any point does not contain two numbers * @throws Exception\BadDataException if two points share the same first number (x-component) */ - public static function validate(array $points, int $degree = 2) + public static function validate(array $points, int $degree = 2): void { if (\count($points) < $degree) { throw new Exception\BadDataException('You need to have at least $degree sets of coordinates (arrays) for this technique'); @@ -99,6 +102,7 @@ public static function validate(array $points, int $degree = 2) $x_coordinates = []; foreach ($points as $point) { + // @phpstan-ignore-next-line if (\count($point) !== 2) { throw new Exception\BadDataException('Each array needs to have have precisely two numbers, an x- and y-component'); } @@ -115,9 +119,9 @@ public static function validate(array $points, int $degree = 2) * Sorts our coordinates (arrays) by their x-component (first number) such * that consecutive coordinates have an increasing x-component. * - * @param array $points + * @param array> $points * - * @return array[] + * @return array> */ protected static function sort(array $points): array { diff --git a/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php b/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php index 23be3aae2..e461e1486 100644 --- a/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php +++ b/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php @@ -31,17 +31,19 @@ class LagrangePolynomial extends Interpolation /** * Interpolate * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return Polynomial The lagrange polynomial p(x) + * @return Polynomial The lagrange polynomial p(x) * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php b/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php index e28492028..7326d2ee9 100644 --- a/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php +++ b/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php @@ -34,18 +34,21 @@ class NaturalCubicSpline extends Interpolation /** * Interpolate * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return Piecewise The interpolating (piecewise) polynomial, as an - * instance of Piecewise. + * @return Piecewise + * The interpolating (piecewise) polynomial, as an + * instance of Piecewise. * * @throws Exception\BadDataException */ diff --git a/src/NumericalAnalysis/Interpolation/NevillesMethod.php b/src/NumericalAnalysis/Interpolation/NevillesMethod.php index 3c6b92bae..b32318571 100644 --- a/src/NumericalAnalysis/Interpolation/NevillesMethod.php +++ b/src/NumericalAnalysis/Interpolation/NevillesMethod.php @@ -27,18 +27,21 @@ class NevillesMethod extends Interpolation /** * Interpolate * - * @param float $target The point at which we are interpolation - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param float[] ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param float $target + * The point at which we are interpolation + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The interpolated value at our target + * @return float The interpolated value at our target * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php b/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php index 25c262ba3..8f8550f7c 100644 --- a/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php +++ b/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php @@ -26,17 +26,19 @@ class NewtonPolynomialForward extends Interpolation /** * Interpolate * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return callable The interpolating polynomial p(x) + * @return callable The interpolating polynomial p(x) * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php b/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php index bcbb64746..41fe2103f 100644 --- a/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php +++ b/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php @@ -53,16 +53,16 @@ class RegularGridInterpolator /** @var string Interpolation method (linear or nearest) */ private $method; - /** @var array[] Points defining the regular grid in n dimensions */ + /** @var array> Points defining the regular grid in n dimensions */ private $grid; - /** @var array Data on the regular grid in n dimensions */ + /** @var array Data on the regular grid in n dimensions */ private $values; /** - * @param array $points Points defining the regular grid in n dimensions - * @param array $values Data on the regular grid in n dimensions - * @param string $method (optional - default: linear) Interpolation method (linear or nearest) + * @param array> $points Points defining the regular grid in n dimensions + * @param array $values Data on the regular grid in n dimensions + * @param string $method (optional - default: linear) Interpolation method (linear or nearest) * * @throws Exception\BadDataException the points and value dimensions do not align, or if an unknown method is used */ @@ -86,7 +86,7 @@ public function __construct(array $points, array $values, string $method = self: /** * Count dimensions of a multi-dimensional array * - * @param array $array + * @param array $array * * @return int */ @@ -104,7 +104,7 @@ private function countDimensions(array $array): int /** * Interpolation of the grid at some coordinates * - * @param array $xi n-dimensional array containing the coordinates to sample the gridded data at + * @param array $xi n-dimensional array containing the coordinates to sample the gridded data at * * @return float * @@ -126,8 +126,8 @@ public function __invoke(array $xi): float } /** - * @param array $indices - * @param array $normDistances + * @param array $indices + * @param array $normDistances * * @return float|int */ @@ -155,8 +155,8 @@ private function evaluateLinear(array $indices, array $normDistances) } /** - * @param array $indices - * @param array $normDistances + * @param array $indices + * @param array $normDistances * * @return float|int */ @@ -169,6 +169,7 @@ private function evaluateNearest(array $indices, array $normDistances) : $i + 1; } + /** @var float|int */ return $this->flatCall($this->values, $idxRes); } @@ -177,7 +178,7 @@ private function evaluateNearest(array $indices, array $normDistances) * * @param float[] $xi 1-dimensional array ( search point = [x,y,z ....] ) * - * @return array[] (indices in grid for search point, normDistances for search point) + * @return array{int[], float[]} (indices in grid for search point, normDistances for search point) */ private function findIndices($xi): array { @@ -209,15 +210,16 @@ private function findIndices($xi): array /** * Dynamically accessing multidimensional array value. * - * @param array $data - * @param array $keys + * @param array $data + * @param array $keys * - * @return array|mixed + * @return array|mixed */ private function flatCall(array $data, array $keys) { $current = $data; foreach ($keys as $key) { + // @phpstan-ignore-next-line $current = $current[$key]; } @@ -229,15 +231,19 @@ private function flatCall(array $data, array $keys) * Output is lexicographic ordered * * @param mixed ...$args ...$iterables[, $repeat] -* - * @return \Generator + * + * @return \Generator> */ private function product(...$args): \Generator { + /** @var int $repeat */ $repeat = \array_pop($args); - $pools = \array_merge(...\array_fill(0, $repeat, $args)); + /** @var array> $fill */ + $fill = \array_fill(0, $repeat, $args); + $pools = \array_merge(...$fill); $result = [[]]; + /** @var array $pool */ foreach ($pools as $pool) { $result_inner = []; foreach ($result as $x) { diff --git a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php index c926afd65..9cc214af0 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php @@ -51,19 +51,23 @@ class FivePointFormula extends NumericalDifferentiation * * where ζ₀ lies between x₀ and x₀ + 4h * - * @param float $target The value at which we are approximating the derivative - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4], [4,5], [5,6]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($number, $source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param float $target + * The value at which we are approximating the derivative + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4], [4,5], [5,6]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($number, $source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation of f'($target), i.e. the derivative - * of our input at our target point + * @return float + * The approximation of f'($target), i.e. the derivative + * of our input at our target point * * @throws Exception\BadDataException */ diff --git a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php index 2b8b3bbd2..172157bef 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php @@ -22,6 +22,12 @@ abstract class NumericalDifferentiation /** @var int Index of y */ protected const Y = 1; + /** + * @param float $target + * @param callable|array $source + * @param number ...$args + * @return mixed + */ abstract public static function differentiate(float $target, $source, ...$args); /** @@ -35,18 +41,21 @@ abstract public static function differentiate(float $target, $source, ...$args); * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. - * @param array $args The arguments of our callback function: start, - * end, and n. Example: [0, 8, 5]. If $source is a - * set of arrays, $args will default to []. + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. + * @param array $args + * The arguments of our callback function: start, + * end, and n. Example: [0, 8, 5]. If $source is a + * set of arrays, $args will default to []. * - * @return array + * @return array * @throws Exception\BadDataException if $source is not callable or a set of arrays */ public static function getPoints($source, array $args = []): array { // Guard clause - source must be callable or array of points + // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -74,7 +83,7 @@ public static function getPoints($source, array $args = []): array * @param int|float $end the end of the interval * @param int|float $n the number of function evaluations * - * @return array[] + * @return array */ protected static function functionToPoints(callable $function, $start, $end, $n): array { @@ -95,14 +104,14 @@ protected static function functionToPoints(callable $function, $start, $end, $n) * has precisely two numbers, and that no two points share the same first number * (x-component) * - * @param array $points Array of arrays (points) - * @param int $degree The number of input arrays + * @param array $points Array of arrays (points) + * @param int $degree The number of input arrays * * @throws Exception\BadDataException if there are not enough input arrays * @throws Exception\BadDataException if any point does not contain two numbers * @throws Exception\BadDataException if two points share the same first number (x-component) */ - public static function validate(array $points, int $degree) + public static function validate(array $points, int $degree): void { if (\count($points) != $degree) { throw new Exception\BadDataException("You need to have $degree sets of coordinates (arrays) for this technique"); @@ -110,6 +119,7 @@ public static function validate(array $points, int $degree) $x_coordinates = []; foreach ($points as $point) { + // @phpstan-ignore-next-line if (\count($point) !== 2) { throw new Exception\BadDataException('Each array needs to have have precisely two numbers, an x- and y-component'); } @@ -126,9 +136,9 @@ public static function validate(array $points, int $degree) * Sorts our coordinates (arrays) by their x-component (first number) such * that consecutive coordinates have an increasing x-component. * - * @param array[] $points + * @param array $points * - * @return array[] + * @return array */ protected static function sort(array $points): array { @@ -143,12 +153,14 @@ protected static function sort(array $points): array * Ensures that the length of each subinterval is equal, or equivalently, * that the spacing between each point is equal * - * @param array[] $sorted Points sorted by (increasing) x-component + * @param array $sorted Points sorted by (increasing) x-component * * @throws Exception\BadDataException if the spacing between any two points is not equal * to the average spacing between every point + * + * FIXME: maybe rename to checkIsSpacingConstant? */ - public static function isSpacingConstant(array $sorted) + public static function isSpacingConstant(array $sorted): void { $x = self::X; $length = \count($sorted); @@ -164,12 +176,14 @@ public static function isSpacingConstant(array $sorted) /** * Ensures that our target is the x-component of one of the points we supply * - * @param int|float $target The value at which we are approximating the derivative - * @param array $sorted Points sorted by (increasing) x-component + * @param int|float $target The value at which we are approximating the derivative + * @param array $sorted Points sorted by (increasing) x-component * * @throws Exception\BadDataException if $target is not contained in the array of our x-components + * + * FIXME: maybe rename to checkIsTargetInPoints? */ - public static function isTargetInPoints($target, array $sorted) + public static function isTargetInPoints($target, array $sorted): void { $xComponents = \array_map( function (array $point) { diff --git a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php index 6a62aa536..af150142d 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php @@ -40,19 +40,23 @@ class SecondDerivativeMidpointFormula extends NumericalDifferentiation * * where ζ lies between x₀ - h and x₀ + h * - * @param float $target The value at which we are approximating the derivative - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: differentiate($target, $source, 0, 8, 3). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param float $target + * The value at which we are approximating the derivative + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: differentiate($target, $source, 0, 8, 3). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation of f'($target), i.e. the derivative - * of our input at our target point + * @return float + * The approximation of f'($target), i.e. the derivative + * of our input at our target point * * @throws Exception\BadDataException */ diff --git a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php index 6161aed49..e36213358 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php @@ -51,19 +51,23 @@ class ThreePointFormula extends NumericalDifferentiation * * where ζ₀ lies between x₀ and x₀ + 2h * - * @param float $target The value at which we are approximating the derivative - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: differentiate($target, $source, 0, 8, 3). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param float $target + * The value at which we are approximating the derivative + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: differentiate($target, $source, 0, 8, 3). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation of f'($target), i.e. the derivative - * of our input at our target point + * @return float + * The approximation of f'($target), i.e. the derivative + * of our input at our target point * * @throws Exception\BadDataException */ diff --git a/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php b/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php index 07e04993d..617acd69c 100644 --- a/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php @@ -63,17 +63,19 @@ class BoolesRule extends NumericalIntegration * ⁱ⁼¹ 45 * where h = (xn - x₁) / (n - 1) * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4], [4,5], [5,6]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 4). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4], [4,5], [5,6]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 4). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation to the integral of f(x) + * @return float The approximation to the integral of f(x) * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php b/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php index b53cb39c5..bf0e4917b 100644 --- a/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php @@ -55,17 +55,19 @@ class MidpointRule extends NumericalIntegration * * where h = xᵢ₊₁ - xᵢ * note: this implementation does not compute the error term. - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation to the integral of f(x) + * @return float The approximation to the integral of f(x) * * @throws Exception\BadDataException */ diff --git a/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php b/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php index 17a24fd09..9cc6d40a0 100644 --- a/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php +++ b/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php @@ -22,6 +22,11 @@ abstract class NumericalIntegration /** @var int Index of y */ protected const Y = 1; + /** + * @param callable|array $source + * @param number ...$args + * @return number + */ abstract public static function approximate($source, ...$args); /** @@ -35,19 +40,22 @@ abstract public static function approximate($source, ...$args); * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. - * @param array $args The arguments of our callback function: start, - * end, and n. Example: [0, 8, 5]. If $source is a - * set of arrays, $args will default to []. + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. + * @param array $args + * The arguments of our callback function: start, + * end, and n. Example: [0, 8, 5]. If $source is a + * set of arrays, $args will default to []. * - * @return array + * @return array * * @throws Exception\BadDataException if $source is not callable or a set of arrays */ public static function getPoints($source, array $args = []): array { // Guard clause - source must be callable or array of points + // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -61,7 +69,7 @@ public static function getPoints($source, array $args = []): array $function = $source; $start = $args[0]; $end = $args[1]; - $n = $args[2]; + $n = (int)$args[2]; return self::functionToPoints($function, $start, $end, $n); } @@ -74,7 +82,7 @@ public static function getPoints($source, array $args = []): array * @param float $end the end of the interval * @param int $n the number of function evaluations * - * @return array + * @return array */ protected static function functionToPoints(callable $function, float $start, float $end, int $n): array { @@ -94,14 +102,14 @@ protected static function functionToPoints(callable $function, float $start, flo * has precisely two numbers, and that no two points share the same first number * (x-component) * - * @param array $points Array of arrays (points) - * @param int $degree The minimum number of input arrays + * @param array $points Array of arrays (points) + * @param int $degree The minimum number of input arrays * * @throws Exception\BadDataException if there are less than two points * @throws Exception\BadDataException if any point does not contain two numbers * @throws Exception\BadDataException if two points share the same first number (x-component) */ - public static function validate(array $points, int $degree = 2) + public static function validate(array $points, int $degree = 2): void { if (\count($points) < $degree) { throw new Exception\BadDataException("You need to have at least $degree sets of coordinates (arrays) for this technique"); @@ -109,6 +117,7 @@ public static function validate(array $points, int $degree = 2) $x_coordinates = []; foreach ($points as $point) { + // @phpstan-ignore-next-line if (\count($point) !== 2) { throw new Exception\BadDataException('Each array needs to have have precisely two numbers, an x- and y-component'); } @@ -125,9 +134,9 @@ public static function validate(array $points, int $degree = 2) * Sorts our coordinates (arrays) by their x-component (first number) such * that consecutive coordinates have an increasing x-component. * - * @param array[] $points + * @param array $points * - * @return array[] + * @return array */ protected static function sort(array $points): array { diff --git a/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php b/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php index 8ee7fe1a8..430ea3bd2 100644 --- a/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php +++ b/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php @@ -58,17 +58,19 @@ class RectangleMethod extends NumericalIntegration * * where h = xᵢ₊₁ - xᵢ * note: this implementation does not compute the error term. - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation to the integral of f(x) + * @return float The approximation to the integral of f(x) * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php b/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php index c472b8729..aba2f456c 100644 --- a/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php @@ -62,17 +62,19 @@ class SimpsonsRule extends NumericalIntegration * ⁱ⁼¹ 3 * where h = (xn - x₁) / (n - 1) * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation to the integral of f(x) + * @return float The approximation to the integral of f(x) * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php b/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php index 32df65ff7..a19d656c2 100644 --- a/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php @@ -63,17 +63,19 @@ class SimpsonsThreeEighthsRule extends NumericalIntegration * ⁱ⁼¹ 8 * where h = (xn - x₁) / (n - 1) * - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4], [4,5]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 4). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4], [4,5]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 4). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation to the integral of f(x) + * @return float The approximation to the integral of f(x) * * @throws Exception\BadDataException * @throws Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php b/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php index 4acfa66ba..e0f597dbc 100644 --- a/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php @@ -59,17 +59,19 @@ class TrapezoidalRule extends NumericalIntegration * * where h = xᵢ₊₁ - xᵢ * note: this implementation does not compute the error term. - * @param callable|array $source The source of our approximation. Should be either - * a callback function or a set of arrays. Each array - * (point) contains precisely two numbers, an x and y. - * Example array: [[1,2], [2,3], [3,4]]. - * Example callback: function($x) {return $x**2;} - * @param int|float ...$args The arguments of our callback function: start, - * end, and n. Example: approximate($source, 0, 8, 5). - * If $source is a set of points, do not input any - * $args. Example: approximate($source). + * @param callable|array $source + * The source of our approximation. Should be either + * a callback function or a set of arrays. Each array + * (point) contains precisely two numbers, an x and y. + * Example array: [[1,2], [2,3], [3,4]]. + * Example callback: function($x) {return $x**2;} + * @param int|float ...$args + * The arguments of our callback function: start, + * end, and n. Example: approximate($source, 0, 8, 5). + * If $source is a set of points, do not input any + * $args. Example: approximate($source). * - * @return float The approximation to the integral of f(x) + * @return float The approximation to the integral of f(x) * * @throws Exception\BadDataException * @throws \MathPHP\Exception\IncorrectTypeException diff --git a/src/NumericalAnalysis/NumericalIntegration/Validation.php b/src/NumericalAnalysis/NumericalIntegration/Validation.php index 28373dc35..fb290a917 100644 --- a/src/NumericalAnalysis/NumericalIntegration/Validation.php +++ b/src/NumericalAnalysis/NumericalIntegration/Validation.php @@ -14,11 +14,11 @@ class Validation * Ensures that the length of each subinterval is equal, or equivalently, * that the spacing between each point is equal * - * @param array $sorted Points sorted by (increasing) x-component + * @param array> $sorted Points sorted by (increasing) x-component * * @throws Exception\BadDataException if the spacing between any two points is not equal to the average spacing between every point */ - public static function isSpacingConstant(array $sorted) + public static function isSpacingConstant(array $sorted): void { $length = \count($sorted); if ($length <= 2) { @@ -39,12 +39,12 @@ public static function isSpacingConstant(array $sorted) * Ensures that the number of subintervals is a multiple of m, or * equivalently, if there are n points, that n-1 is a multiple of m * - * @param array $points - * @param int $m The number that n-1 should be a multiple of + * @param array $points + * @param int $m The number that n-1 should be a multiple of * * @throws Exception\BadDataException if the number of points minus 1 is not a multiple of m */ - public static function isSubintervalsMultiple(array $points, int $m) + public static function isSubintervalsMultiple(array $points, int $m): void { if ((\count($points) - 1) % $m !== 0) { throw new Exception\BadDataException( diff --git a/src/NumericalAnalysis/RootFinding/BisectionMethod.php b/src/NumericalAnalysis/RootFinding/BisectionMethod.php index 5b3ccd31b..6360d533f 100644 --- a/src/NumericalAnalysis/RootFinding/BisectionMethod.php +++ b/src/NumericalAnalysis/RootFinding/BisectionMethod.php @@ -74,7 +74,7 @@ public static function solve(callable $function, $a, $b, $tol) * @throws Exception\BadDataException if $a = $b * @throws Exception\BadDataException if f($a) and f($b) share the same sign */ - private static function validate(callable $function, $a, $b, $tol) + private static function validate(callable $function, $a, $b, $tol): void { Validation::tolerance($tol); Validation::interval($a, $b); diff --git a/src/NumericalAnalysis/RootFinding/FixedPointIteration.php b/src/NumericalAnalysis/RootFinding/FixedPointIteration.php index 59e5619b4..678cd09df 100644 --- a/src/NumericalAnalysis/RootFinding/FixedPointIteration.php +++ b/src/NumericalAnalysis/RootFinding/FixedPointIteration.php @@ -67,7 +67,7 @@ public static function solve(callable $function, $a, $b, $p, $tol) * @throws Exception\BadDataException if $a = $b * @throws Exception\OutOfBoundsException if either $p > $a or $p < $b return false */ - private static function validate($a, $b, $p, $tol) + private static function validate($a, $b, $p, $tol): void { Validation::tolerance($tol); Validation::interval($a, $b); diff --git a/src/NumericalAnalysis/RootFinding/NewtonsMethod.php b/src/NumericalAnalysis/RootFinding/NewtonsMethod.php index 34820c967..1a94effe5 100644 --- a/src/NumericalAnalysis/RootFinding/NewtonsMethod.php +++ b/src/NumericalAnalysis/RootFinding/NewtonsMethod.php @@ -17,13 +17,13 @@ class NewtonsMethod * $args is an array of parameters to pass to $function, but having the element that * will be changed and serve as the initial guess in position $position. * - * @param callable $function f(x) callback function - * @param array $args Parameters to pass to callback function. The initial value for the - * parameter of interest must be in this array. - * @param int|float $target Value of f(x) we a trying to solve for - * @param float $tol Tolerance; How close to the actual solution we would like. - * @param int $position Which element in the $args array will be changed; also serves as initial guess - * @param int $iterations + * @param callable $function f(x) callback function + * @param array $args Parameters to pass to callback function. The initial value for the + * parameter of interest must be in this array. + * @param int|float $target Value of f(x) we a trying to solve for + * @param float $tol Tolerance; How close to the actual solution we would like. + * @param int $position Which element in the $args array will be changed; also serves as initial guess + * @param int $iterations * * @return number * diff --git a/src/NumericalAnalysis/RootFinding/Validation.php b/src/NumericalAnalysis/RootFinding/Validation.php index c0e0bc4fd..913bd3697 100644 --- a/src/NumericalAnalysis/RootFinding/Validation.php +++ b/src/NumericalAnalysis/RootFinding/Validation.php @@ -16,7 +16,7 @@ class Validation * * @throws Exception\OutOfBoundsException if $tol (the tolerance) is negative */ - public static function tolerance($tol) + public static function tolerance($tol): void { if ($tol < 0) { throw new Exception\OutOfBoundsException('Tolerance must be greater than zero.'); @@ -31,7 +31,7 @@ public static function tolerance($tol) * * @throws Exception\BadDataException if $a = $b */ - public static function interval($a, $b) + public static function interval($a, $b): void { if ($a === $b) { throw new Exception\BadDataException('Start point and end point of interval cannot be the same.'); diff --git a/src/Probability/Distribution/Continuous/Beta.php b/src/Probability/Distribution/Continuous/Beta.php index 95f52e7fb..eb3883fc5 100644 --- a/src/Probability/Distribution/Continuous/Beta.php +++ b/src/Probability/Distribution/Continuous/Beta.php @@ -16,7 +16,7 @@ class Beta extends Continuous * Distribution parameter bounds limits * α ∈ (0,∞) * β ∈ (0,∞) - * @var array + * @var array{"α": string, "β": string} */ public const PARAMETER_LIMITS = [ 'α' => '(0,∞)', @@ -26,7 +26,7 @@ class Beta extends Continuous /** * Distribution support bounds limits * x ∈ [0,1] - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '[0,1]', diff --git a/src/Probability/Distribution/Continuous/Cauchy.php b/src/Probability/Distribution/Continuous/Cauchy.php index 616f8639e..941b73b29 100644 --- a/src/Probability/Distribution/Continuous/Cauchy.php +++ b/src/Probability/Distribution/Continuous/Cauchy.php @@ -14,7 +14,7 @@ class Cauchy extends Continuous * Distribution parameter bounds limits * x₀ ∈ (-∞,∞) * γ ∈ (0,∞) - * @var array + * @var array{"x₀": string, "γ": string} */ public const PARAMETER_LIMITS = [ 'x₀' => '(-∞,∞)', @@ -24,7 +24,7 @@ class Cauchy extends Continuous /** * Distribution support bounds limits * x ∈ (-∞,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/ChiSquared.php b/src/Probability/Distribution/Continuous/ChiSquared.php index d08a5d8e9..85c945195 100644 --- a/src/Probability/Distribution/Continuous/ChiSquared.php +++ b/src/Probability/Distribution/Continuous/ChiSquared.php @@ -14,7 +14,7 @@ class ChiSquared extends Continuous /** * Distribution parameter bounds limits * k ∈ [1,∞) - * @var array + * @var array{"k": string} */ public const PARAMETER_LIMITS = [ 'k' => '[1,∞)', @@ -23,7 +23,7 @@ class ChiSquared extends Continuous /** * Distribution support bounds limits * x ∈ [0,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '[0,∞)', diff --git a/src/Probability/Distribution/Continuous/Continuous.php b/src/Probability/Distribution/Continuous/Continuous.php index bebc9290d..60f1a19c5 100644 --- a/src/Probability/Distribution/Continuous/Continuous.php +++ b/src/Probability/Distribution/Continuous/Continuous.php @@ -118,5 +118,8 @@ public function rand() return $this->inverse(\random_int(0, \PHP_INT_MAX) / \PHP_INT_MAX); } + /** + * @return number + */ abstract public function median(); } diff --git a/src/Probability/Distribution/Continuous/ContinuousDistribution.php b/src/Probability/Distribution/Continuous/ContinuousDistribution.php index 17d814ed3..c4426a82d 100644 --- a/src/Probability/Distribution/Continuous/ContinuousDistribution.php +++ b/src/Probability/Distribution/Continuous/ContinuousDistribution.php @@ -28,7 +28,7 @@ public function cdf(float $x); /** * Mean average * - * @return mixed + * @return number */ public function mean(); } diff --git a/src/Probability/Distribution/Continuous/DiracDelta.php b/src/Probability/Distribution/Continuous/DiracDelta.php index 5c2bd5236..6ed2ed2c2 100644 --- a/src/Probability/Distribution/Continuous/DiracDelta.php +++ b/src/Probability/Distribution/Continuous/DiracDelta.php @@ -11,7 +11,7 @@ class DiracDelta extends Continuous /** * Distribution parameter bounds limits * - * @var array + * @var array{} */ public const PARAMETER_LIMITS = []; @@ -19,7 +19,7 @@ class DiracDelta extends Continuous * Distribution support bounds limits * x ∈ (-∞,∞) * - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/Exponential.php b/src/Probability/Distribution/Continuous/Exponential.php index d90ae77b7..73ec0da30 100644 --- a/src/Probability/Distribution/Continuous/Exponential.php +++ b/src/Probability/Distribution/Continuous/Exponential.php @@ -13,7 +13,7 @@ class Exponential extends Continuous /** * Distribution parameter bounds limits * λ ∈ (0,∞) - * @var array + * @var array{"λ": string} */ public const PARAMETER_LIMITS = [ 'λ' => '(0,∞)', @@ -22,7 +22,7 @@ class Exponential extends Continuous /** * Distribution support bounds limits * x ∈ [0,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '[0,∞)', diff --git a/src/Probability/Distribution/Continuous/F.php b/src/Probability/Distribution/Continuous/F.php index 3905a4594..1985cddae 100644 --- a/src/Probability/Distribution/Continuous/F.php +++ b/src/Probability/Distribution/Continuous/F.php @@ -15,7 +15,7 @@ class F extends Continuous * Distribution parameter bounds limits * d₁ ∈ (0,∞) * d₂ ∈ (0,∞) - * @var array + * @var array{"d₁": string, "d₂": string} */ public const PARAMETER_LIMITS = [ 'd₁' => '(0,∞)', @@ -25,7 +25,7 @@ class F extends Continuous /** * Distribution Support bounds limits * x ∈ [0,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '[0,∞)', diff --git a/src/Probability/Distribution/Continuous/Gamma.php b/src/Probability/Distribution/Continuous/Gamma.php index d90fc27d4..f39dbc086 100644 --- a/src/Probability/Distribution/Continuous/Gamma.php +++ b/src/Probability/Distribution/Continuous/Gamma.php @@ -15,7 +15,7 @@ class Gamma extends Continuous * Distribution parameter bounds limits * k ∈ (0,∞) * θ ∈ (0,∞) - * @var array + * @var array{"k": string, "θ": string} */ public const PARAMETER_LIMITS = [ 'k' => '(0,∞)', @@ -25,7 +25,7 @@ class Gamma extends Continuous /** * Distribution suport bounds limits * x ∈ (0,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(0,∞)', diff --git a/src/Probability/Distribution/Continuous/Laplace.php b/src/Probability/Distribution/Continuous/Laplace.php index 29f149177..ef780b15a 100644 --- a/src/Probability/Distribution/Continuous/Laplace.php +++ b/src/Probability/Distribution/Continuous/Laplace.php @@ -10,7 +10,7 @@ class Laplace extends Continuous * Distribution parameter bounds limits * μ ∈ (-∞,∞) * b ∈ (0,∞) - * @var array + * @var array{"μ": string, "b": string} */ public const PARAMETER_LIMITS = [ 'μ' => '(-∞,∞)', @@ -20,7 +20,7 @@ class Laplace extends Continuous /** * Distribution support bounds limits * x ∈ (-∞,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/LogLogistic.php b/src/Probability/Distribution/Continuous/LogLogistic.php index 0a1a14fd9..9308c975e 100644 --- a/src/Probability/Distribution/Continuous/LogLogistic.php +++ b/src/Probability/Distribution/Continuous/LogLogistic.php @@ -15,7 +15,7 @@ class LogLogistic extends Continuous * Distribution parameter bounds limits * α ∈ (0,∞) * β ∈ (0,∞) - * @var array + * @var array{"α": string, "β": string} */ public const PARAMETER_LIMITS = [ 'α' => '(0,∞)', @@ -25,7 +25,7 @@ class LogLogistic extends Continuous /** * Distribution support bounds limits * x ∈ [0,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '[0,∞)', diff --git a/src/Probability/Distribution/Continuous/LogNormal.php b/src/Probability/Distribution/Continuous/LogNormal.php index 21c872fad..45529c94b 100644 --- a/src/Probability/Distribution/Continuous/LogNormal.php +++ b/src/Probability/Distribution/Continuous/LogNormal.php @@ -11,7 +11,7 @@ class LogNormal extends Continuous * Distribution parameter bounds limits * μ ∈ (-∞,∞) * σ ∈ (0,∞) - * @var array + * @var array{"μ": string, "σ": string} */ public const PARAMETER_LIMITS = [ 'μ' => '(-∞,∞)', @@ -21,7 +21,7 @@ class LogNormal extends Continuous /** * Distribution support bounds limits * x ∈ (0,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(0,∞)', diff --git a/src/Probability/Distribution/Continuous/Logistic.php b/src/Probability/Distribution/Continuous/Logistic.php index 6e3e072d1..700c05f90 100644 --- a/src/Probability/Distribution/Continuous/Logistic.php +++ b/src/Probability/Distribution/Continuous/Logistic.php @@ -14,7 +14,7 @@ class Logistic extends Continuous * Distribution parameter bounds limits * μ ∈ (-∞,∞) * s ∈ (0,∞) - * @var array + * @var array{"μ": string, "s": string} */ public const PARAMETER_LIMITS = [ 'μ' => '(-∞,∞)', @@ -24,7 +24,7 @@ class Logistic extends Continuous /** * Distribution support bounds limits * x ∈ (-∞,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/NoncentralT.php b/src/Probability/Distribution/Continuous/NoncentralT.php index 93633f7f7..b0a9f3cef 100644 --- a/src/Probability/Distribution/Continuous/NoncentralT.php +++ b/src/Probability/Distribution/Continuous/NoncentralT.php @@ -16,7 +16,7 @@ class NoncentralT extends Continuous * Distribution parameter bounds limits * ν ∈ (0,∞) * μ ∈ (-∞,∞) - * @var array + * @var array{"ν": string, "μ": string} */ public const PARAMETER_LIMITS = [ 'ν' => '(0,∞)', @@ -26,7 +26,7 @@ class NoncentralT extends Continuous /** * Distribution support bounds limits * x ∈ (-∞,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/Normal.php b/src/Probability/Distribution/Continuous/Normal.php index 5534d0cbd..6bb536987 100644 --- a/src/Probability/Distribution/Continuous/Normal.php +++ b/src/Probability/Distribution/Continuous/Normal.php @@ -15,7 +15,7 @@ class Normal extends Continuous * Distribution parameter bounds limits * μ ∈ (-∞,∞) * σ ∈ (0,∞) - * @var array + * @var array{"μ": string, "σ": string} */ public const PARAMETER_LIMITS = [ 'μ' => '(-∞,∞)', @@ -25,7 +25,7 @@ class Normal extends Continuous /** * Distribution support bounds limits * x ∈ (-∞,∞) - * @var array + * @var array */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/Pareto.php b/src/Probability/Distribution/Continuous/Pareto.php index b1cc38084..ad12b8233 100644 --- a/src/Probability/Distribution/Continuous/Pareto.php +++ b/src/Probability/Distribution/Continuous/Pareto.php @@ -14,7 +14,7 @@ class Pareto extends Continuous * Distribution parameter bounds limits * a ∈ (0,∞) * b ∈ (0,∞) - * @var array + * @var array{"a": string, "b": string} */ public const PARAMETER_LIMITS = [ 'a' => '(0,∞)', @@ -24,7 +24,7 @@ class Pareto extends Continuous /** * Distribution support bounds limits * x ∈ (0,∞) - * @var array + * @var array{"x": string, "a": string, "b": string} */ public const SUPPORT_LIMITS = [ 'x' => '(0,∞)', diff --git a/src/Probability/Distribution/Continuous/StandardNormal.php b/src/Probability/Distribution/Continuous/StandardNormal.php index 0686a94e8..18220c241 100644 --- a/src/Probability/Distribution/Continuous/StandardNormal.php +++ b/src/Probability/Distribution/Continuous/StandardNormal.php @@ -2,8 +2,6 @@ namespace MathPHP\Probability\Distribution\Continuous; -use MathPHP\Functions\Support; - /** * Standard normal distribution * The simplest case of a normal distribution. @@ -27,7 +25,7 @@ class StandardNormal extends Normal * Distribution parameter bounds limits * μ ∈ [0,0] * σ ∈ [1,1] - * @var array + * @var array{"μ": string, "σ": string} */ public const PARAMETER_LIMITS = [ 'μ' => '[-0,0]', @@ -37,7 +35,7 @@ class StandardNormal extends Normal /** * Distribution support bounds limits * z ∈ (-∞,∞) - * @var array + * @var array{z: string} */ public const SUPPORT_LIMITS = [ 'z' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/StudentT.php b/src/Probability/Distribution/Continuous/StudentT.php index 24aa3cb49..fa553d040 100644 --- a/src/Probability/Distribution/Continuous/StudentT.php +++ b/src/Probability/Distribution/Continuous/StudentT.php @@ -14,7 +14,7 @@ class StudentT extends Continuous /** * Distribution parameter bounds limits * ν ∈ (0,∞) - * @var array + * @var array{"ν": string} */ public const PARAMETER_LIMITS = [ 'ν' => '(0,∞)', @@ -23,7 +23,7 @@ class StudentT extends Continuous /** * Distribution support bounds limits * t ∈ (-∞,∞) - * @var array + * @var array{"t": string} */ public const SUPPORT_LIMITS = [ 't' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/Uniform.php b/src/Probability/Distribution/Continuous/Uniform.php index 70b9f5dc1..aa487dfbd 100644 --- a/src/Probability/Distribution/Continuous/Uniform.php +++ b/src/Probability/Distribution/Continuous/Uniform.php @@ -10,7 +10,7 @@ class Uniform extends Continuous * Distribution parameter bounds limits * a ∈ (-∞,∞) * b ∈ (-∞,∞) - * @var array + * @var array{"a": string, "b": string} */ public const PARAMETER_LIMITS = [ 'a' => '(-∞,∞)', @@ -20,7 +20,7 @@ class Uniform extends Continuous /** * Distribution support bounds limits * x ∈ (-∞,∞) - * @var array + * @var array{"x": string} */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Continuous/Weibull.php b/src/Probability/Distribution/Continuous/Weibull.php index fff6d71cc..8b4db25df 100644 --- a/src/Probability/Distribution/Continuous/Weibull.php +++ b/src/Probability/Distribution/Continuous/Weibull.php @@ -11,7 +11,7 @@ class Weibull extends Continuous * Distribution parameter bounds limits * λ ∈ (0,∞) * k ∈ (0,∞) - * @var array + * @var array{"k": string, "λ": string} */ public const PARAMETER_LIMITS = [ 'k' => '(0,∞)', @@ -21,7 +21,7 @@ class Weibull extends Continuous /** * Distribution support bounds limits * x ∈ [0,∞) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Discrete/Bernoulli.php b/src/Probability/Distribution/Discrete/Bernoulli.php index 6977ec7f6..3ad8b66fa 100644 --- a/src/Probability/Distribution/Discrete/Bernoulli.php +++ b/src/Probability/Distribution/Discrete/Bernoulli.php @@ -14,7 +14,7 @@ class Bernoulli extends Discrete /** * Distribution parameter bounds limits * p ∈ (0,1) - * @var array + * @var array{"p": string, "q": string} */ public const PARAMETER_LIMITS = [ 'p' => '(0,1)', @@ -25,7 +25,7 @@ class Bernoulli extends Discrete * Distribution support bounds limits * k ∈ [0,1] * p ∈ (0,1) - * @var array + * @var array{"k": string} */ public const SUPPORT_LIMITS = [ 'k' => '[0,1]', diff --git a/src/Probability/Distribution/Discrete/Binomial.php b/src/Probability/Distribution/Discrete/Binomial.php index b081ef1c8..b7852969d 100644 --- a/src/Probability/Distribution/Discrete/Binomial.php +++ b/src/Probability/Distribution/Discrete/Binomial.php @@ -17,7 +17,7 @@ class Binomial extends Discrete * Distribution parameter bounds limits * n ∈ [0,∞) * p ∈ [0,1] - * @var array + * @var array{"n": string, "p": string} */ public const PARAMETER_LIMITS = [ 'n' => '[0,∞)', @@ -27,7 +27,7 @@ class Binomial extends Discrete /** * Distribution support bounds limits * r ∈ [0,∞) - * @var array + * @var array{"r": string} */ public const SUPPORT_LIMITS = [ 'r' => '[0,∞)', diff --git a/src/Probability/Distribution/Discrete/Categorical.php b/src/Probability/Distribution/Discrete/Categorical.php index 30cb693b3..ae08fc3af 100644 --- a/src/Probability/Distribution/Discrete/Categorical.php +++ b/src/Probability/Distribution/Discrete/Categorical.php @@ -20,7 +20,7 @@ class Categorical extends Discrete private $k; /** - * @var array + * @var array * Probability of each category * If associative array, category names are keys. * Otherwise, category names are array indexes. @@ -30,8 +30,8 @@ class Categorical extends Discrete /** * Distribution constructor * - * @param int $k number of categories - * @param array $probabilities of each category - If associative array, category names are keys. + * @param int $k number of categories + * @param array $probabilities of each category - If associative array, category names are keys. * Otherwise, category names are array indexes. * * @throws Exception\BadParameterException if k does not indicate at least one category @@ -66,7 +66,7 @@ public function __construct(int $k, array $probabilities) * * pmf = p(x = i) = pᵢ * - * @param mixed $x category name/number + * @param string|number $x category name/number * * @return float * @@ -108,7 +108,7 @@ public function mode() * * @param string $name * - * @return int|array + * @return int|array * * @throws Exception\BadDataException if $name is not a valid parameter */ diff --git a/src/Probability/Distribution/Discrete/Geometric.php b/src/Probability/Distribution/Discrete/Geometric.php index 7c8a4654e..ff324b58f 100644 --- a/src/Probability/Distribution/Discrete/Geometric.php +++ b/src/Probability/Distribution/Discrete/Geometric.php @@ -14,7 +14,7 @@ class Geometric extends Discrete /** * Distribution parameter bounds limits * p ∈ (0,1] - * @var array + * @var array{"p": string} */ public const PARAMETER_LIMITS = [ 'p' => '(0,1]', @@ -23,7 +23,7 @@ class Geometric extends Discrete /** * Distribution parameter bounds limits * k ∈ [1,∞) - * @var array + * @var array{"k": string} */ public const SUPPORT_LIMITS = [ 'k' => '[1,∞)', diff --git a/src/Probability/Distribution/Discrete/Hypergeometric.php b/src/Probability/Distribution/Discrete/Hypergeometric.php index 18b68c2da..eac964047 100644 --- a/src/Probability/Distribution/Discrete/Hypergeometric.php +++ b/src/Probability/Distribution/Discrete/Hypergeometric.php @@ -19,7 +19,7 @@ class Hypergeometric extends Discrete * K ∈ [0,N] * n ∈ [0,N] * k ∈ [\max(0, n + K - N),min(n, K)] - * @var array + * @var array{"N": string, "K": string, "n": string} */ public const PARAMETER_LIMITS = [ 'N' => '[0,∞)', @@ -27,7 +27,7 @@ class Hypergeometric extends Discrete 'n' => '[0,∞]', // Dynamically checked in constructor ]; - /** @var array */ + /** @var array */ protected $support_limit; /** @var int */ diff --git a/src/Probability/Distribution/Discrete/NegativeBinomial.php b/src/Probability/Distribution/Discrete/NegativeBinomial.php index 2add8ee9f..a32587df9 100644 --- a/src/Probability/Distribution/Discrete/NegativeBinomial.php +++ b/src/Probability/Distribution/Discrete/NegativeBinomial.php @@ -16,7 +16,7 @@ class NegativeBinomial extends Discrete * Distribution parameter bounds limits * r ∈ [0,∞) * p ∈ [0,1] - * @var array + * @var array{"r": string, "p": string} */ public const PARAMETER_LIMITS = [ 'r' => '[0,∞)', @@ -26,7 +26,7 @@ class NegativeBinomial extends Discrete /** * Distribution support bounds limits * x ∈ [0,∞) - * @var array + * @var array{"x": string} */ public const SUPPORT_LIMITS = [ 'x' => '[0,∞)', diff --git a/src/Probability/Distribution/Discrete/Poisson.php b/src/Probability/Distribution/Discrete/Poisson.php index f10cab719..d1dfbebe6 100644 --- a/src/Probability/Distribution/Discrete/Poisson.php +++ b/src/Probability/Distribution/Discrete/Poisson.php @@ -18,7 +18,7 @@ class Poisson extends Discrete /** * Distribution parameter bounds limits * λ ∈ [0,1] - * @var array + * @var array{"λ": string} */ public const PARAMETER_LIMITS = [ 'λ' => '(0,∞)', @@ -27,7 +27,7 @@ class Poisson extends Discrete /** * Distribution support bounds limits * k ∈ [0,∞) - * @var array + * @var array{"k": string} */ public const SUPPORT_LIMITS = [ 'k' => '[0,∞)', @@ -123,13 +123,13 @@ public function median(): float * * mode = ⌈λ - 1⌉, ⌊λ⌋ * - * @return array + * @return array{int, int} */ public function mode(): array { return [ - \ceil($this->λ - 1), - \floor($this->λ), + (int)\ceil($this->λ - 1), + (int)\floor($this->λ), ]; } diff --git a/src/Probability/Distribution/Discrete/ShiftedGeometric.php b/src/Probability/Distribution/Discrete/ShiftedGeometric.php index 8c0b5e853..5a53fd77e 100644 --- a/src/Probability/Distribution/Discrete/ShiftedGeometric.php +++ b/src/Probability/Distribution/Discrete/ShiftedGeometric.php @@ -17,7 +17,7 @@ class ShiftedGeometric extends Discrete /** * Distribution parameter bounds limits * p ∈ (0,1] - * @var array + * @var array{"p": string} */ public const PARAMETER_LIMITS = [ 'p' => '(0,1]', @@ -26,7 +26,7 @@ class ShiftedGeometric extends Discrete /** * Distribution support bounds limits * k ∈ [1,∞) - * @var array + * @var array{"k": string} */ public const SUPPORT_LIMITS = [ 'k' => '[1,∞)', diff --git a/src/Probability/Distribution/Discrete/Uniform.php b/src/Probability/Distribution/Discrete/Uniform.php index 73e0236d6..f1eabf71d 100644 --- a/src/Probability/Distribution/Discrete/Uniform.php +++ b/src/Probability/Distribution/Discrete/Uniform.php @@ -14,7 +14,7 @@ class Uniform extends Discrete * Distribution parameter bounds limits * a ∈ (-∞,∞) * b ∈ (-∞,∞) b > a - * @var array + * @var array{"a": string, "b": string} */ public const PARAMETER_LIMITS = [ 'a' => '(-∞,∞)', @@ -24,7 +24,7 @@ class Uniform extends Discrete /** * Distribution support bounds limits * k ∈ (-∞,∞) - * @var array + * @var array{"k": string} */ public const SUPPORT_LIMITS = [ 'k' => '(-∞,∞)', diff --git a/src/Probability/Distribution/Multivariate/Dirichlet.php b/src/Probability/Distribution/Multivariate/Dirichlet.php index f128b0dbf..098153d25 100644 --- a/src/Probability/Distribution/Multivariate/Dirichlet.php +++ b/src/Probability/Distribution/Multivariate/Dirichlet.php @@ -16,7 +16,7 @@ class Dirichlet /** * Distribution parameter bounds limits * α ∈ (0,∞) - * @var array + * @var array{"α": string} */ public const PARAMETER_LIMITS = [ 'α' => '(0,∞)', @@ -25,7 +25,7 @@ class Dirichlet /** * Distribution parameter bounds limits * x ∈ (0,1) - * @var array + * @var array{x: string} */ public const SUPPORT_LIMITS = [ 'x' => '(0,1)', diff --git a/src/Probability/Distribution/Multivariate/Hypergeometric.php b/src/Probability/Distribution/Multivariate/Hypergeometric.php index 628707e80..9b79d3f17 100644 --- a/src/Probability/Distribution/Multivariate/Hypergeometric.php +++ b/src/Probability/Distribution/Multivariate/Hypergeometric.php @@ -16,7 +16,7 @@ class Hypergeometric /** * Distribution parameter bounds limits * Kᵢ ∈ [1,∞) - * @var array + * @var array{K: string} */ public const PARAMETER_LIMITS = [ 'K' => '[1,∞)', @@ -25,17 +25,17 @@ class Hypergeometric /** * Distribution parameter bounds limits * kᵢ ∈ [0,Kᵢ] - * @var array + * @var array> */ protected $supportLimits = []; - /** @var array */ + /** @var array */ protected $quantities; /** * Multivariate Hypergeometric constructor * - * @param array $quantities + * @param array $quantities * * @throws Exception\BadDataException if the quantities are not positive integers. */ @@ -57,7 +57,7 @@ public function __construct(array $quantities) /** * Probability mass function * - * @param array $picks + * @param array $picks * * @return float * @@ -81,6 +81,7 @@ public function pmf(array $picks): float $total = \array_sum($this->quantities); $product = \array_product(\array_map( + // @phpstan-ignore-next-line (Parameter #1 $callback of function array_map expects (callable(float|int, float|int): mixed)|null, Closure(int, int): float given.) function (int $quantity, int $pick) { return Combinatorics::combinations($quantity, $pick); }, @@ -88,6 +89,6 @@ function (int $quantity, int $pick) { $picks )); - return $product / Combinatorics::combinations($total, $n); + return $product / Combinatorics::combinations((int)$total, (int)$n); } } diff --git a/src/Probability/Distribution/Multivariate/Multinomial.php b/src/Probability/Distribution/Multivariate/Multinomial.php index 020bd4a09..9c0ab6696 100644 --- a/src/Probability/Distribution/Multivariate/Multinomial.php +++ b/src/Probability/Distribution/Multivariate/Multinomial.php @@ -12,13 +12,13 @@ */ class Multinomial { - /** @var array */ + /** @var array */ protected $probabilities; /** * Multinomial constructor * - * @param array $probabilities + * @param array $probabilities * * @throws Exception\BadDataException if the probabilities do not add up to 1 */ @@ -41,7 +41,7 @@ public function __construct(array $probabilities) * * n = number of trials (sum of the frequencies) = x₁ + x₂ + ⋯ xk * - * @param array $frequencies + * @param array $frequencies * * @return float * diff --git a/src/Probability/Distribution/Multivariate/Normal.php b/src/Probability/Distribution/Multivariate/Normal.php index 7d33d4059..91ce93516 100644 --- a/src/Probability/Distribution/Multivariate/Normal.php +++ b/src/Probability/Distribution/Multivariate/Normal.php @@ -14,7 +14,7 @@ */ class Normal { - /** @var array location */ + /** @var array location */ protected $μ; /** @var NumericMatrix covariance matrix */ @@ -23,7 +23,7 @@ class Normal /** * Constructor * - * @param array $μ ∈ Rᵏ location + * @param array $μ ∈ Rᵏ location * @param NumericMatrix $∑ ∈ Rᵏˣᵏ covariance matrix * * @throws Exception\BadDataException if the covariance matrix does not have the same number of rows and columns as number of elements in μ @@ -56,7 +56,7 @@ public function __construct(array $μ, NumericMatrix $∑) * μ is a real k-dimensinoal column vector of means * │∑│ ≡ det(∑) * - * @param array $X ∈ Rᵏ k-dimensional random vector + * @param array $X ∈ Rᵏ k-dimensional random vector * * @return float density * @@ -78,6 +78,7 @@ public function pdf(array $X): float $Δ = Map\Multi::subtract($X, $μ); $⟮x − μ⟯ = new Vector($Δ); + /** @var NumericMatrix $⟮x − μ⟯ᵀ */ $⟮x − μ⟯ᵀ = MatrixFactory::createFromRowVector($Δ); $∑⁻¹ = $∑->inverse(); diff --git a/src/Probability/Distribution/Table/ChiSquared.php b/src/Probability/Distribution/Table/ChiSquared.php index dcc617091..9a1927a69 100644 --- a/src/Probability/Distribution/Table/ChiSquared.php +++ b/src/Probability/Distribution/Table/ChiSquared.php @@ -30,7 +30,7 @@ class ChiSquared * df => [p => χ², p => χ², ...], * ... * ] - * @var array + * @var array, array> */ public const CHI_SQUARED_SCORES = [ 1 => ['0.995' => 0.0000393, '0.975' => 0.000982, '0.200' => 1.642, '0.100' => 2.706, '0.050' => 3.841, '0.025' => 5.024, '0.020' => 5.412, '0.010' => 6.635, '0.005' => 7.879, '0.002' => 9.550, '0.001' => 10.828], @@ -312,6 +312,7 @@ class ChiSquared */ public static function getChiSquareValue(int $df, float $p): float { + // @phpstan-ignore-next-line (Offset numeric-string on array in isset() does not exist.) if (isset(self::CHI_SQUARED_SCORES[$df][\sprintf('%1.3f', $p)])) { return self::CHI_SQUARED_SCORES[$df][\sprintf('%1.3f', $p)]; } diff --git a/src/Probability/Distribution/Table/StandardNormal.php b/src/Probability/Distribution/Table/StandardNormal.php index 83d40319a..5ef642291 100644 --- a/src/Probability/Distribution/Table/StandardNormal.php +++ b/src/Probability/Distribution/Table/StandardNormal.php @@ -33,75 +33,75 @@ class StandardNormal * Contains positive and negative Z scores. * Negative z-score - value is to the left of the mean. * Positive z-score - value is to the right of the mean. - * @var array + * @var array, float>> */ public const Z_SCORES = [ - '-3.4' => [ 9 => 0.0002, 8 => 0.0003, 7 => 0.0003, 6 => 0.0003, 5 => 0.0003, 4 => 0.0003, 3 => 0.0003, 2 => 0.0003, 1 => 0.0003, 0 => 0.0003 ], - '-3.3' => [ 9 => 0.0003, 8 => 0.0004, 7 => 0.0004, 6 => 0.0004, 5 => 0.0004, 4 => 0.0004, 3 => 0.0004, 2 => 0.0005, 1 => 0.0005, 0 => 0.0005 ], - '-3.2' => [ 9 => 0.0005, 8 => 0.0005, 7 => 0.0005, 6 => 0.0006, 5 => 0.0006, 4 => 0.0006, 3 => 0.0006, 2 => 0.0006, 1 => 0.0007, 0 => 0.0007 ], - '-3.1' => [ 9 => 0.0007, 8 => 0.0007, 7 => 0.0008, 6 => 0.0008, 5 => 0.0008, 4 => 0.0008, 3 => 0.0009, 2 => 0.0009, 1 => 0.0009, 0 => 0.0010 ], - '-3.0' => [ 9 => 0.0010, 8 => 0.0010, 7 => 0.0011, 6 => 0.0011, 5 => 0.0011, 4 => 0.0012, 3 => 0.0012, 2 => 0.0013, 1 => 0.0013, 0 => 0.0013 ], - '-2.9' => [ 9 => 0.0014, 8 => 0.0014, 7 => 0.0015, 6 => 0.0015, 5 => 0.0016, 4 => 0.0016, 3 => 0.0017, 2 => 0.0018, 1 => 0.0018, 0 => 0.0019 ], - '-2.8' => [ 9 => 0.0019, 8 => 0.0020, 7 => 0.0021, 6 => 0.0021, 5 => 0.0022, 4 => 0.0023, 3 => 0.0023, 2 => 0.0024, 1 => 0.0025, 0 => 0.0026 ], - '-2.7' => [ 9 => 0.0026, 8 => 0.0027, 7 => 0.0028, 6 => 0.0029, 5 => 0.0030, 4 => 0.0031, 3 => 0.0032, 2 => 0.0033, 1 => 0.0034, 0 => 0.0035 ], - '-2.6' => [ 9 => 0.0036, 8 => 0.0037, 7 => 0.0038, 6 => 0.0039, 5 => 0.0040, 4 => 0.0041, 3 => 0.0043, 2 => 0.0044, 1 => 0.0045, 0 => 0.0047 ], - '-2.5' => [ 9 => 0.0048, 8 => 0.0049, 7 => 0.0051, 6 => 0.0052, 5 => 0.0054, 4 => 0.0055, 3 => 0.0057, 2 => 0.0059, 1 => 0.0060, 0 => 0.0062 ], - '-2.4' => [ 9 => 0.0064, 8 => 0.0066, 7 => 0.0068, 6 => 0.0069, 5 => 0.0071, 4 => 0.0073, 3 => 0.0075, 2 => 0.0078, 1 => 0.0080, 0 => 0.0082 ], - '-2.3' => [ 9 => 0.0084, 8 => 0.0087, 7 => 0.0089, 6 => 0.0091, 5 => 0.0094, 4 => 0.0096, 3 => 0.0099, 2 => 0.0102, 1 => 0.0104, 0 => 0.0107 ], - '-2.2' => [ 9 => 0.0110, 8 => 0.0113, 7 => 0.0116, 6 => 0.0119, 5 => 0.0122, 4 => 0.0125, 3 => 0.0129, 2 => 0.0132, 1 => 0.0136, 0 => 0.0139 ], - '-2.1' => [ 9 => 0.0143, 8 => 0.0146, 7 => 0.0150, 6 => 0.0154, 5 => 0.0158, 4 => 0.0162, 3 => 0.0166, 2 => 0.0170, 1 => 0.0174, 0 => 0.0179 ], - '-2.0' => [ 9 => 0.0183, 8 => 0.0188, 7 => 0.0192, 6 => 0.0197, 5 => 0.0202, 4 => 0.0207, 3 => 0.0212, 2 => 0.0217, 1 => 0.0222, 0 => 0.0228 ], - '-1.9' => [ 9 => 0.0233, 8 => 0.0239, 7 => 0.0244, 6 => 0.0250, 5 => 0.0256, 4 => 0.0262, 3 => 0.0268, 2 => 0.0274, 1 => 0.0281, 0 => 0.0287 ], - '-1.8' => [ 9 => 0.0294, 8 => 0.0301, 7 => 0.0307, 6 => 0.0314, 5 => 0.0322, 4 => 0.0329, 3 => 0.0336, 2 => 0.0344, 1 => 0.0351, 0 => 0.0359 ], - '-1.7' => [ 9 => 0.0367, 8 => 0.0375, 7 => 0.0384, 6 => 0.0392, 5 => 0.0401, 4 => 0.0409, 3 => 0.0418, 2 => 0.0427, 1 => 0.0436, 0 => 0.0446 ], - '-1.6' => [ 9 => 0.0455, 8 => 0.0465, 7 => 0.0475, 6 => 0.0485, 5 => 0.0495, 4 => 0.0505, 3 => 0.0516, 2 => 0.0526, 1 => 0.0537, 0 => 0.0548 ], - '-1.5' => [ 9 => 0.0559, 8 => 0.0571, 7 => 0.0582, 6 => 0.0594, 5 => 0.0606, 4 => 0.0618, 3 => 0.0630, 2 => 0.0643, 1 => 0.0655, 0 => 0.0668 ], - '-1.4' => [ 9 => 0.0681, 8 => 0.0694, 7 => 0.0708, 6 => 0.0721, 5 => 0.0735, 4 => 0.0749, 3 => 0.0764, 2 => 0.0778, 1 => 0.0793, 0 => 0.0808 ], - '-1.3' => [ 9 => 0.0823, 8 => 0.0838, 7 => 0.0853, 6 => 0.0869, 5 => 0.0885, 4 => 0.0901, 3 => 0.0918, 2 => 0.0934, 1 => 0.0951, 0 => 0.0968 ], - '-1.2' => [ 9 => 0.0985, 8 => 0.1003, 7 => 0.1020, 6 => 0.1038, 5 => 0.1056, 4 => 0.1075, 3 => 0.1093, 2 => 0.1112, 1 => 0.1131, 0 => 0.1151 ], - '-1.1' => [ 9 => 0.1170, 8 => 0.1190, 7 => 0.1210, 6 => 0.1230, 5 => 0.1251, 4 => 0.1271, 3 => 0.1292, 2 => 0.1314, 1 => 0.1335, 0 => 0.1357 ], - '-1.0' => [ 9 => 0.1379, 8 => 0.1401, 7 => 0.1423, 6 => 0.1446, 5 => 0.1469, 4 => 0.1492, 3 => 0.1515, 2 => 0.1539, 1 => 0.1562, 0 => 0.1587 ], - '-0.9' => [ 9 => 0.1611, 8 => 0.1635, 7 => 0.1660, 6 => 0.1685, 5 => 0.1711, 4 => 0.1736, 3 => 0.1762, 2 => 0.1788, 1 => 0.1814, 0 => 0.1841 ], - '-0.8' => [ 9 => 0.1867, 8 => 0.1894, 7 => 0.1922, 6 => 0.1949, 5 => 0.1977, 4 => 0.2005, 3 => 0.2033, 2 => 0.2061, 1 => 0.2090, 0 => 0.2119 ], - '-0.7' => [ 9 => 0.2148, 8 => 0.2177, 7 => 0.2206, 6 => 0.2236, 5 => 0.2266, 4 => 0.2296, 3 => 0.2327, 2 => 0.2358, 1 => 0.2389, 0 => 0.2420 ], - '-0.6' => [ 9 => 0.2451, 8 => 0.2483, 7 => 0.2514, 6 => 0.2546, 5 => 0.2578, 4 => 0.2611, 3 => 0.2643, 2 => 0.2676, 1 => 0.2709, 0 => 0.2743 ], - '-0.5' => [ 9 => 0.2776, 8 => 0.2810, 7 => 0.2843, 6 => 0.2877, 5 => 0.2912, 4 => 0.2946, 3 => 0.2981, 2 => 0.3015, 1 => 0.3050, 0 => 0.3085 ], - '-0.4' => [ 9 => 0.3121, 8 => 0.3156, 7 => 0.3192, 6 => 0.3228, 5 => 0.3264, 4 => 0.3300, 3 => 0.3336, 2 => 0.3372, 1 => 0.3409, 0 => 0.3446 ], - '-0.3' => [ 9 => 0.3483, 8 => 0.3520, 7 => 0.3557, 6 => 0.3594, 5 => 0.3632, 4 => 0.3669, 3 => 0.3707, 2 => 0.3745, 1 => 0.3783, 0 => 0.3821 ], - '-0.2' => [ 9 => 0.3829, 8 => 0.3897, 7 => 0.3936, 6 => 0.3974, 5 => 0.4013, 4 => 0.4052, 3 => 0.4090, 2 => 0.4129, 1 => 0.4168, 0 => 0.4207 ], - '-0.1' => [ 9 => 0.4247, 8 => 0.4286, 7 => 0.4325, 6 => 0.4364, 5 => 0.4404, 4 => 0.4443, 3 => 0.4483, 2 => 0.4522, 1 => 0.4562, 0 => 0.4602 ], - '-0.0' => [ 9 => 0.4641, 8 => 0.4681, 7 => 0.4721, 6 => 0.4761, 5 => 0.4801, 4 => 0.4840, 3 => 0.4880, 2 => 0.4920, 1 => 0.4960, 0 => 0.5000 ], - '0.0' => [ 0 => 0.50000, 1 => 0.50399, 2 => 0.50798, 3 => 0.51197, 4 => 0.51595, 5 => 0.51994, 6 => 0.52392, 7 => 0.52790, 8 => 0.53188, 9 => 0.53586 ], - '0.1' => [ 0 => 0.53980, 1 => 0.54380, 2 => 0.54776, 3 => 0.55172, 4 => 0.55567, 5 => 0.55966, 6 => 0.56360, 7 => 0.56749, 8 => 0.57142, 9 => 0.57535 ], - '0.2' => [ 0 => 0.57930, 1 => 0.58317, 2 => 0.58706, 3 => 0.59095, 4 => 0.59483, 5 => 0.59871, 6 => 0.60257, 7 => 0.60642, 8 => 0.61026, 9 => 0.61409 ], - '0.3' => [ 0 => 0.61791, 1 => 0.62172, 2 => 0.62552, 3 => 0.62930, 4 => 0.63307, 5 => 0.63683, 6 => 0.64058, 7 => 0.64431, 8 => 0.64803, 9 => 0.65173 ], - '0.4' => [ 0 => 0.65542, 1 => 0.65910, 2 => 0.66276, 3 => 0.66640, 4 => 0.67003, 5 => 0.67364, 6 => 0.67724, 7 => 0.68082, 8 => 0.68439, 9 => 0.68793 ], - '0.5' => [ 0 => 0.69146, 1 => 0.69497, 2 => 0.69847, 3 => 0.70194, 4 => 0.70540, 5 => 0.70884, 6 => 0.71226, 7 => 0.71566, 8 => 0.71904, 9 => 0.72240 ], - '0.6' => [ 0 => 0.72575, 1 => 0.72907, 2 => 0.73237, 3 => 0.73565, 4 => 0.73891, 5 => 0.74215, 6 => 0.74537, 7 => 0.74857, 8 => 0.75175, 9 => 0.75490 ], - '0.7' => [ 0 => 0.75804, 1 => 0.76115, 2 => 0.76424, 3 => 0.76730, 4 => 0.77035, 5 => 0.77337, 6 => 0.77637, 7 => 0.77935, 8 => 0.78230, 9 => 0.78524 ], - '0.8' => [ 0 => 0.78814, 1 => 0.79103, 2 => 0.79389, 3 => 0.79673, 4 => 0.79955, 5 => 0.80234, 6 => 0.80511, 7 => 0.80785, 8 => 0.81057, 9 => 0.81327 ], - '0.9' => [ 0 => 0.81594, 1 => 0.81859, 2 => 0.82121, 3 => 0.82381, 4 => 0.82639, 5 => 0.82894, 6 => 0.83147, 7 => 0.83398, 8 => 0.83646, 9 => 0.83891 ], - '1.0' => [ 0 => 0.84134, 1 => 0.84375, 2 => 0.84614, 3 => 0.84849, 4 => 0.85083, 5 => 0.85314, 6 => 0.85543, 7 => 0.85769, 8 => 0.85993, 9 => 0.86214 ], - '1.1' => [ 0 => 0.86433, 1 => 0.86650, 2 => 0.86864, 3 => 0.87076, 4 => 0.87286, 5 => 0.87493, 6 => 0.87698, 7 => 0.87900, 8 => 0.88100, 9 => 0.88298 ], - '1.2' => [ 0 => 0.88493, 1 => 0.88686, 2 => 0.88877, 3 => 0.89065, 4 => 0.89251, 5 => 0.89435, 6 => 0.89617, 7 => 0.89796, 8 => 0.89973, 9 => 0.90147 ], - '1.3' => [ 0 => 0.90320, 1 => 0.90490, 2 => 0.90658, 3 => 0.90824, 4 => 0.90988, 5 => 0.91149, 6 => 0.91308, 7 => 0.91466, 8 => 0.91621, 9 => 0.91774 ], - '1.4' => [ 0 => 0.91924, 1 => 0.92073, 2 => 0.92220, 3 => 0.92364, 4 => 0.92507, 5 => 0.92647, 6 => 0.92785, 7 => 0.92922, 8 => 0.93056, 9 => 0.93189 ], - '1.5' => [ 0 => 0.93319, 1 => 0.93448, 2 => 0.93574, 3 => 0.93699, 4 => 0.93822, 5 => 0.93943, 6 => 0.94062, 7 => 0.94179, 8 => 0.94295, 9 => 0.94408 ], - '1.6' => [ 0 => 0.94520, 1 => 0.94630, 2 => 0.94738, 3 => 0.94845, 4 => 0.94950, 5 => 0.95053, 6 => 0.95154, 7 => 0.95254, 8 => 0.95352, 9 => 0.95449 ], - '1.7' => [ 0 => 0.95543, 1 => 0.95637, 2 => 0.95728, 3 => 0.95818, 4 => 0.95907, 5 => 0.95994, 6 => 0.96080, 7 => 0.96164, 8 => 0.96246, 9 => 0.96327 ], - '1.8' => [ 0 => 0.96407, 1 => 0.96485, 2 => 0.96562, 3 => 0.96638, 4 => 0.96712, 5 => 0.96784, 6 => 0.96856, 7 => 0.96926, 8 => 0.96995, 9 => 0.97062 ], - '1.9' => [ 0 => 0.97128, 1 => 0.97193, 2 => 0.97257, 3 => 0.97320, 4 => 0.97381, 5 => 0.97441, 6 => 0.97500, 7 => 0.97558, 8 => 0.97615, 9 => 0.97670 ], - '2.0' => [ 0 => 0.97725, 1 => 0.97778, 2 => 0.97831, 3 => 0.97882, 4 => 0.97932, 5 => 0.97982, 6 => 0.98030, 7 => 0.98077, 8 => 0.98124, 9 => 0.98169 ], - '2.1' => [ 0 => 0.98214, 1 => 0.98257, 2 => 0.98300, 3 => 0.98341, 4 => 0.98382, 5 => 0.98422, 6 => 0.98461, 7 => 0.98500, 8 => 0.98537, 9 => 0.98574 ], - '2.2' => [ 0 => 0.98610, 1 => 0.98645, 2 => 0.98679, 3 => 0.98713, 4 => 0.98745, 5 => 0.98778, 6 => 0.98809, 7 => 0.98840, 8 => 0.98870, 9 => 0.98899 ], - '2.3' => [ 0 => 0.98928, 1 => 0.98956, 2 => 0.98983, 3 => 0.99010, 4 => 0.99036, 5 => 0.99061, 6 => 0.99086, 7 => 0.99111, 8 => 0.99134, 9 => 0.99158 ], - '2.4' => [ 0 => 0.99180, 1 => 0.99202, 2 => 0.99224, 3 => 0.99245, 4 => 0.99266, 5 => 0.99286, 6 => 0.99305, 7 => 0.99324, 8 => 0.99343, 9 => 0.99361 ], - '2.5' => [ 0 => 0.99379, 1 => 0.99396, 2 => 0.99413, 3 => 0.99430, 4 => 0.99446, 5 => 0.99461, 6 => 0.99477, 7 => 0.99492, 8 => 0.99506, 9 => 0.99520 ], - '2.6' => [ 0 => 0.99534, 1 => 0.99547, 2 => 0.99560, 3 => 0.99573, 4 => 0.99585, 5 => 0.99598, 6 => 0.99609, 7 => 0.99621, 8 => 0.99632, 9 => 0.99643 ], - '2.7' => [ 0 => 0.99653, 1 => 0.99664, 2 => 0.99674, 3 => 0.99683, 4 => 0.99693, 5 => 0.99702, 6 => 0.99711, 7 => 0.99720, 8 => 0.99728, 9 => 0.99736 ], - '2.8' => [ 0 => 0.99744, 1 => 0.99752, 2 => 0.99760, 3 => 0.99767, 4 => 0.99774, 5 => 0.99781, 6 => 0.99788, 7 => 0.99795, 8 => 0.99801, 9 => 0.99807 ], - '2.9' => [ 0 => 0.99813, 1 => 0.99819, 2 => 0.99825, 3 => 0.99831, 4 => 0.99836, 5 => 0.99841, 6 => 0.99846, 7 => 0.99851, 8 => 0.99856, 9 => 0.99861 ], - '3.0' => [ 0 => 0.99865, 1 => 0.99869, 2 => 0.99874, 3 => 0.99878, 4 => 0.99882, 5 => 0.99886, 6 => 0.99889, 7 => 0.99893, 8 => 0.99896, 9 => 0.99900 ], + '-3.4' => [ 9 => 0.0002, 8 => 0.0003, 7 => 0.0003, 6 => 0.0003, 5 => 0.0003, 4 => 0.0003, 3 => 0.0003, 2 => 0.0003, 1 => 0.0003, 0 => 0.0003 ], + '-3.3' => [ 9 => 0.0003, 8 => 0.0004, 7 => 0.0004, 6 => 0.0004, 5 => 0.0004, 4 => 0.0004, 3 => 0.0004, 2 => 0.0005, 1 => 0.0005, 0 => 0.0005 ], + '-3.2' => [ 9 => 0.0005, 8 => 0.0005, 7 => 0.0005, 6 => 0.0006, 5 => 0.0006, 4 => 0.0006, 3 => 0.0006, 2 => 0.0006, 1 => 0.0007, 0 => 0.0007 ], + '-3.1' => [ 9 => 0.0007, 8 => 0.0007, 7 => 0.0008, 6 => 0.0008, 5 => 0.0008, 4 => 0.0008, 3 => 0.0009, 2 => 0.0009, 1 => 0.0009, 0 => 0.0010 ], + '-3.0' => [ 9 => 0.0010, 8 => 0.0010, 7 => 0.0011, 6 => 0.0011, 5 => 0.0011, 4 => 0.0012, 3 => 0.0012, 2 => 0.0013, 1 => 0.0013, 0 => 0.0013 ], + '-2.9' => [ 9 => 0.0014, 8 => 0.0014, 7 => 0.0015, 6 => 0.0015, 5 => 0.0016, 4 => 0.0016, 3 => 0.0017, 2 => 0.0018, 1 => 0.0018, 0 => 0.0019 ], + '-2.8' => [ 9 => 0.0019, 8 => 0.0020, 7 => 0.0021, 6 => 0.0021, 5 => 0.0022, 4 => 0.0023, 3 => 0.0023, 2 => 0.0024, 1 => 0.0025, 0 => 0.0026 ], + '-2.7' => [ 9 => 0.0026, 8 => 0.0027, 7 => 0.0028, 6 => 0.0029, 5 => 0.0030, 4 => 0.0031, 3 => 0.0032, 2 => 0.0033, 1 => 0.0034, 0 => 0.0035 ], + '-2.6' => [ 9 => 0.0036, 8 => 0.0037, 7 => 0.0038, 6 => 0.0039, 5 => 0.0040, 4 => 0.0041, 3 => 0.0043, 2 => 0.0044, 1 => 0.0045, 0 => 0.0047 ], + '-2.5' => [ 9 => 0.0048, 8 => 0.0049, 7 => 0.0051, 6 => 0.0052, 5 => 0.0054, 4 => 0.0055, 3 => 0.0057, 2 => 0.0059, 1 => 0.0060, 0 => 0.0062 ], + '-2.4' => [ 9 => 0.0064, 8 => 0.0066, 7 => 0.0068, 6 => 0.0069, 5 => 0.0071, 4 => 0.0073, 3 => 0.0075, 2 => 0.0078, 1 => 0.0080, 0 => 0.0082 ], + '-2.3' => [ 9 => 0.0084, 8 => 0.0087, 7 => 0.0089, 6 => 0.0091, 5 => 0.0094, 4 => 0.0096, 3 => 0.0099, 2 => 0.0102, 1 => 0.0104, 0 => 0.0107 ], + '-2.2' => [ 9 => 0.0110, 8 => 0.0113, 7 => 0.0116, 6 => 0.0119, 5 => 0.0122, 4 => 0.0125, 3 => 0.0129, 2 => 0.0132, 1 => 0.0136, 0 => 0.0139 ], + '-2.1' => [ 9 => 0.0143, 8 => 0.0146, 7 => 0.0150, 6 => 0.0154, 5 => 0.0158, 4 => 0.0162, 3 => 0.0166, 2 => 0.0170, 1 => 0.0174, 0 => 0.0179 ], + '-2.0' => [ 9 => 0.0183, 8 => 0.0188, 7 => 0.0192, 6 => 0.0197, 5 => 0.0202, 4 => 0.0207, 3 => 0.0212, 2 => 0.0217, 1 => 0.0222, 0 => 0.0228 ], + '-1.9' => [ 9 => 0.0233, 8 => 0.0239, 7 => 0.0244, 6 => 0.0250, 5 => 0.0256, 4 => 0.0262, 3 => 0.0268, 2 => 0.0274, 1 => 0.0281, 0 => 0.0287 ], + '-1.8' => [ 9 => 0.0294, 8 => 0.0301, 7 => 0.0307, 6 => 0.0314, 5 => 0.0322, 4 => 0.0329, 3 => 0.0336, 2 => 0.0344, 1 => 0.0351, 0 => 0.0359 ], + '-1.7' => [ 9 => 0.0367, 8 => 0.0375, 7 => 0.0384, 6 => 0.0392, 5 => 0.0401, 4 => 0.0409, 3 => 0.0418, 2 => 0.0427, 1 => 0.0436, 0 => 0.0446 ], + '-1.6' => [ 9 => 0.0455, 8 => 0.0465, 7 => 0.0475, 6 => 0.0485, 5 => 0.0495, 4 => 0.0505, 3 => 0.0516, 2 => 0.0526, 1 => 0.0537, 0 => 0.0548 ], + '-1.5' => [ 9 => 0.0559, 8 => 0.0571, 7 => 0.0582, 6 => 0.0594, 5 => 0.0606, 4 => 0.0618, 3 => 0.0630, 2 => 0.0643, 1 => 0.0655, 0 => 0.0668 ], + '-1.4' => [ 9 => 0.0681, 8 => 0.0694, 7 => 0.0708, 6 => 0.0721, 5 => 0.0735, 4 => 0.0749, 3 => 0.0764, 2 => 0.0778, 1 => 0.0793, 0 => 0.0808 ], + '-1.3' => [ 9 => 0.0823, 8 => 0.0838, 7 => 0.0853, 6 => 0.0869, 5 => 0.0885, 4 => 0.0901, 3 => 0.0918, 2 => 0.0934, 1 => 0.0951, 0 => 0.0968 ], + '-1.2' => [ 9 => 0.0985, 8 => 0.1003, 7 => 0.1020, 6 => 0.1038, 5 => 0.1056, 4 => 0.1075, 3 => 0.1093, 2 => 0.1112, 1 => 0.1131, 0 => 0.1151 ], + '-1.1' => [ 9 => 0.1170, 8 => 0.1190, 7 => 0.1210, 6 => 0.1230, 5 => 0.1251, 4 => 0.1271, 3 => 0.1292, 2 => 0.1314, 1 => 0.1335, 0 => 0.1357 ], + '-1.0' => [ 9 => 0.1379, 8 => 0.1401, 7 => 0.1423, 6 => 0.1446, 5 => 0.1469, 4 => 0.1492, 3 => 0.1515, 2 => 0.1539, 1 => 0.1562, 0 => 0.1587 ], + '-0.9' => [ 9 => 0.1611, 8 => 0.1635, 7 => 0.1660, 6 => 0.1685, 5 => 0.1711, 4 => 0.1736, 3 => 0.1762, 2 => 0.1788, 1 => 0.1814, 0 => 0.1841 ], + '-0.8' => [ 9 => 0.1867, 8 => 0.1894, 7 => 0.1922, 6 => 0.1949, 5 => 0.1977, 4 => 0.2005, 3 => 0.2033, 2 => 0.2061, 1 => 0.2090, 0 => 0.2119 ], + '-0.7' => [ 9 => 0.2148, 8 => 0.2177, 7 => 0.2206, 6 => 0.2236, 5 => 0.2266, 4 => 0.2296, 3 => 0.2327, 2 => 0.2358, 1 => 0.2389, 0 => 0.2420 ], + '-0.6' => [ 9 => 0.2451, 8 => 0.2483, 7 => 0.2514, 6 => 0.2546, 5 => 0.2578, 4 => 0.2611, 3 => 0.2643, 2 => 0.2676, 1 => 0.2709, 0 => 0.2743 ], + '-0.5' => [ 9 => 0.2776, 8 => 0.2810, 7 => 0.2843, 6 => 0.2877, 5 => 0.2912, 4 => 0.2946, 3 => 0.2981, 2 => 0.3015, 1 => 0.3050, 0 => 0.3085 ], + '-0.4' => [ 9 => 0.3121, 8 => 0.3156, 7 => 0.3192, 6 => 0.3228, 5 => 0.3264, 4 => 0.3300, 3 => 0.3336, 2 => 0.3372, 1 => 0.3409, 0 => 0.3446 ], + '-0.3' => [ 9 => 0.3483, 8 => 0.3520, 7 => 0.3557, 6 => 0.3594, 5 => 0.3632, 4 => 0.3669, 3 => 0.3707, 2 => 0.3745, 1 => 0.3783, 0 => 0.3821 ], + '-0.2' => [ 9 => 0.3829, 8 => 0.3897, 7 => 0.3936, 6 => 0.3974, 5 => 0.4013, 4 => 0.4052, 3 => 0.4090, 2 => 0.4129, 1 => 0.4168, 0 => 0.4207 ], + '-0.1' => [ 9 => 0.4247, 8 => 0.4286, 7 => 0.4325, 6 => 0.4364, 5 => 0.4404, 4 => 0.4443, 3 => 0.4483, 2 => 0.4522, 1 => 0.4562, 0 => 0.4602 ], + '-0.0' => [ 9 => 0.4641, 8 => 0.4681, 7 => 0.4721, 6 => 0.4761, 5 => 0.4801, 4 => 0.4840, 3 => 0.4880, 2 => 0.4920, 1 => 0.4960, 0 => 0.5000 ], + '0.0' => [ 0 => 0.50000, 1 => 0.50399, 2 => 0.50798, 3 => 0.51197, 4 => 0.51595, 5 => 0.51994, 6 => 0.52392, 7 => 0.52790, 8 => 0.53188, 9 => 0.53586 ], + '0.1' => [ 0 => 0.53980, 1 => 0.54380, 2 => 0.54776, 3 => 0.55172, 4 => 0.55567, 5 => 0.55966, 6 => 0.56360, 7 => 0.56749, 8 => 0.57142, 9 => 0.57535 ], + '0.2' => [ 0 => 0.57930, 1 => 0.58317, 2 => 0.58706, 3 => 0.59095, 4 => 0.59483, 5 => 0.59871, 6 => 0.60257, 7 => 0.60642, 8 => 0.61026, 9 => 0.61409 ], + '0.3' => [ 0 => 0.61791, 1 => 0.62172, 2 => 0.62552, 3 => 0.62930, 4 => 0.63307, 5 => 0.63683, 6 => 0.64058, 7 => 0.64431, 8 => 0.64803, 9 => 0.65173 ], + '0.4' => [ 0 => 0.65542, 1 => 0.65910, 2 => 0.66276, 3 => 0.66640, 4 => 0.67003, 5 => 0.67364, 6 => 0.67724, 7 => 0.68082, 8 => 0.68439, 9 => 0.68793 ], + '0.5' => [ 0 => 0.69146, 1 => 0.69497, 2 => 0.69847, 3 => 0.70194, 4 => 0.70540, 5 => 0.70884, 6 => 0.71226, 7 => 0.71566, 8 => 0.71904, 9 => 0.72240 ], + '0.6' => [ 0 => 0.72575, 1 => 0.72907, 2 => 0.73237, 3 => 0.73565, 4 => 0.73891, 5 => 0.74215, 6 => 0.74537, 7 => 0.74857, 8 => 0.75175, 9 => 0.75490 ], + '0.7' => [ 0 => 0.75804, 1 => 0.76115, 2 => 0.76424, 3 => 0.76730, 4 => 0.77035, 5 => 0.77337, 6 => 0.77637, 7 => 0.77935, 8 => 0.78230, 9 => 0.78524 ], + '0.8' => [ 0 => 0.78814, 1 => 0.79103, 2 => 0.79389, 3 => 0.79673, 4 => 0.79955, 5 => 0.80234, 6 => 0.80511, 7 => 0.80785, 8 => 0.81057, 9 => 0.81327 ], + '0.9' => [ 0 => 0.81594, 1 => 0.81859, 2 => 0.82121, 3 => 0.82381, 4 => 0.82639, 5 => 0.82894, 6 => 0.83147, 7 => 0.83398, 8 => 0.83646, 9 => 0.83891 ], + '1.0' => [ 0 => 0.84134, 1 => 0.84375, 2 => 0.84614, 3 => 0.84849, 4 => 0.85083, 5 => 0.85314, 6 => 0.85543, 7 => 0.85769, 8 => 0.85993, 9 => 0.86214 ], + '1.1' => [ 0 => 0.86433, 1 => 0.86650, 2 => 0.86864, 3 => 0.87076, 4 => 0.87286, 5 => 0.87493, 6 => 0.87698, 7 => 0.87900, 8 => 0.88100, 9 => 0.88298 ], + '1.2' => [ 0 => 0.88493, 1 => 0.88686, 2 => 0.88877, 3 => 0.89065, 4 => 0.89251, 5 => 0.89435, 6 => 0.89617, 7 => 0.89796, 8 => 0.89973, 9 => 0.90147 ], + '1.3' => [ 0 => 0.90320, 1 => 0.90490, 2 => 0.90658, 3 => 0.90824, 4 => 0.90988, 5 => 0.91149, 6 => 0.91308, 7 => 0.91466, 8 => 0.91621, 9 => 0.91774 ], + '1.4' => [ 0 => 0.91924, 1 => 0.92073, 2 => 0.92220, 3 => 0.92364, 4 => 0.92507, 5 => 0.92647, 6 => 0.92785, 7 => 0.92922, 8 => 0.93056, 9 => 0.93189 ], + '1.5' => [ 0 => 0.93319, 1 => 0.93448, 2 => 0.93574, 3 => 0.93699, 4 => 0.93822, 5 => 0.93943, 6 => 0.94062, 7 => 0.94179, 8 => 0.94295, 9 => 0.94408 ], + '1.6' => [ 0 => 0.94520, 1 => 0.94630, 2 => 0.94738, 3 => 0.94845, 4 => 0.94950, 5 => 0.95053, 6 => 0.95154, 7 => 0.95254, 8 => 0.95352, 9 => 0.95449 ], + '1.7' => [ 0 => 0.95543, 1 => 0.95637, 2 => 0.95728, 3 => 0.95818, 4 => 0.95907, 5 => 0.95994, 6 => 0.96080, 7 => 0.96164, 8 => 0.96246, 9 => 0.96327 ], + '1.8' => [ 0 => 0.96407, 1 => 0.96485, 2 => 0.96562, 3 => 0.96638, 4 => 0.96712, 5 => 0.96784, 6 => 0.96856, 7 => 0.96926, 8 => 0.96995, 9 => 0.97062 ], + '1.9' => [ 0 => 0.97128, 1 => 0.97193, 2 => 0.97257, 3 => 0.97320, 4 => 0.97381, 5 => 0.97441, 6 => 0.97500, 7 => 0.97558, 8 => 0.97615, 9 => 0.97670 ], + '2.0' => [ 0 => 0.97725, 1 => 0.97778, 2 => 0.97831, 3 => 0.97882, 4 => 0.97932, 5 => 0.97982, 6 => 0.98030, 7 => 0.98077, 8 => 0.98124, 9 => 0.98169 ], + '2.1' => [ 0 => 0.98214, 1 => 0.98257, 2 => 0.98300, 3 => 0.98341, 4 => 0.98382, 5 => 0.98422, 6 => 0.98461, 7 => 0.98500, 8 => 0.98537, 9 => 0.98574 ], + '2.2' => [ 0 => 0.98610, 1 => 0.98645, 2 => 0.98679, 3 => 0.98713, 4 => 0.98745, 5 => 0.98778, 6 => 0.98809, 7 => 0.98840, 8 => 0.98870, 9 => 0.98899 ], + '2.3' => [ 0 => 0.98928, 1 => 0.98956, 2 => 0.98983, 3 => 0.99010, 4 => 0.99036, 5 => 0.99061, 6 => 0.99086, 7 => 0.99111, 8 => 0.99134, 9 => 0.99158 ], + '2.4' => [ 0 => 0.99180, 1 => 0.99202, 2 => 0.99224, 3 => 0.99245, 4 => 0.99266, 5 => 0.99286, 6 => 0.99305, 7 => 0.99324, 8 => 0.99343, 9 => 0.99361 ], + '2.5' => [ 0 => 0.99379, 1 => 0.99396, 2 => 0.99413, 3 => 0.99430, 4 => 0.99446, 5 => 0.99461, 6 => 0.99477, 7 => 0.99492, 8 => 0.99506, 9 => 0.99520 ], + '2.6' => [ 0 => 0.99534, 1 => 0.99547, 2 => 0.99560, 3 => 0.99573, 4 => 0.99585, 5 => 0.99598, 6 => 0.99609, 7 => 0.99621, 8 => 0.99632, 9 => 0.99643 ], + '2.7' => [ 0 => 0.99653, 1 => 0.99664, 2 => 0.99674, 3 => 0.99683, 4 => 0.99693, 5 => 0.99702, 6 => 0.99711, 7 => 0.99720, 8 => 0.99728, 9 => 0.99736 ], + '2.8' => [ 0 => 0.99744, 1 => 0.99752, 2 => 0.99760, 3 => 0.99767, 4 => 0.99774, 5 => 0.99781, 6 => 0.99788, 7 => 0.99795, 8 => 0.99801, 9 => 0.99807 ], + '2.9' => [ 0 => 0.99813, 1 => 0.99819, 2 => 0.99825, 3 => 0.99831, 4 => 0.99836, 5 => 0.99841, 6 => 0.99846, 7 => 0.99851, 8 => 0.99856, 9 => 0.99861 ], + '3.0' => [ 0 => 0.99865, 1 => 0.99869, 2 => 0.99874, 3 => 0.99878, 4 => 0.99882, 5 => 0.99886, 6 => 0.99889, 7 => 0.99893, 8 => 0.99896, 9 => 0.99900 ], ]; /** @@ -118,6 +118,10 @@ public static function getZScoreProbability(float $Z): float if (!preg_match('/^ (\-? \d [.] \d) (\d) $/x', \sprintf('%1.2f', $Z), $matches)) { throw new Exception\BadParameterException("Z does not match format X.XX: $Z"); } + /** + * @var string $z + * @var numeric $+0.0x + */ [$z, $+0.0x] = [ $matches[1], $matches[2] ]; return self::Z_SCORES[$z][$+0.0x]; } @@ -126,7 +130,7 @@ public static function getZScoreProbability(float $Z): float * Z scores for confidence intervals * Key: confidence level % * Value: Z score - * @var array + * @var array */ private const Z_SCORES_FOR_CONFIDENCE_INTERVALS = [ 50 => 0.67449, diff --git a/src/Probability/Distribution/Table/TDistribution.php b/src/Probability/Distribution/Table/TDistribution.php index 940cfaa89..394f6a78e 100644 --- a/src/Probability/Distribution/Table/TDistribution.php +++ b/src/Probability/Distribution/Table/TDistribution.php @@ -22,7 +22,7 @@ class TDistribution /** * One-sided t distribution table * Confidence level percentaces - * @var array + * @var array> */ private const ONE_SIDED_CONFIDENCE_LEVEL = [ 1 => [ 0 => 0, 75 => 1.000, 80 => 1.376, 85 => 1.963, 90 => 3.078, 95 => 6.314, '97.5' => 12.71, 99 => 31.82, '99.5' => 63.66, '99.75' => 127.3, '99.9' => 318.3, '99.95' => 636.6 ], @@ -67,7 +67,7 @@ class TDistribution /** * One-sided t distribution table * Alphas - * @var array + * @var array> */ private const ONE_SIDED_ALPHA = [ 1 => [ '0.50' => 0, '0.25' => 1.000, '0.20' => 1.376, '0.15' => 1.963, '0.10' => 3.078, '0.05' => 6.314, '0.025' => 12.71, '0.01' => 31.82, '0.005' => 63.66, '0.0025' => 127.3, '0.001' => 318.3, '0.0005' => 636.6 ], @@ -112,7 +112,7 @@ class TDistribution /** * Two-sided t distribution table * Confidence level percentaces - * @var array + * @var array> */ private const TWO_SIDED_CONFIDENCE_LEVEL = [ 1 => [ 0 => 0, 50 => 1.000, 60 => 1.376, 70 => 1.963, 80 => 3.078, 90 => 6.314, 95 => 12.71, 98 => 31.82, 99 => 63.66, '99.5' => 127.3, '99.8' => 318.3, '99.9' => 636.6 ], @@ -157,7 +157,7 @@ class TDistribution /** * Two-sided t distribution table * Alphas - * @var array + * @var array> */ private const TWO_SIDED_ALPHA = [ 1 => [ '1.00' => 0, '0.50' => 1.000, '0.40' => 1.376, '0.30' => 1.963, '0.20' => 3.078, '0.10' => 6.314, '0.05' => 12.71, '0.02' => 31.82, '0.01' => 63.66, '0.005' => 127.3, '0.002' => 318.3, '0.001' => 636.6 ], diff --git a/src/SampleData/Cereal.php b/src/SampleData/Cereal.php index b231d153e..ab4f506c5 100644 --- a/src/SampleData/Cereal.php +++ b/src/SampleData/Cereal.php @@ -124,10 +124,11 @@ public function getXData(): array * Raw data with each observation labeled * ['B1' => ['X1126.0' => 0.002682755, 'X1134.0' => 0.003370673, 'X1142.0' => 0.004085942, ... ]] * - * @return number[] + * @return array> */ public function getLabeledXData(): array { + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::X_LABELS, $data); @@ -151,10 +152,11 @@ public function getYData(): array * Raw data with each observation labeled * ['B1' => ['Heating value' => 18373, 'C' => 41.61500, 'H' => 6.565000, ... ]] * - * @return number[] + * @return array> */ public function getLabeledYData(): array { + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::Y_LABELS, $data); @@ -178,10 +180,11 @@ public function getYscData(): array * Raw data with each observation labeled * ['B1' => ['Heating value' => -0.1005049, 'C' => 0.6265746, 'H' => -1.1716630, ... ]] * - * @return number[] + * @return array> */ public function getLabeledYscData(): array { + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::YSC_LABELS, $data); @@ -191,7 +194,7 @@ function (array $data) { } /** - * @return array + * @return array */ public function getScaledCenter(): array { @@ -199,7 +202,7 @@ public function getScaledCenter(): array } /** - * @return array + * @return array */ public function getScaledScale(): array { diff --git a/src/SampleData/Iris.php b/src/SampleData/Iris.php index 01b01f0b0..8eb2a7741 100644 --- a/src/SampleData/Iris.php +++ b/src/SampleData/Iris.php @@ -187,10 +187,11 @@ public function getData(): array * Raw data with each observation labeled * [['sepalLength' => 5.11, 'sepalWidth' => 3.5, 'petalLength' => 1.4, 'petalWidth' => 0.2, 'species' => 'setosa'], ... ] * - * @return number[] + * @return array> */ public function getLabeledData(): array { + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::LABELS, $data); diff --git a/src/SampleData/MtCars.php b/src/SampleData/MtCars.php index 05cb423f4..6c267e9aa 100644 --- a/src/SampleData/MtCars.php +++ b/src/SampleData/MtCars.php @@ -67,10 +67,11 @@ public function getData(): array * Raw data with each observation labeled * ['Car Model' => ['mpg' => 21, 'cyl' => 6, 'disp' => 160, ... ]] * - * @return number[] + * @return array> */ public function getLabeledData(): array { + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::LABELS, $data); @@ -82,7 +83,7 @@ function (array $data) { /** * Car model names * - * @return string[] + * @return array */ public function getModels(): array { @@ -95,10 +96,11 @@ public function getModels(): array * * @param string $model * - * @return number[] + * @return array */ public function getModelData(string $model): array { + /** @var array */ return \array_combine(self::LABELS, self::DATA[$model]); } @@ -106,10 +108,11 @@ public function getModelData(string $model): array * Miles per gallon observations for all models * ['Mazda RX4' => 21, 'Honda civic' => 30.4, ... ] * - * @return number[] + * @return array */ public function getMpg(): array { + /** @var array */ return \array_combine($this->getModels(), \array_column(self::DATA, 0)); } diff --git a/src/SampleData/People.php b/src/SampleData/People.php index 6b21b6d5f..12a2ee117 100644 --- a/src/SampleData/People.php +++ b/src/SampleData/People.php @@ -82,10 +82,11 @@ public function getData(): array * Raw data with each observation labeled * ['Lars' => ['height' => 198, 'weight' => 92, 'hairLength' => -1, ... ]] * - * @return int[][] + * @return array> */ public function getLabeledData(): array { + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::LABELS, $data); @@ -111,105 +112,119 @@ public function getNames(): array * @param string $name * * @return int[] + * @return array */ public function getPersonData(string $name): array { + /** @var array */ return \array_combine(self::LABELS, self::DATA[$name]); } /** - * @return int[] + * @return array */ public function getHeight(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 0)); } /** - * @return int[] + * @return array */ public function getWeight(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 1)); } /** - * @return int[] + * @return array */ public function getHairLength(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 2)); } /** - * @return int[] + * @return array */ public function getShowSize(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 3)); } /** - * @return number[] + * @return array */ public function getAge(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 4)); } /** - * @return int[] + * @return array */ public function getIncome(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 5)); } /** - * @return int[] + * @return array */ public function getBeer(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 6)); } /** - * @return int[] + * @return array */ public function getWine(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 7)); } /** - * @return int[] + * @return array */ public function getSex(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 8)); } /** - * @return int[] + * @return array */ public function getSwim(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 9)); } /** - * @return int[] + * @return array */ public function getRegion(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 10)); } /** - * @return int[] + * @return array */ public function getIq(): array { + /** @var array */ return \array_combine($this->getNames(), \array_column(self::DATA, 11)); } } diff --git a/src/SampleData/PlantGrowth.php b/src/SampleData/PlantGrowth.php index df9311717..5de17504f 100644 --- a/src/SampleData/PlantGrowth.php +++ b/src/SampleData/PlantGrowth.php @@ -65,10 +65,11 @@ public function getData(): array * Raw data with each observation labeled * [['weight' => 4.17, 'group' => 'ctrl'], ['weight' => 5.58, 'group' => 'ctrl'], ... ] * - * @return number[] + * @return array> */ public function getLabeledData(): array { + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::LABELS, $data); @@ -94,6 +95,10 @@ public function getWeight(): array */ public function getGroup(): array { + /** + * FIXME: looks like a mistake: column_key = 0 instead of 1? + * @phpstan-ignore-next-line + */ return \array_column(self::DATA, 0); } } diff --git a/src/SampleData/ToothGrowth.php b/src/SampleData/ToothGrowth.php index 02b538264..6243970cf 100644 --- a/src/SampleData/ToothGrowth.php +++ b/src/SampleData/ToothGrowth.php @@ -96,7 +96,7 @@ public function getData(): array * Raw data with each observation labeled * [['len' => 4.2, 'supp' => 'VC', 'dose' => 0.5], ... ] * - * @return number[] + * @return array> */ public function getLabeledData(): array { @@ -125,6 +125,10 @@ public function getLen(): array */ public function getSupp(): array { + /** + * FIXME: looks like a mistake: column_key = 0 instead of 1? + * @phpstan-ignore-next-line + */ return \array_column(self::DATA, 0); } @@ -135,6 +139,9 @@ public function getSupp(): array */ public function getDose(): array { + /** + * FIXME: looks like a mistake: column_key = 0 instead of 2? + */ return \array_column(self::DATA, 0); } } diff --git a/src/SampleData/UsArrests.php b/src/SampleData/UsArrests.php index e65ab51f3..1cae07a97 100644 --- a/src/SampleData/UsArrests.php +++ b/src/SampleData/UsArrests.php @@ -85,12 +85,13 @@ public function getData(): array * Raw data with each observation labeled * ['Alabama' => ['murder' => 13.2, 'assault' => 236, 'urbanPop' => 58, 'rape' => 21.2], ... ] * - * @return number[][] + * @return array> */ public function getLabeledData(): array { return \array_map( function (array $data) { + /** @var array */ return \array_combine(self::LABELS, $data); }, self::DATA @@ -117,6 +118,7 @@ public function getStates(): array */ public function getStateData(string $state): array { + /** @var array */ return \array_combine(self::LABELS, self::DATA[$state]); } @@ -124,10 +126,11 @@ public function getStateData(string $state): array * Murder observations for all states * ['Alabama' => 13.2, 'Alaska' => 10.1, ... ] * - * @return number[] + * @return array */ public function getMurder(): array { + /** @var array */ return \array_combine($this->getStates(), \array_column(self::DATA, 0)); } @@ -135,10 +138,11 @@ public function getMurder(): array * Assault observations for all states * ['Alabama' => 236, 'Alaska' => 263, ... ] * - * @return number[] + * @return array */ public function getAssault(): array { + /** @var array */ return \array_combine($this->getStates(), \array_column(self::DATA, 1)); } @@ -146,10 +150,11 @@ public function getAssault(): array * UrbanPop observations for all states * ['Alabama' => 58, 'Alaska' => 48, ... ] * - * @return number[] + * @return array */ public function getUrbanPop(): array { + /** @var array */ return \array_combine($this->getStates(), \array_column(self::DATA, 2)); } @@ -157,10 +162,11 @@ public function getUrbanPop(): array * Rape observations for all states * ['Alabama' => 21.2, 'Alaska' => 44.5, ... ] * - * @return number[] + * @return array */ public function getRape(): array { + /** @var array */ return \array_combine($this->getStates(), \array_column(self::DATA, 3)); } } diff --git a/src/Search.php b/src/Search.php index 459d1d998..2fe3aba6d 100644 --- a/src/Search.php +++ b/src/Search.php @@ -76,7 +76,9 @@ function ($value) { } // Standard case: Find max and return index - return self::baseArgMax($values); + /** @var int $result */ + $result = self::baseArgMax($values); + return $result; } /** @@ -110,7 +112,9 @@ function ($value) { throw new Exception\BadDataException('Array of all NANs has no nanArgMax'); } - return self::baseArgMax($valuesWithoutNans); + /** @var int $result */ + $result = self::baseArgMax($valuesWithoutNans); + return $result; } /** @@ -121,9 +125,9 @@ function ($value) { * * @param float[]|int[] $values * - * @return int Index of the first occurrence of the maximum value + * @return int|null Index of the first occurrence of the maximum value */ - private static function baseArgMax(array $values): int + private static function baseArgMax(array $values): ?int { $max = \max($values); foreach ($values as $i => $v) { @@ -131,6 +135,8 @@ private static function baseArgMax(array $values): int return $i; } } + + return null; } /** @@ -170,7 +176,10 @@ function ($value) { } // Standard case: Find max and return index - return self::baseArgMin($values); + + /** @var int $result */ + $result = self::baseArgMin($values); + return $result; } /** @@ -204,7 +213,9 @@ function ($value) { throw new Exception\BadDataException('Array of all NANs has no nanArgMax'); } - return self::baseArgMin($valuesWithoutNans); + /** @var int $result */ + $result = self::baseArgMin($valuesWithoutNans); + return $result; } /** @@ -215,9 +226,9 @@ function ($value) { * * @param float[]|int[] $values * - * @return int Index of the first occurrence of the minimum value + * @return int|null Index of the first occurrence of the minimum value */ - private static function baseArgMin(array $values): int + private static function baseArgMin(array $values): ?int { $max = \min($values); foreach ($values as $i => $v) { @@ -225,6 +236,8 @@ private static function baseArgMin(array $values): int return $i; } } + + return null; } /** diff --git a/src/Sequence/Advanced.php b/src/Sequence/Advanced.php index d09a093cc..5cfcbe3ed 100644 --- a/src/Sequence/Advanced.php +++ b/src/Sequence/Advanced.php @@ -41,7 +41,7 @@ class Advanced * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 + * @return array Indexed from 0 */ public static function fibonacci(int $n): array { @@ -89,7 +89,7 @@ public static function fibonacci(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 + * @return array Indexed from 0 */ public static function lucasNumber(int $n): array { @@ -136,7 +136,7 @@ public static function lucasNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 + * @return array Indexed from 0 */ public static function pellNumber(int $n): array { @@ -183,7 +183,7 @@ public static function pellNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 1 + * @return array Indexed from 1 */ public static function triangularNumber(int $n): array { @@ -217,7 +217,7 @@ public static function triangularNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 1 + * @return array Indexed from 1 */ public static function pentagonalNumber(int $n): array { @@ -251,7 +251,7 @@ public static function pentagonalNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 1 + * @return array Indexed from 1 */ public static function hexagonalNumber(int $n): array { @@ -286,7 +286,7 @@ public static function hexagonalNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 1 + * @return array Indexed from 1 */ public static function heptagonalNumber(int $n): array { @@ -331,7 +331,7 @@ public static function heptagonalNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array of strings indexed from 1 + * @return array of strings indexed from 1 */ public static function lookAndSay(int $n): array { @@ -395,7 +395,7 @@ public static function lookAndSay(int $n): array * * @param int $n How many numbers in the sequence * - * @return array + * @return array */ public static function lazyCaterers(int $n): array { @@ -431,7 +431,7 @@ public static function lazyCaterers(int $n): array * * @param int $n How many numbers in the sequence * - * @return array + * @return array */ public static function magicSquares(int $n): array { @@ -448,6 +448,11 @@ public static function magicSquares(int $n): array return $M; } + /** + * FIXME: big numbers are float, so accuracy is lost. + * php > var_dump(191561942608236107294793378084303638130997321548169216); + * float(1.9156194260824E+53) + */ private const PERFECT_NUMBERS = [ 6, 28, 496, 8128, 33550336, 8589869056, 137438691328, 2305843008139952128, 2658455991569831744654692615953842176, 191561942608236107294793378084303638130997321548169216 ]; @@ -463,7 +468,7 @@ public static function magicSquares(int $n): array * * @param int $n * - * @return array + * @return array * * @throws OutOfBoundsException */ @@ -474,6 +479,10 @@ public static function perfectNumbers(int $n): array } if ($n <= 10) { + /** + * @phpstan-ignore-next-line + * FIXME: Advanced::perfectNumbers() should return array but returns array. + */ return \array_slice(self::PERFECT_NUMBERS, 0, $n); } @@ -495,7 +504,7 @@ public static function perfectNumbers(int $n): array * * @param int $n How many numbers in the sequence * - * @return array + * @return array */ public static function perfectPowers(int $n): array { @@ -530,7 +539,7 @@ public static function perfectPowers(int $n): array * * @param int $n How many numbers in the sequence * - * @return array + * @return array */ public static function notPerfectPowers(int $n): array { @@ -574,7 +583,7 @@ public static function notPerfectPowers(int $n): array * * @param int $n Prime numbers up to this n * - * @return array + * @return array */ public static function primesUpTo(int $n): array { diff --git a/src/Sequence/Basic.php b/src/Sequence/Basic.php index baf846ddb..ebaa50f00 100644 --- a/src/Sequence/Basic.php +++ b/src/Sequence/Basic.php @@ -36,7 +36,7 @@ class Basic * @param int $d Difference between the elements of the sequence * @param int $a₁ Starting number for the sequence * - * @return array Indexed from 1 + * @return array Indexed from 1 */ public static function arithmeticProgression(int $n, int $d, int $a₁): array { @@ -72,7 +72,7 @@ public static function arithmeticProgression(int $n, int $d, int $a₁): array * @param int|float $a Scalar value * @param int|float $r Common ratio * - * @return array Indexed from 0 (indexes are powers of common ratio) + * @return array Indexed from 0 (indexes are powers of common ratio) * * @throws Exception\BadParameterException */ @@ -108,7 +108,7 @@ public static function geometricProgression(int $n, $a, $r): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 (indexes are the base number which is raised to the power of 2) + * @return array Indexed from 0 (indexes are the base number which is raised to the power of 2) */ public static function squareNumber(int $n): array { @@ -138,7 +138,7 @@ public static function squareNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 (indexes are the base number which is raised to the power of 3) + * @return array Indexed from 0 (indexes are the base number which is raised to the power of 3) */ public static function cubicNumber(int $n): array { @@ -168,7 +168,7 @@ public static function cubicNumber(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 (indexes are the power 2 is raised to) + * @return array Indexed from 0 (indexes are the power 2 is raised to) */ public static function powersOfTwo(int $n): array { @@ -196,7 +196,7 @@ public static function powersOfTwo(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 (indexes are the power 10 is raised to) + * @return array Indexed from 0 (indexes are the power 10 is raised to) */ public static function powersOfTen(int $n): array { @@ -224,7 +224,7 @@ public static function powersOfTen(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 (indexes are the n!) + * @return array Indexed from 0 (indexes are the n!) */ public static function factorial(int $n): array { @@ -256,7 +256,7 @@ public static function factorial(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 (indexes are the n in the digitSum(n)) + * @return array Indexed from 0 (indexes are the n in the digitSum(n)) */ public static function digitSum(int $n): array { @@ -284,7 +284,7 @@ public static function digitSum(int $n): array * * @param int $n How many numbers in the sequence * - * @return array Indexed from 0 (indexes are the n in the digitSum(n)) + * @return array Indexed from 0 (indexes are the n in the digitSum(n)) */ public static function digitalRoot(int $n): array { diff --git a/src/SetTheory/ImmutableSet.php b/src/SetTheory/ImmutableSet.php index 5c17110e8..d44fe0f1f 100644 --- a/src/SetTheory/ImmutableSet.php +++ b/src/SetTheory/ImmutableSet.php @@ -37,7 +37,7 @@ public function add($x): Set /** * Cannot add members to an immutable set * - * @param array $x + * @param array $x * * @return Set (this set unchanged) */ @@ -61,7 +61,7 @@ public function remove($x): Set /** * Cannot remove members of an immutable set * - * @param array $x + * @param array $x * * @return Set (this set unchanged) */ diff --git a/src/SetTheory/Set.php b/src/SetTheory/Set.php index fcb7720b4..5ad97011b 100644 --- a/src/SetTheory/Set.php +++ b/src/SetTheory/Set.php @@ -72,6 +72,9 @@ * already is a member of the set. When accessing the actual set member, you * will always get back the original one added, whether it was a Set object or * a string. + * + * @implements \Iterator + * @phpstan-consistent-constructor */ class Set implements \Countable, \Iterator { @@ -79,14 +82,14 @@ class Set implements \Countable, \Iterator * Set as a hash. * Keys are a representation of the members of the set. * Values are the values/objects themselves. - * @var array + * @var array */ protected $A = []; /** * Constructor - Initialize set members * - * @param array $members + * @param array $members */ public function __construct(array $members = []) { @@ -104,7 +107,7 @@ public function __construct(array $members = []) /** * Get the set as an array * - * @return array (values are the set members) + * @return array (values are the set members) */ public function asArray(): array { @@ -147,6 +150,10 @@ public function isEmpty(): bool */ public function isMember($x): bool { + /** + * FIXME: $this->getKey() may return null, int|string required. + * @phpstan-ignore-next-line + */ return \array_key_exists($this->getKey($x), $this->A); } @@ -160,6 +167,10 @@ public function isMember($x): bool */ public function isNotMember($x): bool { + /** + * FIXME: $this->getKey() may return null, int|string required. + * @phpstan-ignore-next-line + */ return !\array_key_exists($this->getKey($x), $this->A); } @@ -190,7 +201,7 @@ public function add($x): Set * Add an array of elements to the set * Does nothing if element already exists in the set. * - * @param array $members + * @param array $members * * @return Set (this set) */ @@ -222,7 +233,7 @@ public function remove($x): Set * Remove elements from the set * Does nothing if the element does not exist in the set. * - * @param array $x + * @param array $x * * @return Set (this set) */ @@ -636,7 +647,7 @@ public function count(): int /** * Iterator interface array to iterate over - * @var array + * @var array */ protected $iterator_keys; diff --git a/src/Statistics/ANOVA.php b/src/Statistics/ANOVA.php index 8f8bc8757..2c825e6bd 100644 --- a/src/Statistics/ANOVA.php +++ b/src/Statistics/ANOVA.php @@ -97,9 +97,9 @@ class ANOVA * F = MSB / MSW * P = F distribution CDF above F with degrees of freedom dfB and dfW * - * @param array[] ...$samples Samples to analyze (at least 3 or more samples) + * @param array ...$samples Samples to analyze (at least 3 or more samples) * - * @return array [ + * @return array [ * ANOVA => [ * treatment => [SS, df, MS, F, P], * error => [SS, df, MS], @@ -338,7 +338,7 @@ function ($sample) use ($n, $μ) { * Factor A₁ | 4, 6, 8 | 6, 6, 9 | ⋯ * Factor A₂ | 4, 8, 9 | 7, 10, 13 | ⋯ * ⋮ ⋮ ⋮ ⋮ - * @param array[] ...$data Samples to analyze [ + * @param array ...$data Samples to analyze [ * // Factor A₁ * [ * [4, 6, 8] // Factor B₁ @@ -354,7 +354,7 @@ function ($sample) use ($n, $μ) { * ... * ] * - * @return array [ + * @return array [ * ANOVA => [ * factorA => [SS, df, MS, F, P], * factorB => [SS, df, MS, F, P], diff --git a/src/Statistics/Average.php b/src/Statistics/Average.php index 02f0430a2..a8f377d92 100644 --- a/src/Statistics/Average.php +++ b/src/Statistics/Average.php @@ -191,7 +191,11 @@ public static function kthSmallest(array $numbers, int $k): float * @param float[] $numbers * @param float $value * - * @return array + * @return array{ + * lower: array, + * upper: array, + * equal: int, + * } */ private static function splitAtValue(array $numbers, float $value): array { @@ -455,7 +459,7 @@ public static function iqm(array $numbers): float * x cubic = ³/ - ∑ xᵢ³ * √ n ⁱ⁼¹ * - * @param array $numbers + * @param array $numbers * * @return float * @@ -717,11 +721,11 @@ public static function cumulativeMovingAverage(array $numbers): array * * Each weighted average = ∑(weighted values) / ∑(weights) * - * @param array $numbers - * @param int $n n-point moving average - * @param array $weights Weights for each n points + * @param array $numbers + * @param int $n n-point moving average + * @param array $weights Weights for each n points * - * @return array of averages + * @return array of averages * * @throws Exception\BadDataException if number of weights is not equal to number of n-points */ @@ -753,10 +757,10 @@ public static function weightedMovingAverage(array $numbers, int $n, array $weig * where * α: coefficient that represents the degree of weighting decrease, a constant smoothing factor between 0 and 1. * - * @param array $numbers - * @param int $n Length of the EPA + * @param array $numbers + * @param int $n Length of the EPA * - * @return array of exponential moving averages + * @return array of exponential moving averages */ public static function exponentialMovingAverage(array $numbers, int $n): array { @@ -915,10 +919,20 @@ public static function identricMean(float $x, float $y): float * Get a report of all the averages over a list of numbers * Includes mean, median mode, geometric mean, harmonic mean, quardratic mean * - * @param array $numbers - * - * @return array [ mean, median, mode, geometric_mean, harmonic_mean, - * contraharmonic_mean, quadratic_mean, trimean, iqm, cubic_mean ] + * @param array $numbers + * + * @return array{ + * mean: float, + * median: float, + * mode: float[], + * geometric_mean: float, + * harmonic_mean: float, + * contraharmonic_mean: float, + * quadratic_mean: float, + * trimean: float, + * iqm: float, + * cubic_mean: float, + * } * * @throws Exception\BadDataException * @throws Exception\OutOfBoundsException diff --git a/src/Statistics/Circular.php b/src/Statistics/Circular.php index 7a5dc26d6..46553fd02 100644 --- a/src/Statistics/Circular.php +++ b/src/Statistics/Circular.php @@ -17,7 +17,7 @@ class Circular * _ * α = atan2(∑sin αⱼ, ∑cos αⱼ) * - * @param array $angles + * @param array $angles * * @return float mean direction of circular data */ @@ -49,7 +49,7 @@ function ($αⱼ) { * R² = S² + C² * R = √(S² + C²) * - * @param array $angles + * @param array $angles * * @return float */ @@ -93,7 +93,7 @@ function ($θᵢ) { * _ * ρ = R * - * @param array $angles + * @param array $angles * * @return float */ @@ -115,7 +115,7 @@ public static function meanResultantLength(array $angles): float * Var(θ) = 1 - R * Var(θ) = 1 - ρ * - * @param array $angles + * @param array $angles * * @return float */ @@ -138,7 +138,7 @@ public static function variance(array $angles): float * _ * Where R = ρ = mean resultant length * - * @param array $angles + * @param array $angles * * @return float */ @@ -154,9 +154,16 @@ public static function standardDeviation(array $angles): float * Get a report of all the descriptive circular statistics over a list of angles * Includes mean, resultant length, mean resultant length, variance, standard deviation. * - * @param array $angles + * @param array $angles * - * @return array [ n, mean, resultant_length, mean_resultant_length, variance, sd] + * @return array{ + * n: int, + * mean: float, + * resultant_length: float, + * mean_resultant_length: float, + * variance: float, + * sd: float, + * } */ public static function describe(array $angles): array { diff --git a/src/Statistics/Correlation.php b/src/Statistics/Correlation.php index cc9e5241e..196a20bab 100644 --- a/src/Statistics/Correlation.php +++ b/src/Statistics/Correlation.php @@ -35,8 +35,8 @@ class Correlation * The population covariance is defined in terms of the sample means x, y * https://en.wikipedia.org/wiki/Covariance * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * @param bool $population Optional flag for population or sample covariance * * @return float @@ -63,8 +63,8 @@ public static function covariance(array $X, array $Y, bool $population = false): * cov(X, Y) = σxy = ----------------- * N * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * * @return float * @@ -103,8 +103,8 @@ function ($xᵢ, $yᵢ) use ($μₓ, $μy) { * cov(X, Y) = Sxy = --------------- * n - 1 * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * * @return float * @@ -139,9 +139,9 @@ function ($xᵢ, $yᵢ) use ($x, $y) { * cov(X, Y, w) = sxyw = -------------------- * ∑wᵢ * - * @param array $X values for random variable X - * @param array $Y values for random variable Y - * @param array $w values for weights + * @param array $X values for random variable X + * @param array $Y values for random variable Y + * @param array $w values for weights * * @return float * @@ -176,8 +176,8 @@ function ($xᵢ, $yᵢ, $wᵢ) use ($μₓ, $μy) { * * Convenience method for population and sample correlationCoefficient * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * @param bool $population Optional flag for population or sample covariance * * @return float @@ -214,8 +214,8 @@ public static function r(array $X, array $Y, bool $population = false): float * σx is the population standard deviation of X * σy is the population standard deviation of Y * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * * @return float * @@ -253,8 +253,8 @@ public static function populationCorrelationCoefficient(array $X, array $Y): flo * σx is the sample standard deviation of X * σy is the sample standard deviation of Y * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * * @return float * @@ -274,8 +274,8 @@ public static function sampleCorrelationCoefficient(array $X, array $Y): float * R² - coefficient of determination * Convenience wrapper for coefficientOfDetermination * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * @param bool $popluation * * @return float @@ -296,8 +296,8 @@ public static function r2(array $X, array $Y, bool $popluation = false): float * Range of 0 - 1. Close to 1 means the regression line is a good fit * https://en.wikipedia.org/wiki/Coefficient_of_determination * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * @param bool $popluation * * @return float @@ -331,9 +331,9 @@ public static function coefficientOfDetermination(array $X, array $Y, bool $popl * sxw is the weighted variance of X * syw is the weighted variance of Y * - * @param array $X values for random variable X - * @param array $Y values for random variable Y - * @param array $w values for weights + * @param array $X values for random variable X + * @param array $Y values for random variable Y + * @param array $w values for weights * * @return float * @@ -378,8 +378,8 @@ public static function weightedCorrelationCoefficient(array $X, array $Y, array * X₀: number of pairs tied only on the X variable * Y₀: number of pairs tied only on the Y variable * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * * @todo Implement with algorithm faster than O(n²) * @@ -471,8 +471,8 @@ function ($x, $y) { * cov(rgᵪ, rgᵧ): covariance of the rank variables * σᵣᵪ and σᵣᵧ: standard deviations of the rank variables * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * * @return float * @@ -497,11 +497,17 @@ public static function spearmansRho(array $X, array $Y): float /** * Descriptive correlation report about two random variables * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * @param bool $population Optional flag if all samples of a population are present * - * @return array [cov, r, R2, tau, rho] + * @return array{ + * cov: float, + * r: float, + * r2: float, + * tau: float, + * rho: float, + * } * * @throws Exception\BadDataException * @throws Exception\OutOfBoundsException @@ -525,14 +531,14 @@ public static function describe(array $X, array $Y, bool $population = false): a * The function will return $num_points pairs of X,Y data * http://stackoverflow.com/questions/3417028/ellipse-around-the-data-in-matlab * - * @param array $X an array of independent data - * @param array $Y an array of dependent data + * @param array $X an array of independent data + * @param array $Y an array of dependent data * @param float $z the number of standard deviations to encompass * @param int $num_points the number of points to include around the ellipse. The actual array * will be one larger because the first point and last will be repeated * to ease display. * - * @return array paired x and y points on an ellipse aligned with the data provided + * @return array> paired x and y points on an ellipse aligned with the data provided * * @throws Exception\BadDataException * @throws Exception\BadParameterException diff --git a/src/Statistics/Descriptive.php b/src/Statistics/Descriptive.php index 35884f6a6..9e7a35378 100644 --- a/src/Statistics/Descriptive.php +++ b/src/Statistics/Descriptive.php @@ -385,7 +385,14 @@ public static function quartiles(array $numbers, string $method = 'exclusive'): * * @param float[] $numbers * - * @return array (0%, Q1, Q2, Q3, 100%, IQR) + * @return array{ + * "0%": float, + * "Q1": float, + * "Q2": float, + * "Q3": float, + * "100%": float, + * "IQR": float, + * } * * @throws Exception\BadDataException if the input array of numbers is empty */ @@ -410,8 +417,8 @@ public static function quartilesExclusive(array $numbers): array $length = \count($numbers); if ($length % 2 == 0) { - $lower_half = \array_slice($numbers, 0, $length / 2); - $upper_half = \array_slice($numbers, $length / 2); + $lower_half = \array_slice($numbers, 0, (int)($length / 2)); + $upper_half = \array_slice($numbers, (int)($length / 2)); } else { $lower_half = \array_slice($numbers, 0, \intdiv($length, 2)); $upper_half = \array_slice($numbers, \intdiv($length, 2) + 1); @@ -456,7 +463,14 @@ public static function quartilesExclusive(array $numbers): array * * @param float[] $numbers * - * @return array (0%, Q1, Q2, Q3, 100%, IQR) + * @return array{ + * "0%": float, + * "Q1": float, + * "Q2": float, + * "Q3": float, + * "100%": float, + * "IQR": float, + * } * * @throws Exception\BadDataException if the input array of numbers is empty */ @@ -470,8 +484,8 @@ public static function quartilesInclusive(array $numbers): array $length = \count($numbers); if ($length % 2 == 0) { - $lower_half = \array_slice($numbers, 0, $length / 2); - $upper_half = \array_slice($numbers, $length / 2); + $lower_half = \array_slice($numbers, 0, (int)($length / 2)); + $upper_half = \array_slice($numbers, (int)($length / 2)); } else { $lower_half = \array_slice($numbers, 0, \intdiv($length, 2)); $upper_half = \array_slice($numbers, \intdiv($length, 2) + 1); @@ -649,8 +663,30 @@ public static function coefficientOfVariation(array $numbers): float * @param bool $population : true means all possible observations of the system are present; * false means a sample is used. * - * @return array [n, mean, median, mode, range, midrange, variance, sd, CV, mean_mad, - * median_mad, quartiles, skewness, kurtosis, sem, ci_95, ci_99] + * @return array{ + * n: int<0, max>, + * min: float|false, + * max: float|false, + * mean: float, + * median: float, + * mode: float[], + * range: float, + * midrange: float, + * variance: float, + * sd: float, + * cv: float, + * mean_mad: float, + * median_mad: float, + * quartiles: float[], + * midhinge: float, + * skewness: float|null, + * ses: float|null, + * kurtosis: float|null, + * sek: float|null, + * sem: float, + * ci_95: array{ci: float|null, lower_bound: float|null, upper_bound: float|null}, + * ci_99: array{ci: float|null, lower_bound: float|null, upper_bound: float|null}, + * } * * @throws Exception\OutOfBoundsException * @throws Exception\BadDataException @@ -703,9 +739,15 @@ public static function describe(array $numbers, bool $population = false): array * * https://en.wikipedia.org/wiki/Five-number_summary * - * @param array $numbers + * @param array $numbers * - * @return array [min, Q1, median, Q3, max] + * @return array{ + * min: float|int|false, + * Q1: float, + * median: float, + * Q3: float, + * max: float|int|false, + * } * * @throws Exception\BadDataException */ diff --git a/src/Statistics/Distance.php b/src/Statistics/Distance.php index 900ed6d37..709ee55c8 100644 --- a/src/Statistics/Distance.php +++ b/src/Statistics/Distance.php @@ -49,8 +49,8 @@ class Distance * BC(p,q) = ∑ √(p(x) q(x)) * x∈X * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float distance between distributions * @@ -84,8 +84,8 @@ public static function bhattacharyya(array $p, array $q): float * H(P,Q) = -- √ ∑ (√pᵢ - √qᵢ)² * √2 * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float difference between distributions * @@ -146,8 +146,8 @@ function ($pᵢ, $qᵢ) { * * D(P‖Q) = Kullback-Leibler divergence * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float * @@ -373,8 +373,8 @@ public static function cosineSimilarity(array $A, array $B): float * ----------- * ∑|uᵢ + vᵢ| * - * @param array $u - * @param array $v + * @param array $u + * @param array $v * * @return float */ @@ -423,8 +423,8 @@ function (float $uᵢ, float $vᵢ) { * d(p,q) = ∑ -------------- * |pᵢ| + |qᵢ| * - * @param array $p - * @param array $q + * @param array $p + * @param array $q * * @return float */ diff --git a/src/Statistics/Distribution.php b/src/Statistics/Distribution.php index 792f8d72a..cca1c09bd 100644 --- a/src/Statistics/Distribution.php +++ b/src/Statistics/Distribution.php @@ -17,9 +17,9 @@ class Distribution * The values of the input array will be the keys of the result array. * The count of the values will be the value of the result array for that key. * - * @param array $values Ex: ( A, A, A, B, B, C ) + * @param array $values Ex: ( A, A, A, B, B, C ) * - * @return array frequency distribution Ex: ( A => 3, B => 2, C => 1 ) + * @return array frequency distribution Ex: ( A => 3, B => 2, C => 1 ) */ public static function frequency(array $values): array { @@ -43,9 +43,9 @@ public static function frequency(array $values): array * The values of the input array will be the keys of the result array. * The relative frequency of the values will be the value of the result array for that key. * - * @param array $values Ex: ( A, A, A, A, A, A, B, B, B, C ) + * @param array $values Ex: ( A, A, A, A, A, A, B, B, B, C ) * - * @return array relative frequency distribution Ex: ( A => 0.6, B => 0.3, C => 0.1 ) + * @return array relative frequency distribution Ex: ( A => 0.6, B => 0.3, C => 0.1 ) */ public static function relativeFrequency(array $values): array { @@ -63,9 +63,9 @@ public static function relativeFrequency(array $values): array * The values of the input array will be the keys of the result array. * The cumulative frequency of the values will be the value of the result array for that key. * - * @param array $values Ex: ( A, A, A, A, A, A, B, B, B, C ) + * @param array $values Ex: ( A, A, A, A, A, A, B, B, B, C ) * - * @return array cumulative frequency distribution Ex: ( A => 6, B => 9, C => 10 ) + * @return array cumulative frequency distribution Ex: ( A => 6, B => 9, C => 10 ) */ public static function cumulativeFrequency(array $values): array { @@ -87,9 +87,9 @@ public static function cumulativeFrequency(array $values): array * The values of the input array will be the keys of the result array. * The cumulative frequency of the values will be the value of the result array for that key. * - * @param array $values Ex: ( A, A, A, A, A, A, B, B, B, C ) + * @param array $values Ex: ( A, A, A, A, A, A, B, B, B, C ) * - * @return array cumulative relative frequency distribution Ex: ( A => 0.6, B => 0.9, C => 1 ) + * @return array cumulative relative frequency distribution Ex: ( A => 0.6, B => 0.9, C => 1 ) */ public static function cumulativeRelativeFrequency(array $values): array { @@ -109,9 +109,9 @@ function ($frequency) use ($sample_size) { * * Similar to R: rank(values, ties.method='average') * - * @param array $values to be ranked + * @param array $values to be ranked * - * @return array Rankings of the data in the same order the values were input + * @return array Rankings of the data in the same order the values were input */ public static function fractionalRanking(array $values): array { @@ -148,9 +148,9 @@ function ($value) use ($rg⟮X⟯) { * * Similar to R: rank(values, ties.method='min') * - * @param array $values to be ranked + * @param array $values to be ranked * - * @return array Rankings of the data in the same order the values were input + * @return array Rankings of the data in the same order the values were input */ public static function standardCompetitionRanking(array $values): array { @@ -166,6 +166,7 @@ public static function standardCompetitionRanking(array $values): array : $i + 1; } + /** @var array> $ranking⟮X⟯ */ $ranking⟮X⟯ = \array_combine(\array_map('\strval', $Xs), $ranking⟮X⟯); // Map ranks to values in order they were originally input @@ -183,9 +184,9 @@ function ($value) use ($ranking⟮X⟯) { * * Similar to R: rank(values, ties.method='max') * - * @param array $values to be ranked + * @param array $values to be ranked * - * @return array Rankings of the data in the same order the values were input + * @return array Rankings of the data in the same order the values were input */ public static function modifiedCompetitionRanking(array $values): array { @@ -201,6 +202,8 @@ public static function modifiedCompetitionRanking(array $values): array : $i + 1; } \sort($ranking⟮X⟯); + + /** @var array> $ranking⟮X⟯ */ $ranking⟮X⟯ = \array_combine(\array_map('\strval', $Xs), $ranking⟮X⟯); // Map ranks to values in order they were originally input @@ -218,9 +221,9 @@ function ($value) use ($ranking⟮X⟯) { * * Similar to R: rank(values, ties.method='first') * - * @param array $values to be ranked + * @param array $values to be ranked * - * @return array Rankings of the data in the same order the values were input + * @return array Rankings of the data in the same order the values were input */ public static function ordinalRanking(array $values): array { @@ -259,10 +262,10 @@ public static function ordinalRanking(array $values): array * 9 | * 10 | 6 * - * @param array $values + * @param array $values * @param bool $print Optional setting to print the distribution * - * @return array keys are the stems, values are the leaves + * @return array> keys are the stems, values are the leaves */ public static function stemAndLeafPlot(array $values, bool $print = false): array { @@ -291,7 +294,7 @@ public static function stemAndLeafPlot(array $values, bool $print = false): arra // Optionally print the stem and leaf plot if ($print === true) { $length = \max(\array_map(function ($stem) { - return \strlen($stem); + return \strlen((string)$stem); }, \array_keys($plot))); foreach ($plot as $stem => $leaves) { \printf("%{$length}d | %s\n", $stem, \implode(' ', $leaves)); diff --git a/src/Statistics/Divergence.php b/src/Statistics/Divergence.php index b17d58a08..7162c768a 100644 --- a/src/Statistics/Divergence.php +++ b/src/Statistics/Divergence.php @@ -35,8 +35,8 @@ class Divergence * * * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float difference between distributions * @@ -99,8 +99,8 @@ function ($P, $Q) { * * D(P‖Q) = Kullback-Leibler divergence * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float difference between distributions * diff --git a/src/Statistics/Experiment.php b/src/Statistics/Experiment.php index a2dd871d5..1593c192b 100644 --- a/src/Statistics/Experiment.php +++ b/src/Statistics/Experiment.php @@ -58,7 +58,12 @@ class Experiment * @param int $c Non-exposed and event present * @param int $d Non-exposed and event absent * - * @return array [ RR, ci_lower_bound, ci_upper_bound, p ] + * @return array{ + * RR: float, + * ci_lower_bound: float, + * ci_upper_bound: float, + * p: float, + * } */ public static function riskRatio(int $a, int $b, int $c, int $d): array { @@ -120,7 +125,12 @@ public static function riskRatio(int $a, int $b, int $c, int $d): array * @param int $c Non-exposed and event present * @param int $d Non-exposed and event absent * - * @return array [ OR, ci_lower_bound, ci_upper_bound, p ] + * @return array{ + * OR: float, + * ci_lower_bound: float, + * ci_upper_bound: float, + * p: float, + * } */ public static function oddsRatio(int $a, int $b, int $c, int $d): array { @@ -171,7 +181,10 @@ public static function oddsRatio(int $a, int $b, int $c, int $d): array * @param int $c Non-exposed and event present * @param int $d Non-exposed and event absent * - * @return array [ LL+, LL- ] + * @return array{ + * "LL+": float, + * "LL-": float, + * } */ public static function likelihoodRatio(int $a, int $b, int $c, int $d): array { @@ -205,7 +218,10 @@ public static function likelihoodRatio(int $a, int $b, int $c, int $d): array * @param float $sensitivity * @param float $specificity * - * @return array [ LL+, LL- ] + * @return array{ + * "LL+": float, + * "LL-": float, + * } * * @throws Exception\OutOfBoundsException if sensitivity or specificity are > 1.0 */ diff --git a/src/Statistics/KernelDensityEstimation.php b/src/Statistics/KernelDensityEstimation.php index c436f7c44..7d182338e 100644 --- a/src/Statistics/KernelDensityEstimation.php +++ b/src/Statistics/KernelDensityEstimation.php @@ -18,7 +18,7 @@ */ class KernelDensityEstimation { - /** @var array Data used for the esimtation */ + /** @var array Data used for the esimtation */ protected $data; /** @var int number of data points */ @@ -41,7 +41,7 @@ class KernelDensityEstimation /** * Constructor * - * @param array $data data used for the estimation + * @param array $data data used for the estimation * @param float|null $h the bandwidth * @param callable|string|null $kernel a function used to generate the KDE * diff --git a/src/Statistics/Multivariate/PCA.php b/src/Statistics/Multivariate/PCA.php index 9b5b9d236..b9bc1b77f 100644 --- a/src/Statistics/Multivariate/PCA.php +++ b/src/Statistics/Multivariate/PCA.php @@ -117,7 +117,9 @@ public function standardizeData(NumericMatrix $new_data = null): NumericMatrix $ones_column = MatrixFactory::one($X->getM(), 1); // Create a matrix the same dimensions as $new_data, each element is the average of that column in the original data. - $center_matrix = $ones_column->multiply(MatrixFactory::create([$this->center->getVector()])); + /** @var NumericMatrix $mult */ + $mult = MatrixFactory::create([$this->center->getVector()]); + $center_matrix = $ones_column->multiply($mult); $scale_matrix = MatrixFactory::diagonal($this->scale->getVector())->inverse(); // scaled data: ($X - μ) / σ @@ -235,12 +237,14 @@ public function getQResiduals(NumericMatrix $new_data = null): NumericMatrix // Initial element with initialization of result matrix $P = $this->EVec->submatrix(0, 0, $vars - 1, 0); // Get the first column of the loading matrix $P′ = $P->transpose(); + /** @var NumericMatrix $Q */ $Q = MatrixFactory::create([$X->multiply($I->subtract($P->multiply($P′)))->multiply($X′)->getDiagonalElements()])->transpose(); for ($i = 1; $i < $vars; $i++) { // Get the first $i+1 columns of the loading matrix $P = $this->EVec->submatrix(0, 0, $vars - 1, $i); $P′ = $P->transpose(); + /** @var NumericMatrix $Qᵢ */ $Qᵢ = MatrixFactory::create([$X->multiply($I->subtract($P->multiply($P′)))->multiply($X′)->getDiagonalElements()])->transpose(); $Q = $Q->augment($Qᵢ); } @@ -278,6 +282,7 @@ public function getT2Distances(NumericMatrix $new_data = null): NumericMatrix $P = $this->EVec->submatrix(0, 0, $vars - 1, 0); // // Get the first column of the loading matrix $P′ = $P->transpose(); $Λⱼ⁻¹ = MatrixFactory::diagonal(\array_slice($this->EVal->getVector(), 0, 0 + 1))->inverse(); + /** @var NumericMatrix $T² */ $T² = MatrixFactory::create([$X->multiply($P)->multiply($Λⱼ⁻¹)->multiply($P′)->multiply($X′)->getDiagonalElements()])->transpose(); for ($i = 1; $i < $this->data->getN(); $i++) { @@ -285,6 +290,7 @@ public function getT2Distances(NumericMatrix $new_data = null): NumericMatrix $P = $this->EVec->submatrix(0, 0, $vars - 1, $i); $P′ = $P->transpose(); $Λⱼ⁻¹ = MatrixFactory::diagonal(\array_slice($this->EVal->getVector(), 0, $i + 1))->inverse(); + /** @var NumericMatrix $Tᵢ² */ $Tᵢ² = MatrixFactory::create([$X->multiply($P)->multiply($Λⱼ⁻¹)->multiply($P′)->multiply($X′)->getDiagonalElements()])->transpose(); $T² = $T²->augment($Tᵢ²); } diff --git a/src/Statistics/Multivariate/PLS.php b/src/Statistics/Multivariate/PLS.php index 6bc9debd2..e0b44fb26 100644 --- a/src/Statistics/Multivariate/PLS.php +++ b/src/Statistics/Multivariate/PLS.php @@ -3,8 +3,15 @@ namespace MathPHP\Statistics\Multivariate; use MathPHP\Exception; +use MathPHP\Exception\BadDataException; +use MathPHP\Exception\IncorrectTypeException; +use MathPHP\Exception\MathException; +use MathPHP\Exception\MatrixException; +use MathPHP\Exception\OutOfBoundsException; use MathPHP\LinearAlgebra\Matrix; use MathPHP\LinearAlgebra\MatrixFactory; +use MathPHP\LinearAlgebra\NumericMatrix; +use MathPHP\LinearAlgebra\ObjectMatrix; use MathPHP\LinearAlgebra\Vector; use MathPHP\Statistics\Descriptive; @@ -29,31 +36,33 @@ class PLS /** @var Vector Y Scale */ private $Yscale; - /** @var Matrix $B Regression Coefficients*/ + /** @var NumericMatrix $B Regression Coefficients */ private $B; - /** @var Matrix $C Y Loadings*/ + /** @var NumericMatrix $C Y Loadings */ private $C; - /** @var Matrix $P Projection of X to X scores*/ + /** @var NumericMatrix $P Projection of X to X scores */ private $P; - /** @var Matrix $T X Scores*/ + /** @var NumericMatrix $T X Scores */ private $T; - /** @var Matrix $U Y Scores*/ + /** @var NumericMatrix $U Y Scores */ private $U; - /** @var Matrix $W X Weights*/ + /** @var NumericMatrix $W X Weights */ private $W; /** - * @param Matrix $X each row is a sample, each column is a variable - * @param Matrix $Y each row is a sample, each column is a variable + * @param NumericMatrix $X each row is a sample, each column is a variable + * @param NumericMatrix $Y each row is a sample, each column is a variable * @param int $ncomp number of components to use in the model * @param bool $scale standardize each column? * * @throws Exception\BadDataException if any rows have a different column count + * + * FIXME: cannot use Matrix, only NumericMatrix (because of using `columnMeans()` function). */ public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = false) { @@ -69,8 +78,12 @@ public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = fals $this->Xscale = self::columnStdevs($X); $this->Yscale = self::columnStdevs($Y); } else { - $this->Xscale = new Vector(array_fill(0, $X->getN(), 1)); - $this->Yscale = new Vector(array_fill(0, $Y->getN(), 1)); + /** @var array $xFill */ + $xFill = array_fill(0, $X->getN(), 1); + $this->Xscale = new Vector($xFill); + /** @var array $yFill */ + $yFill = array_fill(0, $Y->getN(), 1); + $this->Yscale = new Vector($yFill); } $E = $this->standardizeData($X, $this->Xcenter, $this->Xscale); @@ -112,10 +125,15 @@ public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = fals $F = $F->subtract($t->multiply($c->transpose())->scalarMultiply($d)); // Add each of these columns to the overall matrices + // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) $this->C = is_null($this->C) ? $c : $this->C->augment($c); + // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) $this->P = is_null($this->P) ? $p : $this->P->augment($p); + // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) $this->T = is_null($this->T) ? $t : $this->T->augment($t); + // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) $this->U = is_null($this->U) ? $u : $this->U->augment($u); + // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) $this->W = is_null($this->W) ? $w : $this->W->augment($w); } @@ -138,6 +156,8 @@ public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = fals * Get the regression coefficients * * The matrix that best transforms E into F + * + * @return NumericMatrix */ public function getCoefficients(): Matrix { @@ -148,6 +168,8 @@ public function getCoefficients(): Matrix * Get the loadings for Y * * Each loading column transforms F to U + * + * @return NumericMatrix */ public function getYLoadings(): Matrix { @@ -158,6 +180,8 @@ public function getYLoadings(): Matrix * Get the projection matrix * * Each projection column transforms T into Ê + * + * @return NumericMatrix */ public function getProjection(): Matrix { @@ -168,6 +192,8 @@ public function getProjection(): Matrix * Get the scores for the X values * * The latent variables of X + * + * @return NumericMatrix */ public function getXScores(): Matrix { @@ -178,6 +204,8 @@ public function getXScores(): Matrix * Get the scores for the Y values * * The latent variables of Y + * + * @return NumericMatrix */ public function getYScores(): Matrix { @@ -188,6 +216,8 @@ public function getYScores(): Matrix * Get the loadings for the X values * * Each loading column transforms E into T + * + * @return NumericMatrix */ public function getXLoadings(): Matrix { @@ -200,9 +230,11 @@ public function getXLoadings(): Matrix * Use the regression model to predict new values of Y given values for X. * Y = (X - μₓ) ∗ σₓ⁻¹ ∗ B ∗ σ + μ * - * @param Matrix $X + * @param NumericMatrix $X + * + * @return NumericMatrix * - * @return Matrix + * @throws BadDataException */ public function predict(Matrix $X): Matrix { @@ -227,11 +259,11 @@ public function predict(Matrix $X): Matrix * Standardize the data * Use provided $center and $scale Vectors to transform the provided data * - * @param Matrix $new_data - A Matrix of new data which is standardized against the original data - * @param Vector $center - A list of values to center the data against - * @param Vector $scale - A list of standard deviations to scale the data with. + * @param NumericMatrix $new_data - A Matrix of new data which is standardized against the original data + * @param Vector $center - A list of values to center the data against + * @param Vector $scale - A list of standard deviations to scale the data with. * - * @return Matrix + * @return NumericMatrix * * @throws Exception\MathException */ @@ -239,7 +271,7 @@ private function standardizeData(Matrix $new_data, Vector $center, Vector $scale { // Create a matrix the same dimensions as $new_data, each element is the average of that column in the original data. $ones_column = MatrixFactory::one($new_data->getM(), 1); - $center_matrix = $center_matrix ?? $ones_column->multiply(MatrixFactory::createNumeric([$center->getVector()])); + $center_matrix = $ones_column->multiply(MatrixFactory::createNumeric([$center->getVector()])); // Create a diagonal matrix of the inverse of each column standard deviation. $scale_matrix = MatrixFactory::diagonal($scale->getVector())->inverse(); @@ -252,7 +284,7 @@ private function standardizeData(Matrix $new_data, Vector $center, Vector $scale * Column Standard Deviations * Create a Vector with the standard deviations of each column of the supplied matrix * - * @param Matrix $M - A Matrix of which to calculate the standard deviations. + * @param NumericMatrix $M - A Matrix of which to calculate the standard deviations. * * @return Vector */ diff --git a/src/Statistics/Outlier.php b/src/Statistics/Outlier.php index 097466018..04ca0648b 100644 --- a/src/Statistics/Outlier.php +++ b/src/Statistics/Outlier.php @@ -125,7 +125,7 @@ public static function grubbsCriticalValue(float $𝛼, int $n, string $typeOfTe * * @throws Exception\BadParameterException */ - private static function validateGrubbsCriticalValueTestType(string $typeOfTest) + private static function validateGrubbsCriticalValueTestType(string $typeOfTest): void { if (!\in_array($typeOfTest, [self::ONE_SIDED, self::TWO_SIDED])) { throw new Exception\BadParameterException("{$typeOfTest} is not a valid Grubbs' test"); diff --git a/src/Statistics/RandomVariable.php b/src/Statistics/RandomVariable.php index 541b48684..79a3b7e94 100644 --- a/src/Statistics/RandomVariable.php +++ b/src/Statistics/RandomVariable.php @@ -379,7 +379,7 @@ public static function kurtosis(array $X, string $type = self::POPULATION_KURTOS * Is the kurtosis negative? (Platykurtic) * Indicates a flat distribution. * - * @param array $X list of numbers (random variable X) + * @param array $X list of numbers (random variable X) * @param string $type (optional) determines the kurtsosis algorithm used (POPULATION_KURTOSIS (default), SAMPLE_KURTOSIS) * * @return bool true if platykurtic @@ -395,7 +395,7 @@ public static function isPlatykurtic(array $X, string $type = self::POPULATION_K * Is the kurtosis postive? (Leptokurtic) * Indicates a peaked distribution. * - * @param array $X list of numbers (random variable X) + * @param array $X list of numbers (random variable X) * @param string $type (optional) determines the kurtsosis algorithm used (POPULATION_KURTOSIS (default), SAMPLE_KURTOSIS) * * @return bool true if leptokurtic @@ -411,7 +411,7 @@ public static function isLeptokurtic(array $X, string $type = self::POPULATION_K * Is the kurtosis zero? (Mesokurtic) * Indicates a normal distribution. * - * @param array $X list of numbers (random variable X) + * @param array $X list of numbers (random variable X) * @param string $type (optional) determines the kurtsosis algorithm used (POPULATION_KURTOSIS (default), SAMPLE_KURTOSIS) * * @return bool true if mesokurtic @@ -483,7 +483,7 @@ public static function standardErrorOfTheMean(array $X): float /** * SEM - Convenience method for standard error of the mean * - * @param array $X list of numbers (random variable X) + * @param array $X list of numbers (random variable X) * * @return float * @@ -513,7 +513,11 @@ public static function sem(array $X): float * @param float $σ standard deviation * @param string $cl confidence level (Ex: 95, 99, 99.5, 99.9, etc.) * - * @return array [ ci, lower_bound, upper_bound ] + * @return array{ + * ci: float|null, + * lower_bound: float|null, + * upper_bound: float|null, + * } * * @throws Exception\BadDataException */ diff --git a/src/Statistics/Regression/LOESS.php b/src/Statistics/Regression/LOESS.php index 0981e6149..6fa1b7d0b 100644 --- a/src/Statistics/Regression/LOESS.php +++ b/src/Statistics/Regression/LOESS.php @@ -36,15 +36,15 @@ class LOESS extends NonParametricRegression protected $number_of_points; /** - * @param array $points [ [x, y], [x, y], ... ] - * @param float $α Smoothness parameter (bandwidth) - * Determines how much of the data is used to fit each local polynomial - * ((λ + 1) / n, 1] - * @param int $λ Order of the polynomial to fit + * @param array $points [ [x, y], [x, y], ... ] + * @param float $α Smoothness parameter (bandwidth) + * Determines how much of the data is used to fit each local polynomial + * ((λ + 1) / n, 1] + * @param int $λ Order of the polynomial to fit * * @throws Exception\OutOfBoundsException if α is ≤ λ + 1 or > 1 */ - public function __construct($points, float $α, int $λ) + public function __construct(array $points, float $α, int $λ) { $this->α = $α; $this->λ = $λ; diff --git a/src/Statistics/Regression/Linear.php b/src/Statistics/Regression/Linear.php index 8f31dec6e..d9e91c871 100644 --- a/src/Statistics/Regression/Linear.php +++ b/src/Statistics/Regression/Linear.php @@ -30,30 +30,6 @@ class Linear extends ParametricRegression use Methods\LeastSquares; use Models\LinearModel; - /** - * Average of x - * @var number - */ - private $xbar; - - /** - * Average of y - * @var number - */ - private $ybar; - - /** - * Sum of squared deviations of x - * @var number - */ - private $SSx; - - /** - * Sum of squares residuals - * @var number - */ - private $SSres; - /** * Calculates the regression parameters. * diff --git a/src/Statistics/Regression/LinearThroughPoint.php b/src/Statistics/Regression/LinearThroughPoint.php index 4a34b5571..55e6b81aa 100644 --- a/src/Statistics/Regression/LinearThroughPoint.php +++ b/src/Statistics/Regression/LinearThroughPoint.php @@ -42,8 +42,8 @@ class LinearThroughPoint extends ParametricRegression * * This procedure is most frequently used with $force = [0,0], the origin. * - * @param array $points - * @param array $force Point to force regression line through (default: origin) + * @param array $points + * @param array{float, float} $force Point to force regression line through (default: origin) */ public function __construct(array $points, array $force = [0,0]) { diff --git a/src/Statistics/Regression/Methods/LeastSquares.php b/src/Statistics/Regression/Methods/LeastSquares.php index 8f06a8b94..74677052d 100644 --- a/src/Statistics/Regression/Methods/LeastSquares.php +++ b/src/Statistics/Regression/Methods/LeastSquares.php @@ -2,6 +2,9 @@ namespace MathPHP\Statistics\Regression\Methods; +use MathPHP\Exception\BadDataException; +use MathPHP\Exception\BadParameterException; +use MathPHP\Exception\IncorrectTypeException; use MathPHP\LinearAlgebra\MatrixFactory; use MathPHP\Statistics\RandomVariable; use MathPHP\Functions\Map\Single; @@ -17,7 +20,7 @@ trait LeastSquares * Regression ys * Since the actual xs may be translated for regression, we need to keep these * handy for regression statistics. - * @var array + * @var array */ private $reg_ys; @@ -25,14 +28,14 @@ trait LeastSquares * Regression xs * Since the actual xs may be translated for regression, we need to keep these * handy for regression statistics. - * @var array + * @var array */ private $reg_xs; /** * Regression Yhat * The Yhat for the regression xs. - * @var array + * @var array */ private $reg_Yhat; @@ -92,8 +95,8 @@ trait LeastSquares * _ __ * (x)² - x² * - * @param array $ys y values - * @param array $xs x values + * @param array $ys y values + * @param array $xs x values * @param int $order The order of the polynomial. 1 = linear, 2 = x², etc * @param int $fit_constant '1' if we are fitting a constant to the regression. * @@ -115,6 +118,7 @@ public function leastSquares(array $ys, array $xs, int $order = 1, int $fit_cons // y = Xa $X = $this->createDesignMatrix($xs); + /** @var NumericMatrix $y */ $y = MatrixFactory::createFromColumnVector($ys); // a = (XᵀX)⁻¹Xᵀy @@ -149,6 +153,7 @@ public function createDesignMatrix($xs): NumericMatrix $xs = [$xs]; } + /** @var array $xs */ $X = MatrixFactory::vandermonde($xs, $this->p + 1); if ($this->fit_constant == 0) { $X = $X->columnExclude(0); @@ -183,7 +188,7 @@ public function getProjectionMatrix(): NumericMatrix * which is the i-th diagonal element of the project matrix H, * where H = X⟮XᵀX⟯⁻¹Xᵀ where X is the design matrix. * - * @return array + * @return array */ public function leverages(): array { @@ -370,7 +375,7 @@ public function degreesOfFreedom(): float * se(b) = / ---- * √ n * - * @return array [m => se(m), b => se(b)] + * @return array{m: float, b: float} [m => se(m), b => se(b)] * * @throws Exception\BadParameterException * @throws Exception\IncorrectTypeException @@ -414,7 +419,9 @@ public function regressionVariance(float $x): float * or in matrix form * e = (I - H)y * - * @return array + * @return array + * + * @throws BadDataException */ public function residuals(): array { @@ -436,7 +443,9 @@ public function residuals(): array * where s ≡ (n - p)⁻¹eᵀ (mean square residuals) * e is the mean square error of the residual model * - * @return array + * @return array + * + * @throws BadDataException */ public function cooksD(): array { @@ -497,7 +506,9 @@ function ($eᵢ, $hᵢ) use ($mse, $p) { * DFFITS = s₍ᵢ₎ / ------ * √ 1 - hᵢ * - * @return array + * @return array + * + * @throws BadDataException */ public function dffits(): array { @@ -549,6 +560,8 @@ function ($s₍ᵢ₎, $hᵢ) { * √[(n∑x² − ⟮∑x⟯²)(n∑y² − ⟮∑y⟯²)] * * @return float + * + * @throws BadDataException */ public function correlationCoefficient(): float { @@ -560,6 +573,8 @@ public function correlationCoefficient(): float * Convenience wrapper for correlationCoefficient * * @return float + * + * @throws BadDataException */ public function r(): float { @@ -575,6 +590,8 @@ public function r(): float * https://en.wikipedia.org/wiki/Coefficient_of_determination * * @return float + * + * @throws BadDataException */ public function coefficientOfDetermination(): float { @@ -586,6 +603,8 @@ public function coefficientOfDetermination(): float * Convenience wrapper for coefficientOfDetermination * * @return float + * + * @throws BadDataException */ public function r2(): float { @@ -603,7 +622,10 @@ public function r2(): float * β = regression parameter (coefficient) * se(β) = standard error of the regression parameter (coefficient) * - * @return array [m => t, b => t] + * @return array{m: float, b: float} [m => t, b => t] + * + * @throws BadParameterException + * @throws IncorrectTypeException */ public function tValues(): array { @@ -628,7 +650,10 @@ public function tValues(): array * * alpha = 1 if the regression includes a constant term * - * @return array [m => p, b => p] + * @return array{m: float, b: float} [m => p, b => p] + * + * @throws BadParameterException + * @throws IncorrectTypeException */ public function tProbability(): array { @@ -659,6 +684,8 @@ public function tProbability(): array * SSₑ = sum of squares of residuals * * @return float + * + * @throws BadDataException */ public function fStatistic(): float { @@ -679,6 +706,8 @@ public function fStatistic(): float * ν = degrees of freedom * * @return float + * + * @throws BadDataException */ public function fProbability(): float { diff --git a/src/Statistics/Regression/Methods/WeightedLeastSquares.php b/src/Statistics/Regression/Methods/WeightedLeastSquares.php index 98147816c..4c0c01828 100644 --- a/src/Statistics/Regression/Methods/WeightedLeastSquares.php +++ b/src/Statistics/Regression/Methods/WeightedLeastSquares.php @@ -44,9 +44,9 @@ trait WeightedLeastSquares * _ __ * (x)² - x² * - * @param array $ys y values - * @param array $xs x values - * @param array $ws weight values + * @param array $ys y values + * @param array $xs x values + * @param array $ws weight values * @param int $order * * @return NumericMatrix [[m], [b]] @@ -57,11 +57,13 @@ public function leastSquares(array $ys, array $xs, array $ws, int $order = 1): N { // y = Xa $X = MatrixFactory::vandermonde($xs, $order + 1); + /** @var NumericMatrix $y */ $y = MatrixFactory::createFromColumnVector($ys); $W = MatrixFactory::diagonal($ws); // a = (XᵀWX)⁻¹XᵀWy $Xᵀ = $X->transpose(); + // @phpstan-ignore-next-line (Call to an undefined method MathPHP\LinearAlgebra\Matrix::multiply()) $beta_hat = $Xᵀ->multiply($W) ->multiply($X) ->inverse() diff --git a/src/Statistics/Regression/Models/LinearModel.php b/src/Statistics/Regression/Models/LinearModel.php index 47d71b131..036b2c554 100644 --- a/src/Statistics/Regression/Models/LinearModel.php +++ b/src/Statistics/Regression/Models/LinearModel.php @@ -15,7 +15,7 @@ trait LinearModel * y = mx + b * * @param float $x - * @param array $params + * @param array $params * * @return float y evaluated */ @@ -31,9 +31,9 @@ public static function evaluateModel(float $x, array $params): float * m = slope * b = y intercept * - * @param array $params + * @param array $params * - * @return array [ m => number, b => number ] + * @return array{m: float, b: float} [ m => number, b => number ] */ public function getModelParameters(array $params): array { @@ -46,7 +46,7 @@ public function getModelParameters(array $params): array /** * Get regression equation (y = mx + b) * - * @param array $params + * @param array $params * * @return string */ diff --git a/src/Statistics/Regression/Models/MichaelisMenten.php b/src/Statistics/Regression/Models/MichaelisMenten.php index 57e755d8d..b1b656cca 100644 --- a/src/Statistics/Regression/Models/MichaelisMenten.php +++ b/src/Statistics/Regression/Models/MichaelisMenten.php @@ -24,7 +24,7 @@ trait MichaelisMenten * y = (V * X) / (K + X) * * @param float $x - * @param array $params + * @param array $params * * @return float y evaluated */ @@ -39,9 +39,9 @@ public static function evaluateModel(float $x, array $params): float /** * Get regression parameters (V and K) * - * @param array $params + * @param array $params * - * @return array [ V => number, K => number ] + * @return array{V: float, K: float} [ V => number, K => number ] */ public function getModelParameters(array $params): array { @@ -54,7 +54,7 @@ public function getModelParameters(array $params): array /** * Get regression equation (y = V * X / (K + X)) * - * @param array $params + * @param array $params * * @return string */ diff --git a/src/Statistics/Regression/Models/PowerModel.php b/src/Statistics/Regression/Models/PowerModel.php index 5303455a7..ba3d543cd 100644 --- a/src/Statistics/Regression/Models/PowerModel.php +++ b/src/Statistics/Regression/Models/PowerModel.php @@ -15,7 +15,7 @@ trait PowerModel * y = axᵇ * * @param float $x - * @param array $params + * @param array $params * * @return float y evaluated */ @@ -30,9 +30,12 @@ public static function evaluateModel(float $x, array $params): float /** * Get regression parameters (a and b) * - * @param array $params + * @param array $params * - * @return array [ a => number, b => number ] + * @return array{ + * a: float, + * b: float, + * } */ public function getModelParameters(array $params): array { @@ -45,7 +48,7 @@ public function getModelParameters(array $params): array /** * Get regression equation (y = axᵇ) in format y = ax^b * - * @param array $params + * @param array $params * * @return string */ diff --git a/src/Statistics/Regression/ParametricRegression.php b/src/Statistics/Regression/ParametricRegression.php index 2fa0aec62..23c5d8bb8 100644 --- a/src/Statistics/Regression/ParametricRegression.php +++ b/src/Statistics/Regression/ParametricRegression.php @@ -6,6 +6,7 @@ abstract class ParametricRegression extends Regression { /** * An array of model parameters + * @var array */ protected $parameters; @@ -13,7 +14,7 @@ abstract class ParametricRegression extends Regression * Have the parent separate the points into xs and ys. * Calculate the regression parameters * - * @param float[][] $points + * @param array $points */ public function __construct(array $points) { @@ -46,14 +47,24 @@ public function getEquation(): string * Get the parameters * Uses the model's getModelParameters method. * - * @return array + * @return array */ public function getParameters(): array { return $this->getModelParameters($this->parameters); } + /** + * @param array $parameters + * + * @return string + */ abstract public function getModelEquation(array $parameters): string; + /** + * @param array $parameters + * + * @return array + */ abstract public function getModelParameters(array $parameters): array; } diff --git a/src/Statistics/Regression/Regression.php b/src/Statistics/Regression/Regression.php index 23d28bff7..3f449fe69 100644 --- a/src/Statistics/Regression/Regression.php +++ b/src/Statistics/Regression/Regression.php @@ -9,19 +9,19 @@ abstract class Regression { /** * Array of x and y points: [ [x, y], [x, y], ... ] - * @var array + * @var array */ protected $points; /** * X values of the original points - * @var array + * @var array */ protected $xs; /** * Y values of the original points - * @var array + * @var array */ protected $ys; @@ -34,7 +34,7 @@ abstract class Regression /** * Constructor - Prepares the data arrays for regression analysis * - * @param array $points [ [x, y], [x, y], ... ] + * @param array $points [ [x, y], [x, y], ... ] */ public function __construct(array $points) { @@ -64,7 +64,7 @@ abstract public function evaluate(float $x): float; /** * Get points * - * @return array + * @return array */ public function getPoints(): array { @@ -74,7 +74,7 @@ public function getPoints(): array /** * Get Xs (x values of each point) * - * @return array of x values + * @return array of x values */ public function getXs(): array { @@ -84,7 +84,7 @@ public function getXs(): array /** * Get Ys (y values of each point) * - * @return array of y values + * @return array of y values */ public function getYs(): array { @@ -105,7 +105,7 @@ public function getSampleSize(): int * Ŷ (yhat) * A list of the predicted values of Y given the regression. * - * @return array + * @return array */ public function yHat(): array { diff --git a/src/Statistics/Regression/WeightedLinear.php b/src/Statistics/Regression/WeightedLinear.php index 72c62d435..1c54827b4 100644 --- a/src/Statistics/Regression/WeightedLinear.php +++ b/src/Statistics/Regression/WeightedLinear.php @@ -24,13 +24,13 @@ class WeightedLinear extends ParametricRegression /** * Array of weights - * @var array + * @var array */ private $ws; /** - * @param array $points - * @param array $ws Weights + * @param array $points + * @param array $ws Weights */ public function __construct(array $points, array $ws) { diff --git a/src/Statistics/Significance.php b/src/Statistics/Significance.php index a5360371e..f91899df6 100644 --- a/src/Statistics/Significance.php +++ b/src/Statistics/Significance.php @@ -30,7 +30,11 @@ class Significance * @param float $H₀ Null hypothesis (μ Population mean) * @param float $σ SD of population (Standard error of the mean) * - * @return array [ + * @return array{ + * z: float, + * p1: float, + * p2: float, + * } [ * z => z score * p1 => one-tailed p value (left or right tail depends on how Hₐ differs from H₀) * p2 => two-tailed p value @@ -59,7 +63,11 @@ public static function zTest(float $Hₐ, int $n, float $H₀, float $σ): array * @param float $H₀ Null hypothesis (μ Population mean) * @param float $σ SD of population (Standard error of the mean) * - * @return array [ + * @return array{ + * z: float, + * p1: float, + * p2: float, + * } [ * z => z score * p1 => one-tailed p value (left or right tail depends on how Hₐ differs from H₀) * p2 => two-tailed p value @@ -123,7 +131,11 @@ public static function zTestOneSample(float $Hₐ, int $n, float $H₀, float $ * @param float $σ₂ Standard deviation of sample mean 2 * @param float $Δ (Optional) hypothesized difference between the population means (0 if testing for equal means) * - * @return array [ + * @return array{ + * z: float, + * p1: float, + * p2: float, + * } [ * z => z score * p1 => one-tailed p value * p2 => two-tailed p value @@ -174,10 +186,26 @@ public static function zScore(float $M, float $μ, float $σ, bool $table_value * t-test - one sample or two sample tests * https://en.wikipedia.org/wiki/Student%27s_t-test * - * @param array $a sample set 1 - * @param float|array $b population mean for one sample t test; sample set 2 for two sample t-test - * - * @return array + * @param array $a sample set 1 + * @param float|array $b population mean for one sample t test; sample set 2 for two sample t-test + * + * @return array{ + * t: float, + * df: float, + * p1: float, + * p2: float, + * mean: float, + * sd: float, + * }|array{ + * t: float, + * df: float, + * p1: float, + * p2: float, + * mean1: float, + * mean2: float, + * sd1: float, + * sd2: float, + * } * * @throws Exception\BadParameterException * @throws Exception\OutOfBoundsException @@ -191,6 +219,7 @@ public static function tTest(array $a, $b): array return self::tTestTwoSample($a, $b); } + // @phpstan-ignore-next-line (Unreachable statement - code above always terminates.) throw new Exception\BadParameterException('Second parameter must be numeric for one-sample t-test, or an array for two-sample t-test'); } @@ -207,10 +236,17 @@ public static function tTest(array $a, $b): array * = CDF above if right tailed * p2 = CDF outside * - * @param array $a Sample set + * @param array $a Sample set * @param float $H₀ Null hypothesis (μ₀ Population mean) * - * @return array [ + * @return array{ + * t: float, + * df: float, + * p1: float, + * p2: float, + * mean: float, + * sd: float, + * } [ * t => t score * df => degrees of freedom * p1 => one-tailed p value (left or right tail depends on how Hₐ differs from H₀) @@ -248,7 +284,14 @@ public static function tTestOneSample(array $a, float $H₀): array * @param int $n Sample size * @param float $H₀ Null hypothesis (μ₀ Population mean) * - * @return array [ + * @return array{ + * t: float, + * df: int, + * p1: float, + * p2: float, + * mean: float, + * sd: float, + * } [ * t => t score * df => degrees of freedom * p1 => one-tailed p value (left or right tail depends on how Hₐ differs from H₀) @@ -318,10 +361,19 @@ public static function tTestOneSampleFromSummaryData(float $Hₐ, float $s, int * p1 = CDF above * p2 = CDF outside * - * @param array $x₁ sample set 1 - * @param array $x₂ sample set 2 - * - * @return array [ + * @param array $x₁ sample set 1 + * @param array $x₂ sample set 2 + * + * @return array{ + * t: float, + * df: float, + * p1: float, + * p2: float, + * mean1: float, + * mean2: float, + * sd1: float, + * sd2: float, + * } [ * t => t score * df => degrees of freedom * p1 => one-tailed p value @@ -389,7 +441,16 @@ public static function tTestTwoSample(array $x₁, array $x₂): array * @param float $σ₁ Standard deviation of sample mean 1 * @param float $σ₂ Standard deviation of sample mean 2 * - * @return array [ + * @return array{ + * t: float, + * df: float, + * p1: float, + * p2: float, + * mean1: float, + * mean2: float, + * sd1: float, + * sd2: float, + * } [ * t => t score * df => degrees of freedom * p1 => one-tailed p value @@ -463,10 +524,13 @@ public static function tScore(float $Hₐ, float $s, int $n, float $H₀): float * * p = χ² distribution CDF(χ², k) * - * @param array $observed - * @param array $expected + * @param array $observed + * @param array $expected * - * @return array [chi-square, p] + * @return array{ + * "chi-square": float, + * "p": float, + * } [chi-square, p] * * @throws Exception\BadDataException if count of observed does not equal count of expected */ diff --git a/src/Trigonometry.php b/src/Trigonometry.php index 53bb6cf9a..9ee25f503 100644 --- a/src/Trigonometry.php +++ b/src/Trigonometry.php @@ -16,7 +16,7 @@ class Trigonometry * * @param int $points number of points * - * @return array + * @return array */ public static function unitCircle(int $points = 11): array { diff --git a/src/Util/Iter.php b/src/Util/Iter.php index 1ccba22a9..e83aae616 100644 --- a/src/Util/Iter.php +++ b/src/Util/Iter.php @@ -2,8 +2,6 @@ namespace MathPHP\Util; -use MathPHP\Exception; - /** * @internal */ @@ -14,7 +12,7 @@ class Iter * Similar to Python's zip function * @internal * - * @param iterable ...$iterables + * @param iterable ...$iterables * * @return \MultipleIterator */ @@ -29,7 +27,7 @@ public static function zip(iterable ...$iterables): \MultipleIterator } /** - * @param iterable $iterable + * @param iterable $iterable * * @return \Iterator|\IteratorIterator|\ArrayIterator */ From 309c628a3c5a15d5ad6dea8cacfc4efd738561dd Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 20:15:39 -0700 Subject: [PATCH 35/66] Fix sample data column indexes. --- src/SampleData/PlantGrowth.php | 6 +----- src/SampleData/ToothGrowth.php | 11 ++--------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/SampleData/PlantGrowth.php b/src/SampleData/PlantGrowth.php index 5de17504f..c449e10eb 100644 --- a/src/SampleData/PlantGrowth.php +++ b/src/SampleData/PlantGrowth.php @@ -95,10 +95,6 @@ public function getWeight(): array */ public function getGroup(): array { - /** - * FIXME: looks like a mistake: column_key = 0 instead of 1? - * @phpstan-ignore-next-line - */ - return \array_column(self::DATA, 0); + return \array_column(self::DATA, 1); } } diff --git a/src/SampleData/ToothGrowth.php b/src/SampleData/ToothGrowth.php index 6243970cf..d786630b5 100644 --- a/src/SampleData/ToothGrowth.php +++ b/src/SampleData/ToothGrowth.php @@ -125,11 +125,7 @@ public function getLen(): array */ public function getSupp(): array { - /** - * FIXME: looks like a mistake: column_key = 0 instead of 1? - * @phpstan-ignore-next-line - */ - return \array_column(self::DATA, 0); + return \array_column(self::DATA, 1); } /** @@ -139,9 +135,6 @@ public function getSupp(): array */ public function getDose(): array { - /** - * FIXME: looks like a mistake: column_key = 0 instead of 2? - */ - return \array_column(self::DATA, 0); + return \array_column(self::DATA, 2); } } From d3e98454efdcd10e9a0676987647bb9a19606b2b Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 20:50:23 -0700 Subject: [PATCH 36/66] Clean up Search. --- src/Search.php | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/Search.php b/src/Search.php index 2fe3aba6d..6235bd8c4 100644 --- a/src/Search.php +++ b/src/Search.php @@ -76,9 +76,7 @@ function ($value) { } // Standard case: Find max and return index - /** @var int $result */ - $result = self::baseArgMax($values); - return $result; + return self::baseArgMax($values); } /** @@ -112,9 +110,7 @@ function ($value) { throw new Exception\BadDataException('Array of all NANs has no nanArgMax'); } - /** @var int $result */ - $result = self::baseArgMax($valuesWithoutNans); - return $result; + return self::baseArgMax($valuesWithoutNans); } /** @@ -125,9 +121,11 @@ function ($value) { * * @param float[]|int[] $values * - * @return int|null Index of the first occurrence of the maximum value + * @return int Index of the first occurrence of the maximum value + * + * @throws \LogicException if the array of values is empty - should never happen */ - private static function baseArgMax(array $values): ?int + private static function baseArgMax(array $values): int { $max = \max($values); foreach ($values as $i => $v) { @@ -136,7 +134,7 @@ private static function baseArgMax(array $values): ?int } } - return null; + throw new \LogicException('argMax values is empty--should not happen'); } /** @@ -176,10 +174,7 @@ function ($value) { } // Standard case: Find max and return index - - /** @var int $result */ - $result = self::baseArgMin($values); - return $result; + return self::baseArgMin($values); } /** @@ -213,9 +208,7 @@ function ($value) { throw new Exception\BadDataException('Array of all NANs has no nanArgMax'); } - /** @var int $result */ - $result = self::baseArgMin($valuesWithoutNans); - return $result; + return self::baseArgMin($valuesWithoutNans); } /** @@ -226,9 +219,11 @@ function ($value) { * * @param float[]|int[] $values * - * @return int|null Index of the first occurrence of the minimum value + * @return int Index of the first occurrence of the minimum value + * + * @throws \LogicException if the array of values is empty - should never happen */ - private static function baseArgMin(array $values): ?int + private static function baseArgMin(array $values): int { $max = \min($values); foreach ($values as $i => $v) { @@ -237,7 +232,7 @@ private static function baseArgMin(array $values): ?int } } - return null; + throw new \LogicException('argMin values is empty--should not happen'); } /** From 18b87238c2be706b0af5562e3503141da98e2ce5 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 20:52:53 -0700 Subject: [PATCH 37/66] Clean up Advanced. --- src/Sequence/Advanced.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Sequence/Advanced.php b/src/Sequence/Advanced.php index 5cfcbe3ed..fc08ca4bd 100644 --- a/src/Sequence/Advanced.php +++ b/src/Sequence/Advanced.php @@ -448,11 +448,6 @@ public static function magicSquares(int $n): array return $M; } - /** - * FIXME: big numbers are float, so accuracy is lost. - * php > var_dump(191561942608236107294793378084303638130997321548169216); - * float(1.9156194260824E+53) - */ private const PERFECT_NUMBERS = [ 6, 28, 496, 8128, 33550336, 8589869056, 137438691328, 2305843008139952128, 2658455991569831744654692615953842176, 191561942608236107294793378084303638130997321548169216 ]; @@ -468,7 +463,7 @@ public static function magicSquares(int $n): array * * @param int $n * - * @return array + * @return array May return float due to integer precision limitations of large numbers * * @throws OutOfBoundsException */ @@ -479,10 +474,6 @@ public static function perfectNumbers(int $n): array } if ($n <= 10) { - /** - * @phpstan-ignore-next-line - * FIXME: Advanced::perfectNumbers() should return array but returns array. - */ return \array_slice(self::PERFECT_NUMBERS, 0, $n); } From b183ba099167ab94795f5749636f42d5a5b489fb Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 20:54:31 -0700 Subject: [PATCH 38/66] Clean up WLS. --- src/Statistics/Regression/Methods/WeightedLeastSquares.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Statistics/Regression/Methods/WeightedLeastSquares.php b/src/Statistics/Regression/Methods/WeightedLeastSquares.php index 4c0c01828..7d4b7bb63 100644 --- a/src/Statistics/Regression/Methods/WeightedLeastSquares.php +++ b/src/Statistics/Regression/Methods/WeightedLeastSquares.php @@ -62,8 +62,8 @@ public function leastSquares(array $ys, array $xs, array $ws, int $order = 1): N $W = MatrixFactory::diagonal($ws); // a = (XᵀWX)⁻¹XᵀWy + /** @var NumericMatrix $Xᵀ */ $Xᵀ = $X->transpose(); - // @phpstan-ignore-next-line (Call to an undefined method MathPHP\LinearAlgebra\Matrix::multiply()) $beta_hat = $Xᵀ->multiply($W) ->multiply($X) ->inverse() From e7e6927328d4e41919342d30d39c8bf0595e741f Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 21:46:02 -0700 Subject: [PATCH 39/66] Minor changes to PLS. --- src/Statistics/Multivariate/PLS.php | 36 +++++++++++++++-------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Statistics/Multivariate/PLS.php b/src/Statistics/Multivariate/PLS.php index e0b44fb26..a98b3c2f6 100644 --- a/src/Statistics/Multivariate/PLS.php +++ b/src/Statistics/Multivariate/PLS.php @@ -4,14 +4,9 @@ use MathPHP\Exception; use MathPHP\Exception\BadDataException; -use MathPHP\Exception\IncorrectTypeException; -use MathPHP\Exception\MathException; -use MathPHP\Exception\MatrixException; -use MathPHP\Exception\OutOfBoundsException; use MathPHP\LinearAlgebra\Matrix; use MathPHP\LinearAlgebra\MatrixFactory; use MathPHP\LinearAlgebra\NumericMatrix; -use MathPHP\LinearAlgebra\ObjectMatrix; use MathPHP\LinearAlgebra\Vector; use MathPHP\Statistics\Descriptive; @@ -89,6 +84,12 @@ public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = fals $E = $this->standardizeData($X, $this->Xcenter, $this->Xscale); $F = $this->standardizeData($Y, $this->Ycenter, $this->Yscale); + $C = null; + $P = null; + $T = null; + $U = null; + $W = null; + $tol = 1E-8; for ($i = 0; $i < $ncomp; $i++) { $iterations = 0; @@ -100,7 +101,7 @@ public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = fals while (!$end) { ++$iterations; - // $w is a unit vector + /** @var NumericMatrix $w is a unit vector */ $w = $E->transpose()->multiply($u); $w = $w->scalarDivide($w->frobeniusNorm()); @@ -125,18 +126,19 @@ public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = fals $F = $F->subtract($t->multiply($c->transpose())->scalarMultiply($d)); // Add each of these columns to the overall matrices - // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) - $this->C = is_null($this->C) ? $c : $this->C->augment($c); - // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) - $this->P = is_null($this->P) ? $p : $this->P->augment($p); - // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) - $this->T = is_null($this->T) ? $t : $this->T->augment($t); - // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) - $this->U = is_null($this->U) ? $u : $this->U->augment($u); - // @phpstan-ignore-next-line (Call to function is_null() with MathPHP\LinearAlgebra\NumericMatrix will always evaluate to false.) - $this->W = is_null($this->W) ? $w : $this->W->augment($w); + $C = \is_null($C) ? $c : $C->augment($c); + $P = \is_null($P) ? $p : $P->augment($p); + $T = \is_null($T) ? $t : $T->augment($t); + $U = \is_null($U) ? $u : $U->augment($u); + $W = \is_null($W) ? $w : $W->augment($w); } + $this->C = $C; + $this->P = $P; + $this->T = $T; + $this->U = $U; + $this->W = $W; + // Calculate R (or W*) $R = $this->W->multiply($this->P->transpose()->multiply($this->W)->inverse()); $this->B = $R->multiply($this->C->transpose()); @@ -267,7 +269,7 @@ public function predict(Matrix $X): Matrix * * @throws Exception\MathException */ - private function standardizeData(Matrix $new_data, Vector $center, Vector $scale): Matrix + private function standardizeData(NumericMatrix $new_data, Vector $center, Vector $scale): NumericMatrix { // Create a matrix the same dimensions as $new_data, each element is the average of that column in the original data. $ones_column = MatrixFactory::one($new_data->getM(), 1); From 81bded08bccdb230da89c3d5b721299f7e710604 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 22:02:46 -0700 Subject: [PATCH 40/66] Minor improvements. --- src/LinearAlgebra/ObjectMatrix.php | 4 +--- src/LinearAlgebra/Vector.php | 6 +++--- src/Statistics/Multivariate/PLS.php | 8 +++----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/LinearAlgebra/ObjectMatrix.php b/src/LinearAlgebra/ObjectMatrix.php index 97da7eba1..749b844af 100644 --- a/src/LinearAlgebra/ObjectMatrix.php +++ b/src/LinearAlgebra/ObjectMatrix.php @@ -359,10 +359,8 @@ public function det() * @param int $nⱼ * * @return ObjectArithmetic - * - * FIXME: maybe add return type to the method definition? */ - public function cofactor(int $mᵢ, int $nⱼ) + public function cofactor(int $mᵢ, int $nⱼ): ObjectArithmetic { /** @var ObjectArithmetic $Mᵢⱼ */ $Mᵢⱼ = $this->minor($mᵢ, $nⱼ); diff --git a/src/LinearAlgebra/Vector.php b/src/LinearAlgebra/Vector.php index da1fc1854..9d62e89a6 100644 --- a/src/LinearAlgebra/Vector.php +++ b/src/LinearAlgebra/Vector.php @@ -172,7 +172,7 @@ public function length() * * @return number|false * - * FIXME: maybe null instead of false? + * Note: Remove false from return value after PHP 8.0 */ public function max() { @@ -184,7 +184,7 @@ public function max() * * @return number|false * - * FIXME: maybe null instead of false? + * Note: Remove false from return value after PHP 8.0 */ public function min() { @@ -716,7 +716,7 @@ public function pNorm($p) * * @return number|false * - * FIXME: maybe null instead of false? + * Note: Remove false from return value after PHP 8.0 */ public function maxNorm() { diff --git a/src/Statistics/Multivariate/PLS.php b/src/Statistics/Multivariate/PLS.php index a98b3c2f6..bdba38193 100644 --- a/src/Statistics/Multivariate/PLS.php +++ b/src/Statistics/Multivariate/PLS.php @@ -52,14 +52,12 @@ class PLS /** * @param NumericMatrix $X each row is a sample, each column is a variable * @param NumericMatrix $Y each row is a sample, each column is a variable - * @param int $ncomp number of components to use in the model - * @param bool $scale standardize each column? + * @param int $ncomp number of components to use in the model + * @param bool $scale standardize each column? * * @throws Exception\BadDataException if any rows have a different column count - * - * FIXME: cannot use Matrix, only NumericMatrix (because of using `columnMeans()` function). */ - public function __construct(Matrix $X, Matrix $Y, int $ncomp, bool $scale = false) + public function __construct(NumericMatrix $X, NumericMatrix $Y, int $ncomp, bool $scale = false) { // Check that X and Y have the same amount of data. if ($X->getM() !== $Y->getM()) { From b88555332223e6097742e83e7eb26c3f4f07578b Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 22:18:26 -0700 Subject: [PATCH 41/66] Minor comment change. --- src/Statistics/Multivariate/PLS.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Statistics/Multivariate/PLS.php b/src/Statistics/Multivariate/PLS.php index bdba38193..ce0a683ca 100644 --- a/src/Statistics/Multivariate/PLS.php +++ b/src/Statistics/Multivariate/PLS.php @@ -131,10 +131,15 @@ public function __construct(NumericMatrix $X, NumericMatrix $Y, int $ncomp, bool $W = \is_null($W) ? $w : $W->augment($w); } + // @phpstan-ignore-next-line $this->C = $C; + // @phpstan-ignore-next-line $this->P = $P; + // @phpstan-ignore-next-line $this->T = $T; + // @phpstan-ignore-next-line $this->U = $U; + // @phpstan-ignore-next-line $this->W = $W; // Calculate R (or W*) From 4ce709268f6d4de59874bc6420643ebbf211b1e4 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 25 Apr 2023 22:32:40 -0700 Subject: [PATCH 42/66] Minor change. --- src/Statistics/Multivariate/PLS.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Statistics/Multivariate/PLS.php b/src/Statistics/Multivariate/PLS.php index ce0a683ca..546c76aa3 100644 --- a/src/Statistics/Multivariate/PLS.php +++ b/src/Statistics/Multivariate/PLS.php @@ -142,7 +142,7 @@ public function __construct(NumericMatrix $X, NumericMatrix $Y, int $ncomp, bool // @phpstan-ignore-next-line $this->W = $W; - // Calculate R (or W*) + // Calculate R (or W*) @phpstan-ignore-next-line $R = $this->W->multiply($this->P->transpose()->multiply($this->W)->inverse()); $this->B = $R->multiply($this->C->transpose()); } From 48ca4bd6bb9a3e6c07dbc4d34e1babb082e2cf06 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 2 May 2023 06:57:20 -0700 Subject: [PATCH 43/66] Minor static analysis comment. --- src/Statistics/Multivariate/PLS.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Statistics/Multivariate/PLS.php b/src/Statistics/Multivariate/PLS.php index 546c76aa3..a447c61e2 100644 --- a/src/Statistics/Multivariate/PLS.php +++ b/src/Statistics/Multivariate/PLS.php @@ -144,6 +144,7 @@ public function __construct(NumericMatrix $X, NumericMatrix $Y, int $ncomp, bool // Calculate R (or W*) @phpstan-ignore-next-line $R = $this->W->multiply($this->P->transpose()->multiply($this->W)->inverse()); + // @phpstan-ignore-next-line $this->B = $R->multiply($this->C->transpose()); } From 460377d00ea58f6e4660e70d07829aba542e1e80 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:23:07 -0700 Subject: [PATCH 44/66] Update CHANGELOG for v2.8.0. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c0e89e65..65a3334d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Improvements * Better error handling and exception message in `Sequence\NonIntenger::hyperharmonic` +* Internal code improvements to conform to static analysis checks ### Improvements From fc5e16aee7bff63aa65a6db53cf535d410dbf0ba Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:28:40 -0700 Subject: [PATCH 45/66] Rename methods to better indicate assertion and no return value. --- CHANGELOG.md | 5 ++++- .../NumericalDifferentiation/FivePointFormula.php | 4 ++-- .../NumericalDifferentiation/NumericalDifferentiation.php | 8 ++------ .../SecondDerivativeMidpointFormula.php | 2 +- .../NumericalDifferentiation/ThreePointFormula.php | 4 ++-- .../NumericalDifferentiationTest.php | 4 ++-- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65a3334d8..2bab9420d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,10 @@ * Better error handling and exception message in `Sequence\NonIntenger::hyperharmonic` * Internal code improvements to conform to static analysis checks -### Improvements +### Backwards Incompatible Changes +* Helper method names changed (public abstract methods but not part of published interface) + * `NumericalDifferentiation::isTargetInPoints` changed to `assertTargetInPoints` + * `NumericalDifferentiation::isSpacingConstant` changed to `assertSpacingConstant` ## v2.7.0 - 2022-12-31 diff --git a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php index 9cc214af0..3b99c027a 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php @@ -80,8 +80,8 @@ public static function differentiate(float $target, $source, ...$args): float // sure our target is contained in an interval supplied by our $source self::validate($points, $degree = 5); $sorted = self::sort($points); - self::isSpacingConstant($sorted); - self::isTargetInPoints($target, $sorted); + self::assertSpacingConstant($sorted); + self::assertTargetInPoints($target, $sorted); // Descriptive constants $x = self::X; diff --git a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php index 172157bef..46d45dd89 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php @@ -157,10 +157,8 @@ protected static function sort(array $points): array * * @throws Exception\BadDataException if the spacing between any two points is not equal * to the average spacing between every point - * - * FIXME: maybe rename to checkIsSpacingConstant? */ - public static function isSpacingConstant(array $sorted): void + public static function assertSpacingConstant(array $sorted): void { $x = self::X; $length = \count($sorted); @@ -180,10 +178,8 @@ public static function isSpacingConstant(array $sorted): void * @param array $sorted Points sorted by (increasing) x-component * * @throws Exception\BadDataException if $target is not contained in the array of our x-components - * - * FIXME: maybe rename to checkIsTargetInPoints? */ - public static function isTargetInPoints($target, array $sorted): void + public static function assertTargetInPoints($target, array $sorted): void { $xComponents = \array_map( function (array $point) { diff --git a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php index af150142d..8e31c2c8f 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php @@ -69,7 +69,7 @@ public static function differentiate(float $target, $source, ...$args) // sure our target is contained in an interval supplied by our $source self::validate($points, $degree = 3); $sorted = self::sort($points); - self::isSpacingConstant($sorted); + self::assertSpacingConstant($sorted); // Descriptive constants $x = self::X; diff --git a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php index e36213358..f0a53a03a 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php @@ -80,8 +80,8 @@ public static function differentiate(float $target, $source, ...$args): float // sure our target is contained in an interval supplied by our $source self::validate($points, $degree = 3); $sorted = self::sort($points); - self::isSpacingConstant($sorted); - self::isTargetInPoints($target, $sorted); + self::assertSpacingConstant($sorted); + self::assertTargetInPoints($target, $sorted); // Descriptive constants $x = self::X; diff --git a/tests/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiationTest.php b/tests/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiationTest.php index e54fabcc6..27851fd3d 100644 --- a/tests/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiationTest.php +++ b/tests/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiationTest.php @@ -88,7 +88,7 @@ public function testSpacingNonConstant() $this->expectException(Exception\BadDataException::class); // When - NumericalDifferentiation::isSpacingConstant($sortedPoints); + NumericalDifferentiation::assertSpacingConstant($sortedPoints); } /** @@ -105,6 +105,6 @@ public function testTargetNotInPoints() $this->expectException(Exception\BadDataException::class); // When - NumericalDifferentiation::isTargetInPoints($target, $sortedPoints); + NumericalDifferentiation::assertTargetInPoints($target, $sortedPoints); } } From b3872ef1330361a52425cffcca1546dff83a9aed Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:29:59 -0700 Subject: [PATCH 46/66] Minor comment change. --- src/SetTheory/Set.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/SetTheory/Set.php b/src/SetTheory/Set.php index 5ad97011b..735f3ae45 100644 --- a/src/SetTheory/Set.php +++ b/src/SetTheory/Set.php @@ -150,10 +150,7 @@ public function isEmpty(): bool */ public function isMember($x): bool { - /** - * FIXME: $this->getKey() may return null, int|string required. - * @phpstan-ignore-next-line - */ + // @phpstan-ignore-next-line ($this->getKey() may return null, int|string required) return \array_key_exists($this->getKey($x), $this->A); } @@ -167,10 +164,7 @@ public function isMember($x): bool */ public function isNotMember($x): bool { - /** - * FIXME: $this->getKey() may return null, int|string required. - * @phpstan-ignore-next-line - */ + // @phpstan-ignore-next-line ($this->getKey() may return null, int|string required) return !\array_key_exists($this->getKey($x), $this->A); } From 64bc11a5375f31d90cbb36a4b22207ac4b03fdfc Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:30:54 -0700 Subject: [PATCH 47/66] Minor comment change. --- src/Algebra.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Algebra.php b/src/Algebra.php index 6da542a37..b89777b8d 100644 --- a/src/Algebra.php +++ b/src/Algebra.php @@ -531,10 +531,7 @@ public static function quartic(float $a₄, float $a₃, float $a₂, float $a // The roots for this polynomial are the roots of the depressed polynomial minus a₃/4. if (!$return_complex) { - /** - * FIXME: are the roots real? Single::subtract() works with real numbers only. - * @phpstan-ignore-next-line - */ + // @phpstan-ignore-next-line (Single::subtract() works with real numbers only, must be real roots) return Single::subtract($depressed_quartic_roots, $a₃ / 4); } From 3c13e5a51fd982796e51ffc5c3519ecc1e19c42b Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:34:47 -0700 Subject: [PATCH 48/66] Minor comment change. --- src/LinearAlgebra/Matrix.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/LinearAlgebra/Matrix.php b/src/LinearAlgebra/Matrix.php index 085d6dadb..140694a28 100644 --- a/src/LinearAlgebra/Matrix.php +++ b/src/LinearAlgebra/Matrix.php @@ -221,10 +221,7 @@ public function asVectors(): array $vectors = []; for ($j = 0; $j < $n; $j++) { - /** - * FIXME: maybe define vector as a generic class of T type? - * @phpstan-ignore-next-line - */ + // @phpstan-ignore-next-line (Vector expects numbers, Matrix may be generic T) $vectors[] = new Vector(\array_column($this->A, $j)); } @@ -249,10 +246,7 @@ public function asRowVectors(): array { return \array_map( function (array $row) { - /** - * FIXME: maybe define vector as a generic class of T type? - * @phpstan-ignore-next-line - */ + // @phpstan-ignore-next-line (Vector expects numbers, Matrix may be generic T) return new Vector($row); }, $this->A From 6fb5024851f71d0a32c5941688c41d4cd56f9597 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:35:16 -0700 Subject: [PATCH 49/66] Update CHANGELOG for v2.8.0. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bab9420d..ebabe823e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # MathPHP Change Log -## v2.8.0 - TBD +## v2.8.0 - 2023-05-07 ### New Features * Matrix `rowAddVector` From de15ba5c7ce8a1cf2a78505991520aefa04253f3 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:43:48 -0700 Subject: [PATCH 50/66] Github actions improvements for static analysis. --- .github/workflows/test_develop_and_master.yml | 4 +++- .github/workflows/test_other_branches.yml | 4 +++- .github/workflows/test_pull_request.yml | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index f9a5a0451..07940bc4b 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -57,7 +57,9 @@ jobs: run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . - name: Static analysis - run: ./vendor/bin/phpstan analyze --level max src/ + run: | + ./vendor/bin/phpstan --version + ./vendor/bin/phpstan analyze --level max src/ code-coverage: name: Code coverage diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index c198d4f28..855495f06 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -56,4 +56,6 @@ jobs: run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . - name: Static analysis - run: ./vendor/bin/phpstan analyze --level max src/ + run: | + ./vendor/bin/phpstan --version + ./vendor/bin/phpstan analyze --level max src/ diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index bff052c4b..3e0c3eabb 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -53,7 +53,9 @@ jobs: run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . - name: Static analysis - run: ./vendor/bin/phpstan analyze --level max src/ + run: | + ./vendor/bin/phpstan --version + ./vendor/bin/phpstan analyze --level max src/ code-coverage: name: Code coverage From 70d0111a0930338a60eed9cad23cf587a4806380 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 7 May 2023 10:45:19 -0700 Subject: [PATCH 51/66] Github actions changes for static analysis. --- .github/workflows/test_develop_and_master.yml | 4 +++- .github/workflows/test_other_branches.yml | 4 +++- .github/workflows/test_pull_request.yml | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index 07940bc4b..f55d04032 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -54,7 +54,9 @@ jobs: ./vendor/bin/phpunit --configuration tests/phpunit.xml --testsuite=LinearAlgebra - name: PHP Code Sniffer - run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + run: | + ./vendor/bin/phpcs --version + ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . - name: Static analysis run: | diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index 855495f06..347cd67ce 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -53,7 +53,9 @@ jobs: ./vendor/bin/phpunit --configuration tests/phpunit.xml --testsuite=LinearAlgebra - name: PHP Code Sniffer - run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + run: | + ./vendor/bin/phpcs --version + ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . - name: Static analysis run: | diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index 3e0c3eabb..56dc25250 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -50,7 +50,9 @@ jobs: ./vendor/bin/phpunit --configuration tests/phpunit.xml --testsuite=LinearAlgebra - name: PHP Code Sniffer - run: ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + run: | + ./vendor/bin/phpcs --version + ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . - name: Static analysis run: | From 341013a253e67862cbea89db973c62bdd957f87c Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Thu, 18 May 2023 21:38:31 -0700 Subject: [PATCH 52/66] Changes for static anlaysis improvements, and various other internal changes. --- .github/workflows/test_develop_and_master.yml | 40 ++++++++++++++++--- .github/workflows/test_other_branches.yml | 38 +++++++++++++++--- .github/workflows/test_pull_request.yml | 40 ++++++++++++++++--- Makefile | 2 +- README.md | 2 +- composer.json | 2 +- src/Algebra.php | 10 +++-- src/Expression/Piecewise.php | 1 - src/Expression/Polynomial.php | 8 ++-- src/Functions/Map/Multi.php | 22 +++++----- src/Functions/Map/Single.php | 28 ++++++------- src/Functions/Support.php | 2 +- src/InformationTheory/Entropy.php | 16 ++++---- src/LinearAlgebra/Decomposition/LU.php | 4 +- src/LinearAlgebra/Decomposition/QR.php | 4 +- src/LinearAlgebra/Decomposition/SVD.php | 14 +++---- src/LinearAlgebra/Eigenvalue.php | 4 +- src/LinearAlgebra/MatrixFactory.php | 33 +++++++++------ src/LinearAlgebra/NumericDiagonalMatrix.php | 2 +- src/LinearAlgebra/NumericMatrix.php | 31 +++++++------- src/LinearAlgebra/NumericSquareMatrix.php | 2 +- src/LinearAlgebra/ObjectMatrix.php | 3 +- .../Reduction/ReducedRowEchelonForm.php | 2 +- .../Reduction/RowEchelonForm.php | 8 ++-- src/LinearAlgebra/Vector.php | 28 ++++++------- src/Number/Complex.php | 17 ++++---- src/Number/Quaternion.php | 35 ++++++++-------- .../Interpolation/ClampedCubicSpline.php | 20 +++++----- .../Interpolation/Interpolation.php | 4 +- .../Interpolation/LagrangePolynomial.php | 2 +- .../Interpolation/NaturalCubicSpline.php | 2 +- .../Interpolation/NevillesMethod.php | 2 +- .../Interpolation/NewtonPolynomialForward.php | 2 +- .../Interpolation/RegularGridInterpolator.php | 16 ++++---- .../FivePointFormula.php | 2 +- .../NumericalDifferentiation.php | 8 ++-- .../SecondDerivativeMidpointFormula.php | 2 +- .../ThreePointFormula.php | 2 +- .../NumericalIntegration/BoolesRule.php | 2 +- .../NumericalIntegration/MidpointRule.php | 2 +- .../NumericalIntegration.php | 14 +++---- .../NumericalIntegration/RectangleMethod.php | 2 +- .../NumericalIntegration/SimpsonsRule.php | 2 +- .../SimpsonsThreeEighthsRule.php | 2 +- .../NumericalIntegration/TrapezoidalRule.php | 2 +- .../NumericalIntegration/Validation.php | 2 +- .../RootFinding/BisectionMethod.php | 2 +- .../RootFinding/FixedPointIteration.php | 2 +- .../RootFinding/NewtonsMethod.php | 2 +- .../Distribution/Continuous/Beta.php | 4 +- .../Distribution/Continuous/Cauchy.php | 4 +- .../Distribution/Continuous/Continuous.php | 6 +-- .../Continuous/ContinuousDistribution.php | 4 +- .../Distribution/Continuous/Normal.php | 2 + .../Distribution/Discrete/Categorical.php | 6 +-- .../Distribution/Discrete/Zipf.php | 10 ++--- .../Multivariate/Hypergeometric.php | 6 +-- .../Distribution/Multivariate/Multinomial.php | 4 +- .../Distribution/Multivariate/Normal.php | 6 +-- .../Distribution/Table/ChiSquared.php | 1 - .../Distribution/Table/StandardNormal.php | 2 +- .../Distribution/Table/TDistribution.php | 10 ++--- src/SampleData/Cereal.php | 14 +++---- src/SampleData/Iris.php | 12 +++--- src/SampleData/MtCars.php | 34 ++++++++-------- src/SampleData/PlantGrowth.php | 6 +-- src/SampleData/ToothGrowth.php | 4 +- src/SampleData/UsArrests.php | 12 +++--- src/SetTheory/ImmutableSet.php | 4 +- src/SetTheory/Set.php | 2 +- src/Statistics/Average.php | 10 ++--- src/Statistics/Correlation.php | 6 +-- src/Statistics/Descriptive.php | 2 +- src/Statistics/Distance.php | 12 +++--- src/Statistics/Distribution.php | 8 ++-- src/Statistics/Divergence.php | 8 ++-- src/Statistics/Regression/LOESS.php | 2 +- .../Regression/Methods/LeastSquares.php | 2 +- src/Statistics/Significance.php | 1 - .../Matrix/MatrixFactoryTest.php | 16 ++++++++ tests/phpstan.neon | 5 +++ 81 files changed, 412 insertions(+), 307 deletions(-) create mode 100644 tests/phpstan.neon diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index f55d04032..3fdc2ffdf 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -8,7 +8,7 @@ on: jobs: test-and-static-analysis: - name: Test and Static Analysis + name: Test and Lint runs-on: ubuntu-latest strategy: matrix: @@ -23,12 +23,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: '14.x' - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -58,10 +58,38 @@ jobs: ./vendor/bin/phpcs --version ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + static-analysis: + name: Static Analysis + runs-on: ubuntu-latest + strategy: + matrix: + php: ['7.2'] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: xdebug + tools: composer:v2 + + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: '14.x' + + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Run Composer + run: composer install --no-interaction + - name: Static analysis run: | ./vendor/bin/phpstan --version - ./vendor/bin/phpstan analyze --level max src/ + ./vendor/bin/phpstan analyze -c tests/phpstan.neon code-coverage: name: Code coverage @@ -79,12 +107,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: '14.x' - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index 347cd67ce..a4cef9afd 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -7,8 +7,8 @@ on: - master jobs: - test-and-static-analysis: - name: Test and Static Analysis + test-and-lint: + name: Test and Lint runs-on: ubuntu-latest strategy: matrix: @@ -22,12 +22,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: '14.x' - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -57,7 +57,35 @@ jobs: ./vendor/bin/phpcs --version ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + static-analysis: + name: Static Analysis + runs-on: ubuntu-latest + strategy: + matrix: + php: ['7.2'] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: xdebug + tools: composer:v2 + + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: '14.x' + + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Run Composer + run: composer install --no-interaction + - name: Static analysis run: | ./vendor/bin/phpstan --version - ./vendor/bin/phpstan analyze --level max src/ + ./vendor/bin/phpstan analyze -c tests/phpstan.neon \ No newline at end of file diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index 56dc25250..957cad081 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -4,7 +4,7 @@ on: pull_request jobs: test-and-static-analysis: - name: Test and Static Analysis + name: Test and Lint runs-on: ubuntu-latest strategy: matrix: @@ -19,12 +19,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: '14.x' - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -54,10 +54,38 @@ jobs: ./vendor/bin/phpcs --version ./vendor/bin/phpcs --ignore=vendor --standard=tests/coding_standard.xml -s . + static-analysis: + name: Static Analysis + runs-on: ubuntu-latest + strategy: + matrix: + php: ['7.2'] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: xdebug + tools: composer:v2 + + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: '14.x' + + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Run Composer + run: composer install --no-interaction + - name: Static analysis run: | ./vendor/bin/phpstan --version - ./vendor/bin/phpstan analyze --level max src/ + ./vendor/bin/phpstan analyze -c tests/phpstan.neon code-coverage: name: Code coverage @@ -75,12 +103,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: '14.x' - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/Makefile b/Makefile index 3270e55f0..9eb7ee0b8 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ style : vendor/bin/phpcs --standard=tests/coding_standard.xml --ignore=vendor -s . phpstan : - vendor/bin/phpstan analyze --level max src/ + vendor/bin/phpstan analyze -c tests/phpstan.neon phpmd : vendor/bin/phpmd src/ ansi cleancode,codesize,design,unusedcode,naming diff --git a/README.md b/README.md index 6f0c29298..71a125b8e 100644 --- a/README.md +++ b/README.md @@ -977,7 +977,7 @@ $f’⟮x⟯ = function ($x) { }; [$start, $end, $n] = [0, 3, 4]; -$p = Interpolation\ClampedCubicSpline::interpolate($points); // input as a set of points +$p = Interpolation\ClampedCubicSpline::interpolate($points); // input as a set of points $p = Interpolation\ClampedCubicSpline::interpolate($f⟮x⟯, $f’⟮x⟯, $start, $end, $n); // input as a callback function $p(0); // 1 diff --git a/composer.json b/composer.json index 031208891..760839c27 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "phpunit/phpunit": "^8.5", "php-coveralls/php-coveralls": "^2.0", "squizlabs/php_codesniffer": "3.*", - "phpstan/phpstan": "*", + "phpstan/phpstan": "^1.10", "phpmd/phpmd": "^2.6", "phploc/phploc": "*", "php-parallel-lint/php-parallel-lint": "^1.2" diff --git a/src/Algebra.php b/src/Algebra.php index b89777b8d..3a1e2cf93 100644 --- a/src/Algebra.php +++ b/src/Algebra.php @@ -95,6 +95,7 @@ public static function extendedGcd(int $a, int $b): array * @param int $b * * @return int + * @psalm-suppress InvalidReturnType (Change to intdiv for PHP 8.0) */ public static function lcm(int $a, int $b): int { @@ -236,7 +237,7 @@ public static function linear(float $a, float $b): ?float * @param float $c constant coefficient * @param bool $return_complex Whether to return complex numbers or NANs if imaginary roots * - * @return array{0: float|Complex, 1?: float|Complex} + * @return float[]|Complex[] * [x₁, x₂] roots of the equation, or * [NAN, NAN] if discriminant is negative, or * [Complex, Complex] if discriminant is negative and complex option is on or @@ -367,7 +368,7 @@ public static function discriminant(float $a, float $b, float $c): float * @param float $a₀ constant coefficient * @param bool $return_complex whether to return complex numbers * - * @return array{0: float|Complex, 1?: float|Complex, 2?: float|Complex} + * @return float[]|Complex[] * array of roots (three real roots, or one real root and two NANs because complex numbers not yet supported) * (If $a₃ = 0, then only two roots of quadratic equation) * @@ -531,7 +532,10 @@ public static function quartic(float $a₄, float $a₃, float $a₂, float $a // The roots for this polynomial are the roots of the depressed polynomial minus a₃/4. if (!$return_complex) { - // @phpstan-ignore-next-line (Single::subtract() works with real numbers only, must be real roots) + /** + * @phpstan-ignore-next-line (Single::subtract() works with real numbers only, must be real roots) + * @psalm-suppress InvalidArgument + */ return Single::subtract($depressed_quartic_roots, $a₃ / 4); } diff --git a/src/Expression/Piecewise.php b/src/Expression/Piecewise.php index 22dd13015..6417d79b8 100644 --- a/src/Expression/Piecewise.php +++ b/src/Expression/Piecewise.php @@ -71,7 +71,6 @@ public function __construct(array $intervals, array $functions) $lastB = $b ?? -\INF; $lastBOpen = $bOpen ?? false; - // @phpstan-ignore-next-line (Strict comparison using !== between 2 and 2 will always evaluate to false.) if (\count(\array_filter($interval, '\is_numeric')) !== 2) { throw new Exception\BadDataException('Each interval must contain two numbers.'); } diff --git a/src/Expression/Polynomial.php b/src/Expression/Polynomial.php index e81612523..e44085f68 100644 --- a/src/Expression/Polynomial.php +++ b/src/Expression/Polynomial.php @@ -56,7 +56,7 @@ class Polynomial implements ObjectArithmetic /** @var int */ private $degree; - /** @var array */ + /** @var array */ private $coefficients; /** @var string */ @@ -71,7 +71,7 @@ class Polynomial implements ObjectArithmetic * When a polynomial is instantiated, set the coefficients and degree of * that polynomial as its object parameters. * - * @param array $coefficients An array of coefficients in decreasing powers + * @param array $coefficients An array of coefficients in decreasing powers * Example: new Polynomial([1, 2, 3]) will create * a polynomial that looks like x² + 2x + 3. * @param string $variable @@ -215,7 +215,7 @@ private function checkNumericOrPolynomial($input): Polynomial if ($input instanceof Polynomial) { return $input; } elseif (\is_numeric($input)) { - /** @var number $input */ + /** @var int|float $input */ return new Polynomial([$input]); } else { throw new Exception\IncorrectTypeException('Input must be a Polynomial or a number'); @@ -235,7 +235,7 @@ public function getDegree(): int /** * Getter method for the coefficients of a polynomial * - * @return array The coefficients array of a polynomial object + * @return array The coefficients array of a polynomial object */ public function getCoefficients(): array { diff --git a/src/Functions/Map/Multi.php b/src/Functions/Map/Multi.php index 023c5d380..f60ba257b 100644 --- a/src/Functions/Map/Multi.php +++ b/src/Functions/Map/Multi.php @@ -14,9 +14,9 @@ class Multi * * [x₁ + y₁, x₂ + y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -42,9 +42,9 @@ public static function add(array ...$arrays): array * * [x₁ - y₁, x₂ - y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -75,9 +75,9 @@ function ($x) { * * [x₁ * y₁, x₂ * y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -103,7 +103,7 @@ public static function multiply(array ...$arrays): array * * [x₁ / y₁, x₂ / y₂, ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * * @return array * @@ -136,9 +136,9 @@ function ($x) { * * [max(x₁, y₁), max(x₂, y₂), ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ @@ -169,9 +169,9 @@ function ($x) { * * [max(x₁, y₁), max(x₂, y₂), ... ] * - * @param array ...$arrays Two or more arrays of numbers + * @param array ...$arrays Two or more arrays of numbers * - * @return array + * @return array * * @throws Exception\BadDataException */ diff --git a/src/Functions/Map/Single.php b/src/Functions/Map/Single.php index f9a20feb6..a989b215c 100644 --- a/src/Functions/Map/Single.php +++ b/src/Functions/Map/Single.php @@ -12,7 +12,7 @@ class Single /** * Map addition * - * @param array $xs + * @param array $xs * @param int|float $k Number to add to each element * * @return array @@ -30,7 +30,7 @@ function ($x) use ($k) { /** * Map subtract * - * @param array $xs + * @param array $xs * @param int|float $k Number to subtract from each element * * @return array @@ -48,7 +48,7 @@ function ($x) use ($k) { /** * Map multiply * - * @param array $xs + * @param array $xs * @param int|float $k Number to multiply to each element * * @return array @@ -66,7 +66,7 @@ function ($x) use ($k) { /** * Map Divide * - * @param array $xs + * @param array $xs * @param int|float $k Number to divide each element by * * @return array @@ -84,7 +84,7 @@ function ($x) use ($k) { /** * Map square * - * @param array $xs + * @param array $xs * * @return array */ @@ -101,7 +101,7 @@ function ($x) { /** * Map cube * - * @param array $xs + * @param array $xs * * @return array */ @@ -119,7 +119,7 @@ function ($x) { * Map reciprocal * x := 1/x * - * @param array $xs + * @param array $xs * * @return array * @@ -148,7 +148,7 @@ function ($x) { /** * Map raise to a power * - * @param array $xs + * @param array $xs * @param int|float $n * * @return array @@ -166,7 +166,7 @@ function ($x) use ($n) { /** * Map square root * - * @param array $xs + * @param array $xs * * @return array */ @@ -183,7 +183,7 @@ function ($x) { /** * Map absolute value * - * @param array $xs + * @param array $xs * * @return array */ @@ -202,10 +202,10 @@ function ($x) { * Each element in array is compared against the value, * and the min of each is returned. * - * @param array $xs + * @param array $xs * @param int|float $value * - * @return array + * @return array */ public static function min(array $xs, $value): array { @@ -222,10 +222,10 @@ function ($x) use ($value) { * Each element in the array is compared against the value, * and the max of each is returned. * - * @param array $xs + * @param array $xs * @param int|float $value * - * @return array + * @return array */ public static function max(array $xs, $value): array { diff --git a/src/Functions/Support.php b/src/Functions/Support.php index 6694367ad..c4248df71 100644 --- a/src/Functions/Support.php +++ b/src/Functions/Support.php @@ -21,7 +21,7 @@ class Support * * @param array $limits Boundary limit definitions for each parameter * ['var1' => limit, 'var2' => limit, ...] - * @param array $params Parameters and their value to check against the defined limits + * @param array $params Parameters and their value to check against the defined limits * ['var1' => value, 'var2' => value, ...] * * @return bool True if all parameters are within defined limits diff --git a/src/InformationTheory/Entropy.php b/src/InformationTheory/Entropy.php index 8a707b115..35ad6b6bb 100644 --- a/src/InformationTheory/Entropy.php +++ b/src/InformationTheory/Entropy.php @@ -31,7 +31,7 @@ class Entropy * * H is in shannons, or bits. * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float average minimum number of bits * @@ -74,7 +74,7 @@ function ($pᵢ) { * 1 nat = 1/ln(2) shannons or bits. * https://en.wikipedia.org/wiki/Nat_(unit) * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float average minimum number of nats * @@ -117,7 +117,7 @@ function ($pᵢ) { * 1 hartley = log₂(10) bit = ln(10) nat, or approximately 3.322 Sh, or 2.303 nat. * https://en.wikipedia.org/wiki/Hartley_(unit) * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float average minimum number of hartleys * @@ -158,8 +158,8 @@ function ($pᵢ) { * * H(p,q) = -∑ p(x) log₂ q(x) * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float entropy between distributions * @@ -213,7 +213,7 @@ function ($pᵢ, $qᵢ) { * Joint entropy is basically just shannonEntropy but the probability distribution input * represents the probability of two variables happening at the same time. * - * @param array $P⟮x、y⟯ probability distribution of x and y occuring together + * @param array $P⟮x、y⟯ probability distribution of x and y occuring together * * @return float uncertainty * @@ -236,7 +236,7 @@ public static function jointEntropy(array $P⟮x、y⟯) * * H is in shannons, or bits. * - * @param array $p probability distribution + * @param array $p probability distribution * @param int|float $α order α * * @return float @@ -274,7 +274,7 @@ public static function renyiEntropy(array $p, $α) * * Perplexity is in shannons, or bits. * - * @param array $p probability distribution + * @param array $p probability distribution * * @return float perplexity * diff --git a/src/LinearAlgebra/Decomposition/LU.php b/src/LinearAlgebra/Decomposition/LU.php index a88c63812..107931d97 100644 --- a/src/LinearAlgebra/Decomposition/LU.php +++ b/src/LinearAlgebra/Decomposition/LU.php @@ -224,7 +224,7 @@ protected static function pivotize(NumericMatrix $A): NumericMatrix * xᵢ = --- | yᵢ - ∑ Uᵢⱼxⱼ | * Uᵢᵢ \ ʲ⁼ⁱ⁺¹ / * - * @param Vector|array $b solution to Ax = b + * @param Vector|array $b solution to Ax = b * * @return Vector x * @@ -236,7 +236,7 @@ protected static function pivotize(NumericMatrix $A): NumericMatrix */ public function solve($b): Vector { - // Input must be a Vector or array. @phpstan-ignore-next-line + // Input must be a Vector or array. if (!($b instanceof Vector || \is_array($b))) { throw new Exception\IncorrectTypeException('b in Ax = b must be a Vector or array'); } diff --git a/src/LinearAlgebra/Decomposition/QR.php b/src/LinearAlgebra/Decomposition/QR.php index f45546024..a944c330d 100644 --- a/src/LinearAlgebra/Decomposition/QR.php +++ b/src/LinearAlgebra/Decomposition/QR.php @@ -120,7 +120,7 @@ public static function decompose(NumericMatrix $A): QR * - R⁻¹R = I, so we get x = R⁻¹Qᵀb * Solve x = R⁻¹Qᵀb * - * @param Vector|array $b solution to Ax = b + * @param Vector|array $b solution to Ax = b * * @return Vector x * @@ -128,7 +128,7 @@ public static function decompose(NumericMatrix $A): QR */ public function solve($b): Vector { - // Input must be a Vector or array. @phpstan-ignore-next-line + // Input must be a Vector or array. if (!($b instanceof Vector || \is_array($b))) { throw new Exception\IncorrectTypeException('b in Ax = b must be a Vector or array'); } diff --git a/src/LinearAlgebra/Decomposition/SVD.php b/src/LinearAlgebra/Decomposition/SVD.php index 28ea10708..3bb807833 100644 --- a/src/LinearAlgebra/Decomposition/SVD.php +++ b/src/LinearAlgebra/Decomposition/SVD.php @@ -13,10 +13,10 @@ * The generalization of the eigendecomposition of a square matrix to an m x n matrix * https://en.wikipedia.org/wiki/Singular_value_decomposition * - * @property-read NumericMatrix $S m x n diagonal matrix - * @property-read NumericMatrix $V n x n orthogonal matrix - * @property-read NumericMatrix $U m x m orthogonal matrix - * @property-read Vector $D diagonal elements from S + * @property-read NumericMatrix $S m x n diagonal matrix + * @property-read NumericMatrix $V n x n orthogonal matrix + * @property-read NumericMatrix $U m x m orthogonal matrix + * @property-read Vector $D diagonal elements from S */ class SVD extends Decomposition { @@ -29,7 +29,7 @@ class SVD extends Decomposition /** @var NumericMatrix m x n diagonal matrix containing the singular values */ private $S; - /** @var Vector diagonal elements from S that are the singular values */ + /** @var Vector diagonal elements from S that are the singular values */ private $D; /** @@ -78,7 +78,7 @@ public function getV(): NumericMatrix /** * Get D * - * @return Vector + * @return Vector */ public function getD(): Vector { @@ -128,7 +128,7 @@ public static function decompose(NumericMatrix $M): SVD * * @param string $name * - * @return NumericMatrix|Vector + * @return NumericMatrix|Vector */ public function __get(string $name) { diff --git a/src/LinearAlgebra/Eigenvalue.php b/src/LinearAlgebra/Eigenvalue.php index 46e71bf0b..c4db0ef4c 100644 --- a/src/LinearAlgebra/Eigenvalue.php +++ b/src/LinearAlgebra/Eigenvalue.php @@ -108,10 +108,10 @@ public static function closedFormPolynomialRootMethod(NumericMatrix $A): array $det = $⟮B − λ⟯->det(); // Calculate the roots of the determinant. - /** @var array $eigenvalues */ + /** @var array $eigenvalues */ $eigenvalues = $det->roots(); \usort($eigenvalues, function ($a, $b) { - /** @var number $a */ /** @var number $b */ + /** @var int|float $a */ /** @var int|float $b */ return \abs($b) <=> \abs($a); }); diff --git a/src/LinearAlgebra/MatrixFactory.php b/src/LinearAlgebra/MatrixFactory.php index 273b75761..8a16fc99a 100644 --- a/src/LinearAlgebra/MatrixFactory.php +++ b/src/LinearAlgebra/MatrixFactory.php @@ -10,13 +10,15 @@ * Matrix factory to create matrices of all types. * Use factory instead of instantiating individual Matrix classes. * - * @template T = int[][]|float[][]|Complex[][]|object[][] + * template T = int[][]|float[][]|Complex[][]|object[][] */ class MatrixFactory { /** * Factory method * + * @template T = int|float|Complex|object + * * @param T[][] $A 2-dimensional array of Matrix data * @param float|null $ε Optional error tolerance * @@ -36,7 +38,7 @@ public static function create(array $A, ?float $ε = null): Matrix switch ($matrix_type) { case 'numeric': case 'numeric_square': - /** @var array> $A */ + /** @var array> $A */ return self::createNumeric($A, $ε); case 'complex': /** @var array> $A */ @@ -128,6 +130,8 @@ public static function createFromVectors(array $A, ?float $ε = null): NumericMa * [⋮ ] * [xm] * + * @template T = int|float|Complex|object + * * @param T[] $A m × 1 vector representing the matrix * * @return Matrix|NumericMatrix|ComplexMatrix|ObjectMatrix|ObjectSquareMatrix @@ -154,6 +158,8 @@ public static function createFromColumnVector(array $A): Matrix * * x = [x₁ x₂ ⋯ xn] * + * @template T = int|float|Complex|object + * * @param T[] $A 1 × n vector representing the matrix * * @return Matrix|NumericMatrix|ComplexMatrix|ObjectMatrix|ObjectSquareMatrix @@ -301,7 +307,7 @@ public static function downshiftPermutation(int $n): NumericSquareMatrix $bottom_row = \array_pop($I); \array_unshift($I, $bottom_row); - /** @var array> $I */ + /** @var array> $I */ return new NumericSquareMatrix($I); } @@ -451,7 +457,7 @@ public static function eye(int $m, int $n, int $k, float $x = null): NumericMatr * A = [0 2 0] * [0 0 3] * - * @param array $D elements of the diagonal + * @param array $D elements of the diagonal * * @return NumericDiagonalMatrix * @@ -518,7 +524,7 @@ public static function hilbert(int $n): NumericMatrix /** * Create the Vandermonde Matrix from a simple array. * - * @param array $M (α₁, α₂, α₃ ⋯ αm) + * @param array $M (α₁, α₂, α₃ ⋯ αm) * @param int $n * * @return NumericMatrix @@ -610,7 +616,9 @@ public static function random(int $m, int $n, int $min = 0, int $max = 20): Nume /** * Check input parameters * - * @param array $A + * @template T = int|float|Complex|object + * + * @param array> $A * * @throws Exception\BadDataException if array data not provided for matrix creation * @throws Exception\MatrixException if any row has a different column count @@ -620,13 +628,14 @@ private static function checkParams(array $A): void if (empty($A)) { throw new Exception\BadDataException('Array data not provided for Matrix creation'); } + if (!isset($A[0]) || !\is_array($A[0])) { + throw new Exception\BadDataException('Array of array data not provided for Matrix creation'); + } - if (isset($A[0]) && \is_array($A[0])) { - $column_count = \count($A[0]); - foreach ($A as $i => $row) { - if (\count($row) !== $column_count) { - throw new Exception\MatrixException("Row $i has a different column count: " . \count($row) . "; was expecting $column_count."); - } + $column_count = \count($A[0]); + foreach ($A as $i => $row) { + if (\count($row) !== $column_count) { + throw new Exception\MatrixException("Row $i has a different column count: " . \count($row) . "; was expecting $column_count."); } } } diff --git a/src/LinearAlgebra/NumericDiagonalMatrix.php b/src/LinearAlgebra/NumericDiagonalMatrix.php index 8748fad40..dc1e424f7 100644 --- a/src/LinearAlgebra/NumericDiagonalMatrix.php +++ b/src/LinearAlgebra/NumericDiagonalMatrix.php @@ -15,7 +15,7 @@ class NumericDiagonalMatrix extends NumericSquareMatrix /** * Constructor * - * @param array> $A + * @param array> $A */ public function __construct(array $A) { diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index cf0637453..52970dced 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -10,7 +10,7 @@ /** * m x n Matrix * - * @extends Matrix + * @extends Matrix */ class NumericMatrix extends Matrix { @@ -34,7 +34,7 @@ class NumericMatrix extends Matrix /** * Constructor * - * @param array> $A of arrays $A m x n matrix + * @param array> $A of arrays $A m x n matrix * * @throws Exception\BadDataException if any rows have a different column count */ @@ -1266,7 +1266,6 @@ public function subtract($B): NumericMatrix */ public function multiply($B): NumericMatrix { - // @phpstan-ignore-next-line if ((!$B instanceof NumericMatrix) && (!$B instanceof Vector)) { throw new Exception\IncorrectTypeException('Can only do matrix multiplication with a Matrix or Vector'); } @@ -1281,15 +1280,16 @@ public function multiply($B): NumericMatrix $Bᵀ = $B->transpose()->getMatrix(); foreach ($this->A as $i => $Aʳᵒʷ⟦i⟧) { - /** @var array $R */ $R[$i] = \array_fill(0, $B->n, 0); foreach ($Bᵀ as $j => $Bᶜᵒˡ⟦j⟧) { foreach ($Aʳᵒʷ⟦i⟧ as $k => $A⟦i⟧⟦k⟧) { + // @phpstan-ignore-next-line (Remove in PHP 8.0, no longer returns false) $R[$i][$j] += $A⟦i⟧⟦k⟧ * $Bᶜᵒˡ⟦j⟧[$k]; } } } + // @phpstan-ignore-next-line (Due to above false from array_fill) return MatrixFactory::createNumeric($R, $this->ε); } @@ -2053,7 +2053,7 @@ public function columnMeans(): Vector * * tr(A) = a₁₁ + a₂₂ + ... ann * - * @return number + * @return int|float * * @throws Exception\MatrixException if the matrix is not a square matrix */ @@ -2077,7 +2077,7 @@ public function trace() * 1-norm (‖A‖₁) * Maximum absolute column sum of the matrix * - * @return number + * @return int|float */ public function oneNorm() { @@ -2102,7 +2102,7 @@ public function oneNorm() * ‖A‖F = √ Σ Σ |aᵢⱼ|² * ᵢ₌₁ ᵢ₌₁ * - * @return number + * @return int|float */ public function frobeniusNorm() { @@ -2123,7 +2123,7 @@ public function frobeniusNorm() * Infinity norm (‖A‖∞) * Maximum absolute row sum of the matrix * - * @return number + * @return int|float */ public function infinityNorm() { @@ -2141,7 +2141,7 @@ public function infinityNorm() * Max norm (‖A‖max) * Elementwise max * - * @return number + * @return int|float */ public function maxNorm() { @@ -2187,7 +2187,7 @@ public function maxNorm() * │ref(A)│ = determinant of the row echelon form of A * ⁿ = number of row swaps when computing REF * - * @return number + * @return int|float * * @throws Exception\MatrixException if matrix is not square * @throws Exception\IncorrectTypeException @@ -2196,7 +2196,7 @@ public function maxNorm() public function det() { if ($this->catalog->hasDeterminant()) { - /** @var number */ + /** @var int|float */ return $this->catalog->getDeterminant(); } @@ -2316,7 +2316,7 @@ public function det() * @param int $mᵢ Row to exclude * @param int $nⱼ Column to exclude * - * @return number + * @return int|float * * @throws Exception\MatrixException if matrix is not square * @throws Exception\MatrixException if row to exclude for cofactor does not exist @@ -2893,8 +2893,8 @@ public function svd(): Decomposition\SVD * Otherwise, it is more efficient to decompose and then solve. * Use LU Decomposition and solve Ax = b. * - * @param Vector|array $b solution to Ax = b - * @param string $method (optional) Force a specific solve method - defaults to DEFAULT where various methods are tried + * @param Vector|array $b solution to Ax = b + * @param string $method (optional) Force a specific solve method - defaults to DEFAULT where various methods are tried * * @return Vector x * @@ -2907,7 +2907,6 @@ public function svd(): Decomposition\SVD public function solve($b, string $method = self::DEFAULT): Vector { // Input must be a Vector or array. - // @phpstan-ignore-next-line if (!($b instanceof Vector || \is_array($b))) { throw new Exception\IncorrectTypeException('b in Ax = b must be a Vector or array'); } @@ -3025,7 +3024,7 @@ private function solveRref(Vector $b): Vector * * @param string $method Algorithm used to compute the eigenvalues * - * @return array of eigenvalues + * @return array of eigenvalues * * @throws Exception\MatrixException if method is not a valid eigenvalue method * @throws Exception\MathException diff --git a/src/LinearAlgebra/NumericSquareMatrix.php b/src/LinearAlgebra/NumericSquareMatrix.php index fcf716c11..b263de142 100644 --- a/src/LinearAlgebra/NumericSquareMatrix.php +++ b/src/LinearAlgebra/NumericSquareMatrix.php @@ -14,7 +14,7 @@ class NumericSquareMatrix extends NumericMatrix /** * Constructor * - * @param array> $A + * @param array> $A * * @throws Exception\MathException */ diff --git a/src/LinearAlgebra/ObjectMatrix.php b/src/LinearAlgebra/ObjectMatrix.php index 749b844af..beec727dc 100644 --- a/src/LinearAlgebra/ObjectMatrix.php +++ b/src/LinearAlgebra/ObjectMatrix.php @@ -56,7 +56,6 @@ protected function validateMatrixData(): void { if ($this->A[0][0] instanceof ObjectArithmetic) { $this->object_type = \get_class($this->A[0][0]); - // @phpstan-ignore-next-line } else { throw new Exception\IncorrectTypeException("The object must implement the interface."); } @@ -271,7 +270,7 @@ public function scalarMultiply($λ): Matrix /** * {@inheritDoc} * - * @return number + * @return int|float * * @throws Exception\MatrixException if the matrix is not a square matrix */ diff --git a/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php b/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php index ccc8fee03..cc27bdc25 100644 --- a/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php +++ b/src/LinearAlgebra/Reduction/ReducedRowEchelonForm.php @@ -29,7 +29,7 @@ class ReducedRowEchelonForm extends NumericMatrix /** * ReducedRowEchelonForm constructor * - * @param array> $A + * @param array> $A * * @throws Exception\BadDataException */ diff --git a/src/LinearAlgebra/Reduction/RowEchelonForm.php b/src/LinearAlgebra/Reduction/RowEchelonForm.php index ee49b0c32..510c6d7d7 100644 --- a/src/LinearAlgebra/Reduction/RowEchelonForm.php +++ b/src/LinearAlgebra/Reduction/RowEchelonForm.php @@ -24,8 +24,8 @@ class RowEchelonForm extends NumericMatrix /** * RowEchelonForm constructor - * @param array> $A - * @param int $swaps Number of row swaps when computing REF + * @param array> $A + * @param int $swaps Number of row swaps when computing REF * * @throws Exception\BadDataException */ @@ -114,7 +114,7 @@ public static function reduce(NumericMatrix $A): RowEchelonForm * * @param NumericMatrix $A * - * @return array{array>, int} - matrix in row echelon form and number of row swaps + * @return array{array>, int} - matrix in row echelon form and number of row swaps * * @throws Exception\SingularMatrixException if the matrix is singular */ @@ -179,7 +179,7 @@ public static function gaussianElimination(NumericMatrix $A): array * * @param NumericMatrix $A * - * @return array{array>, int} - matrix in row echelon form and number of row swaps + * @return array{array>, int} - matrix in row echelon form and number of row swaps * * @throws Exception\IncorrectTypeException * @throws Exception\MatrixException diff --git a/src/LinearAlgebra/Vector.php b/src/LinearAlgebra/Vector.php index 9d62e89a6..75d56d82e 100644 --- a/src/LinearAlgebra/Vector.php +++ b/src/LinearAlgebra/Vector.php @@ -9,15 +9,15 @@ /** * 1 x n Vector * - * @implements \Iterator - * @implements \ArrayAccess + * @implements \Iterator + * @implements \ArrayAccess */ class Vector implements \Countable, \Iterator, \ArrayAccess, \JsonSerializable { /** @var int Number of elements */ private $n; - /** @var array of numbers */ + /** @var array of numbers */ private $A; /** @var int Iterator position */ @@ -26,7 +26,7 @@ class Vector implements \Countable, \Iterator, \ArrayAccess, \JsonSerializable /** * Constructor * - * @param array $A 1 x n vector + * @param array $A 1 x n vector * * @throws Exception\BadDataException if the Vector is empty */ @@ -53,7 +53,7 @@ public function __construct(array $A) /** * Get matrix * - * @return array + * @return array */ public function getVector(): array { @@ -75,7 +75,7 @@ public function getN(): int * * @param int $i index * - * @return number + * @return int|float * * @throws Exception\VectorException */ @@ -160,7 +160,7 @@ public function sum() * Vector length (magnitude) * Same as l2-norm * - * @return number + * @return int|float */ public function length() { @@ -170,7 +170,7 @@ public function length() /** * Max of all the elements * - * @return number|false + * @return int|float|false * * Note: Remove false from return value after PHP 8.0 */ @@ -182,7 +182,7 @@ public function max() /** * Min of all the elements * - * @return number|false + * @return int|float|false * * Note: Remove false from return value after PHP 8.0 */ @@ -714,7 +714,7 @@ public function pNorm($p) * * |x|∞ = max |x| * - * @return number|false + * @return int|float|false * * Note: Remove false from return value after PHP 8.0 */ @@ -767,7 +767,7 @@ public function offsetExists($i): bool /** * @param mixed $i - * @return number + * @return int|float */ #[\ReturnTypeWillChange] public function offsetGet($i) @@ -777,7 +777,7 @@ public function offsetGet($i) /** * @param int $i - * @param number $value + * @param int|float $value * @throws Exception\VectorException */ public function offsetSet($i, $value): void @@ -799,7 +799,7 @@ public function offsetUnset($i): void **************************************************************************/ /** - * @return array + * @return array */ public function jsonSerialize(): array { @@ -816,7 +816,7 @@ public function rewind(): void } /** - * @return number + * @return int|float */ #[\ReturnTypeWillChange] public function current() diff --git a/src/Number/Complex.php b/src/Number/Complex.php index e7135f617..d58b03543 100644 --- a/src/Number/Complex.php +++ b/src/Number/Complex.php @@ -14,20 +14,20 @@ * part of the complex number. * https://en.wikipedia.org/wiki/Complex_number * - * @property-read number $r - * @property-read number $i + * @property-read int|float $r + * @property-read int|float $i */ class Complex implements ObjectArithmetic { /** * Real part of the complex number - * @var number + * @var int|float */ protected $r; /** * Imaginary part fo the complex number - * @var number + * @var int|float */ protected $i; @@ -84,7 +84,7 @@ public function __toString(): string * * @param string $part * - * @return number + * @return int|float * * @throws Exception\BadParameterException if something other than r or i is attempted */ @@ -124,7 +124,7 @@ public function complexConjugate(): Complex * _______ * |z| = √a² + b² * - * @return number + * @return int|float */ public function abs() { @@ -139,7 +139,7 @@ public function abs() * If z = a + bi * arg(z) = atan(b, a) * - * @return number + * @return int|float */ public function arg() { @@ -244,7 +244,7 @@ public function negate(): Complex * r = |z| * θ = arg(z) (in radians) * - * @return number[] + * @return int[]|float[] */ public function polarForm(): array { @@ -406,7 +406,6 @@ public function pow($c): Complex return new Complex($new_r, $new_i); } - // @phpstan-ignore-next-line throw new Exception\IncorrectTypeException('Argument must be real or complex number'); } diff --git a/src/Number/Quaternion.php b/src/Number/Quaternion.php index fb9f54c5a..90d7bde22 100644 --- a/src/Number/Quaternion.php +++ b/src/Number/Quaternion.php @@ -14,16 +14,16 @@ */ class Quaternion implements ObjectArithmetic { - /** @var number Real part of the quaternionic number */ + /** @var int|float Real part of the quaternionic number */ protected $r; - /** @var number First Imaginary part of the quaternionic number */ + /** @var int|float First Imaginary part of the quaternionic number */ protected $i; - /** @var number Second Imaginary part of the quaternionic number */ + /** @var int|float Second Imaginary part of the quaternionic number */ protected $j; - /** @var number Third Imaginary part of the quaternionic number */ + /** @var int|float Third Imaginary part of the quaternionic number */ protected $k; /** Floating-point range near zero to consider insignificant */ @@ -37,7 +37,6 @@ class Quaternion implements ObjectArithmetic */ public function __construct($r, $i, $j, $k) { - // @phpstan-ignore-next-line if (!\is_numeric($r) || !\is_numeric($i) || !\is_numeric($j) || !\is_numeric($k)) { throw new Exception\BadDataException('Values must be real numbers.'); } @@ -79,7 +78,7 @@ public function __toString(): string * * @param string $part * - * @return number + * @return int|float * * @throws Exception\BadParameterException if something other than r or i is attempted */ @@ -122,7 +121,7 @@ public function complexConjugate(): Quaternion * _________________ * |z| = √a² + b² + c² + d² * - * @return number + * @return int|float */ public function abs() { @@ -172,7 +171,7 @@ public function negate(): Quaternion * * (a + bi + cj + dk) - (e + fi + gj + hk) = (a + e) + (b + f)i + (c + g)j + (d + h)k * - * @param mixed $q + * @param int|float|Quaternion $q * * @return Quaternion * @@ -180,10 +179,10 @@ public function negate(): Quaternion */ public function add($q): Quaternion { - if (!is_numeric($q) && ! $q instanceof Quaternion) { - throw new Exception\IncorrectTypeException('Argument must be real or quaternion' . print_r($q, true)); + if (!\is_numeric($q) && ! $q instanceof Quaternion) { + throw new Exception\IncorrectTypeException('Argument must be real or quaternion' . \print_r($q, true)); } - if (is_numeric($q)) { + if (\is_numeric($q)) { $r = $this->r + $q; return new Quaternion($r, $this->i, $this->j, $this->k); } @@ -202,7 +201,7 @@ public function add($q): Quaternion * * (a + bi + cj + dk) - (e + fi + gj + hk) = (a - e) + (b - f)i + (c - g)j + (d - h)k * - * @param mixed $q + * @param int|float|Quaternion $q * * @return Quaternion * @@ -213,7 +212,7 @@ public function subtract($q): Quaternion if (!is_numeric($q) && ! $q instanceof Quaternion) { throw new Exception\IncorrectTypeException('Argument must be real or quaternion' . print_r($q, true)); } - if (is_numeric($q)) { + if (\is_numeric($q)) { $r = $this->r - $q; return new Quaternion($r, $this->i, $this->j, $this->k); } @@ -238,7 +237,7 @@ public function subtract($q): Quaternion * * Note: Quaternion multiplication is not commutative. * - * @param mixed $q + * @param int|float|Quaternion $q * * @return Quaternion * @@ -249,7 +248,7 @@ public function multiply($q): Quaternion if (!is_numeric($q) && ! $q instanceof Quaternion) { throw new Exception\IncorrectTypeException('Argument must be real or quaternion' . print_r($q, true)); } - if (is_numeric($q)) { + if (\is_numeric($q)) { return new Quaternion($this->r * $q, $this->i * $q, $this->j * $q, $this->k * $q); } @@ -269,7 +268,7 @@ public function multiply($q): Quaternion * Dividing two quaternions is accomplished by multiplying the first by the inverse of the second * This is not commutative! * - * @param mixed $q + * @param int|float|Quaternion $q * * @return Quaternion * @@ -281,7 +280,7 @@ public function divide($q): Quaternion throw new Exception\IncorrectTypeException('Argument must be real or quaternion' . print_r($q, true)); } - if (is_numeric($q)) { + if (\is_numeric($q)) { $r = $this->r / $q; $i = $this->i / $q; $j = $this->j / $q; @@ -318,7 +317,7 @@ public function equals(Quaternion $q): bool /** * Stringify an additional part of the quaternion * - * @param number $q + * @param int|float $q * @param string $unit * @param string $string * @return string diff --git a/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php b/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php index ca4ba5b2d..d1f388632 100644 --- a/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php +++ b/src/NumericalAnalysis/Interpolation/ClampedCubicSpline.php @@ -37,13 +37,13 @@ class ClampedCubicSpline extends Interpolation /** * Interpolate * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely three numbers: x, y, and y' * Example array: [[1,2,1], [2,3,0], [3,4,2]]. * Example callback: function($x) {return $x**2;} - * @param mixed ...$args + * @param array{callable, int|float, int|float, int|float} ...$args * (Optional) An additional callback: our first derivative, * and arguments of our callback functions: start, * end, and n. @@ -59,7 +59,7 @@ class ClampedCubicSpline extends Interpolation */ public static function interpolate($source, ...$args): Piecewise { - // Get an array of points from our $source argument + // Get an array of points from our $source argument @phpstan-ignore-next-line $points = self::getSplinePoints($source, $args); // Validate input and sort points @@ -156,22 +156,21 @@ public static function interpolate($source, ...$args): Piecewise * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array> $source + * @param callable|array> $source * The source of our approximation. Should be either * a callback function or a set of arrays. - * @param array{callable, number, number, number}|array $args + * @param array{callable, int|float, int|float, int|float} $args * The arguments of our callback function: derivative, * start, end, and n. Example: [$derivative, 0, 8, 5]. * If $source is a set of arrays, $args will default to []. * - * @return array + * @return array * * @throws Exception\BadDataException if $source is not callable or a set of arrays */ - public static function getSplinePoints($source, array $args = []): array + public static function getSplinePoints($source, array $args): array { // Guard clause - source must be callable or array of points - // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -202,7 +201,7 @@ public static function getSplinePoints($source, array $args = []): array * @param float $end the end of the interval * @param int $n the number of function evaluations * - * @return array + * @return array */ protected static function functionToSplinePoints(callable $function, callable $derivative, float $start, float $end, int $n): array { @@ -224,7 +223,7 @@ protected static function functionToSplinePoints(callable $function, callable $d * has precisely three numbers, and that no two points share the same first number * (x-component) * - * @param array $points Array of arrays (points) + * @param array $points Array of arrays (points) * @param int $degree The minimum number of input arrays * * @throws Exception\BadDataException if there are less than two points @@ -239,7 +238,6 @@ public static function validateSpline(array $points, int $degree = 2): void $x_coordinates = []; foreach ($points as $point) { - // @phpstan-ignore-next-line if (\count($point) !== 3) { throw new Exception\BadDataException('Each array needs to have have precisely three numbers, representing x, y, and y-prime'); } diff --git a/src/NumericalAnalysis/Interpolation/Interpolation.php b/src/NumericalAnalysis/Interpolation/Interpolation.php index b4c3d2b03..16ec00194 100644 --- a/src/NumericalAnalysis/Interpolation/Interpolation.php +++ b/src/NumericalAnalysis/Interpolation/Interpolation.php @@ -26,7 +26,7 @@ abstract class Interpolation * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either a callback function or a set of arrays. * @param array $args * The arguments of our callback function: start, end, and n. @@ -39,7 +39,6 @@ abstract class Interpolation public static function getPoints($source, array $args = []): array { // Guard clause - source must be callable or array of points - // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -102,7 +101,6 @@ public static function validate(array $points, int $degree = 2): void $x_coordinates = []; foreach ($points as $point) { - // @phpstan-ignore-next-line if (\count($point) !== 2) { throw new Exception\BadDataException('Each array needs to have have precisely two numbers, an x- and y-component'); } diff --git a/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php b/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php index e461e1486..e7de91573 100644 --- a/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php +++ b/src/NumericalAnalysis/Interpolation/LagrangePolynomial.php @@ -31,7 +31,7 @@ class LagrangePolynomial extends Interpolation /** * Interpolate * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php b/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php index 7326d2ee9..e691ee469 100644 --- a/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php +++ b/src/NumericalAnalysis/Interpolation/NaturalCubicSpline.php @@ -34,7 +34,7 @@ class NaturalCubicSpline extends Interpolation /** * Interpolate * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/Interpolation/NevillesMethod.php b/src/NumericalAnalysis/Interpolation/NevillesMethod.php index b32318571..f8dfd460b 100644 --- a/src/NumericalAnalysis/Interpolation/NevillesMethod.php +++ b/src/NumericalAnalysis/Interpolation/NevillesMethod.php @@ -29,7 +29,7 @@ class NevillesMethod extends Interpolation * * @param float $target * The point at which we are interpolation - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php b/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php index 8f8550f7c..67155dc4c 100644 --- a/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php +++ b/src/NumericalAnalysis/Interpolation/NewtonPolynomialForward.php @@ -26,7 +26,7 @@ class NewtonPolynomialForward extends Interpolation /** * Interpolate * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php b/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php index 41fe2103f..4dbf58217 100644 --- a/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php +++ b/src/NumericalAnalysis/Interpolation/RegularGridInterpolator.php @@ -53,16 +53,16 @@ class RegularGridInterpolator /** @var string Interpolation method (linear or nearest) */ private $method; - /** @var array> Points defining the regular grid in n dimensions */ + /** @var array> Points defining the regular grid in n dimensions */ private $grid; /** @var array Data on the regular grid in n dimensions */ private $values; /** - * @param array> $points Points defining the regular grid in n dimensions - * @param array $values Data on the regular grid in n dimensions - * @param string $method (optional - default: linear) Interpolation method (linear or nearest) + * @param array> $points Points defining the regular grid in n dimensions + * @param array $values Data on the regular grid in n dimensions + * @param string $method (optional - default: linear) Interpolation method (linear or nearest) * * @throws Exception\BadDataException the points and value dimensions do not align, or if an unknown method is used */ @@ -126,8 +126,8 @@ public function __invoke(array $xi): float } /** - * @param array $indices - * @param array $normDistances + * @param array $indices + * @param array $normDistances * * @return float|int */ @@ -155,8 +155,8 @@ private function evaluateLinear(array $indices, array $normDistances) } /** - * @param array $indices - * @param array $normDistances + * @param array $indices + * @param array $normDistances * * @return float|int */ diff --git a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php index 3b99c027a..8c3446868 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/FivePointFormula.php @@ -53,7 +53,7 @@ class FivePointFormula extends NumericalDifferentiation * * @param float $target * The value at which we are approximating the derivative - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php index 46d45dd89..247ad6ac4 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/NumericalDifferentiation.php @@ -24,8 +24,8 @@ abstract class NumericalDifferentiation /** * @param float $target - * @param callable|array $source - * @param number ...$args + * @param callable|array $source + * @param int|float ...$args * @return mixed */ abstract public static function differentiate(float $target, $source, ...$args); @@ -41,7 +41,7 @@ abstract public static function differentiate(float $target, $source, ...$args); * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. * @param array $args @@ -55,7 +55,6 @@ abstract public static function differentiate(float $target, $source, ...$args); public static function getPoints($source, array $args = []): array { // Guard clause - source must be callable or array of points - // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -119,7 +118,6 @@ public static function validate(array $points, int $degree): void $x_coordinates = []; foreach ($points as $point) { - // @phpstan-ignore-next-line if (\count($point) !== 2) { throw new Exception\BadDataException('Each array needs to have have precisely two numbers, an x- and y-component'); } diff --git a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php index 8e31c2c8f..f165e479a 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/SecondDerivativeMidpointFormula.php @@ -42,7 +42,7 @@ class SecondDerivativeMidpointFormula extends NumericalDifferentiation * * @param float $target * The value at which we are approximating the derivative - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php index f0a53a03a..1fbca659e 100644 --- a/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php +++ b/src/NumericalAnalysis/NumericalDifferentiation/ThreePointFormula.php @@ -53,7 +53,7 @@ class ThreePointFormula extends NumericalDifferentiation * * @param float $target * The value at which we are approximating the derivative - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php b/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php index 617acd69c..2e301221e 100644 --- a/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/BoolesRule.php @@ -63,7 +63,7 @@ class BoolesRule extends NumericalIntegration * ⁱ⁼¹ 45 * where h = (xn - x₁) / (n - 1) * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php b/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php index bf0e4917b..f5d67161a 100644 --- a/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/MidpointRule.php @@ -55,7 +55,7 @@ class MidpointRule extends NumericalIntegration * * where h = xᵢ₊₁ - xᵢ * note: this implementation does not compute the error term. - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php b/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php index 9cc6d40a0..8613da1c6 100644 --- a/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php +++ b/src/NumericalAnalysis/NumericalIntegration/NumericalIntegration.php @@ -23,9 +23,9 @@ abstract class NumericalIntegration protected const Y = 1; /** - * @param callable|array $source - * @param number ...$args - * @return number + * @param callable|array $source + * @param int|float ...$args + * @return int|float */ abstract public static function approximate($source, ...$args); @@ -40,7 +40,7 @@ abstract public static function approximate($source, ...$args); * @todo Add method to verify input arguments are valid. * Verify $start and $end are numbers, $end > $start, and $points is an integer > 1 * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. * @param array $args @@ -55,7 +55,6 @@ abstract public static function approximate($source, ...$args); public static function getPoints($source, array $args = []): array { // Guard clause - source must be callable or array of points - // @phpstan-ignore-next-line if (!(\is_callable($source) || \is_array($source))) { throw new Exception\BadDataException('Input source is incorrect. You need to input either a callback function or a set of arrays'); } @@ -102,8 +101,8 @@ protected static function functionToPoints(callable $function, float $start, flo * has precisely two numbers, and that no two points share the same first number * (x-component) * - * @param array $points Array of arrays (points) - * @param int $degree The minimum number of input arrays + * @param array $points Array of arrays (points) + * @param int $degree The minimum number of input arrays * * @throws Exception\BadDataException if there are less than two points * @throws Exception\BadDataException if any point does not contain two numbers @@ -117,7 +116,6 @@ public static function validate(array $points, int $degree = 2): void $x_coordinates = []; foreach ($points as $point) { - // @phpstan-ignore-next-line if (\count($point) !== 2) { throw new Exception\BadDataException('Each array needs to have have precisely two numbers, an x- and y-component'); } diff --git a/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php b/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php index 430ea3bd2..587e0c6ff 100644 --- a/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php +++ b/src/NumericalAnalysis/NumericalIntegration/RectangleMethod.php @@ -58,7 +58,7 @@ class RectangleMethod extends NumericalIntegration * * where h = xᵢ₊₁ - xᵢ * note: this implementation does not compute the error term. - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php b/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php index aba2f456c..1861523da 100644 --- a/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/SimpsonsRule.php @@ -62,7 +62,7 @@ class SimpsonsRule extends NumericalIntegration * ⁱ⁼¹ 3 * where h = (xn - x₁) / (n - 1) * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php b/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php index a19d656c2..30d37510e 100644 --- a/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/SimpsonsThreeEighthsRule.php @@ -63,7 +63,7 @@ class SimpsonsThreeEighthsRule extends NumericalIntegration * ⁱ⁼¹ 8 * where h = (xn - x₁) / (n - 1) * - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php b/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php index e0f597dbc..66dda5fc0 100644 --- a/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php +++ b/src/NumericalAnalysis/NumericalIntegration/TrapezoidalRule.php @@ -59,7 +59,7 @@ class TrapezoidalRule extends NumericalIntegration * * where h = xᵢ₊₁ - xᵢ * note: this implementation does not compute the error term. - * @param callable|array $source + * @param callable|array $source * The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. diff --git a/src/NumericalAnalysis/NumericalIntegration/Validation.php b/src/NumericalAnalysis/NumericalIntegration/Validation.php index fb290a917..eb7a14542 100644 --- a/src/NumericalAnalysis/NumericalIntegration/Validation.php +++ b/src/NumericalAnalysis/NumericalIntegration/Validation.php @@ -14,7 +14,7 @@ class Validation * Ensures that the length of each subinterval is equal, or equivalently, * that the spacing between each point is equal * - * @param array> $sorted Points sorted by (increasing) x-component + * @param array> $sorted Points sorted by (increasing) x-component * * @throws Exception\BadDataException if the spacing between any two points is not equal to the average spacing between every point */ diff --git a/src/NumericalAnalysis/RootFinding/BisectionMethod.php b/src/NumericalAnalysis/RootFinding/BisectionMethod.php index 6360d533f..90e76e511 100644 --- a/src/NumericalAnalysis/RootFinding/BisectionMethod.php +++ b/src/NumericalAnalysis/RootFinding/BisectionMethod.php @@ -31,7 +31,7 @@ class BisectionMethod * @param int|float $b The end of the interval which contains a root * @param int|float $tol Tolerance; How close to the actual solution we would like. - * @return number + * @return int|float * * @throws Exception\OutOfBoundsException * @throws Exception\BadDataException diff --git a/src/NumericalAnalysis/RootFinding/FixedPointIteration.php b/src/NumericalAnalysis/RootFinding/FixedPointIteration.php index 678cd09df..b77e8ed6a 100644 --- a/src/NumericalAnalysis/RootFinding/FixedPointIteration.php +++ b/src/NumericalAnalysis/RootFinding/FixedPointIteration.php @@ -33,7 +33,7 @@ class FixedPointIteration * @param int|float $p The initial guess of our root, in [$a, $b] * @param int|float $tol Tolerance; How close to the actual solution we would like. - * @return number + * @return int|float * * @throws Exception\OutOfBoundsException * @throws Exception\BadDataException diff --git a/src/NumericalAnalysis/RootFinding/NewtonsMethod.php b/src/NumericalAnalysis/RootFinding/NewtonsMethod.php index 1a94effe5..77c03ac6e 100644 --- a/src/NumericalAnalysis/RootFinding/NewtonsMethod.php +++ b/src/NumericalAnalysis/RootFinding/NewtonsMethod.php @@ -25,7 +25,7 @@ class NewtonsMethod * @param int $position Which element in the $args array will be changed; also serves as initial guess * @param int $iterations * - * @return number + * @return int|float * * @throws Exception\OutOfBoundsException if the tolerance is not valid */ diff --git a/src/Probability/Distribution/Continuous/Beta.php b/src/Probability/Distribution/Continuous/Beta.php index eb3883fc5..c7a966d68 100644 --- a/src/Probability/Distribution/Continuous/Beta.php +++ b/src/Probability/Distribution/Continuous/Beta.php @@ -32,10 +32,10 @@ class Beta extends Continuous 'x' => '[0,1]', ]; - /** @var number Shape Parameter */ + /** @var int|float Shape Parameter */ protected $α; - /** @var number Shape Parameter */ + /** @var int|float Shape Parameter */ protected $β; /** diff --git a/src/Probability/Distribution/Continuous/Cauchy.php b/src/Probability/Distribution/Continuous/Cauchy.php index 941b73b29..109f94b2f 100644 --- a/src/Probability/Distribution/Continuous/Cauchy.php +++ b/src/Probability/Distribution/Continuous/Cauchy.php @@ -30,10 +30,10 @@ class Cauchy extends Continuous 'x' => '(-∞,∞)', ]; - /** @var number Location Parameter */ + /** @var int|float Location Parameter */ protected $x₀; - /** @var number Scale Parameter */ + /** @var int|float Scale Parameter */ protected $γ; /** diff --git a/src/Probability/Distribution/Continuous/Continuous.php b/src/Probability/Distribution/Continuous/Continuous.php index 60f1a19c5..9b9e1ab09 100644 --- a/src/Probability/Distribution/Continuous/Continuous.php +++ b/src/Probability/Distribution/Continuous/Continuous.php @@ -16,7 +16,7 @@ abstract class Continuous extends \MathPHP\Probability\Distribution\Distribution * @param float $target The area for which we are trying to find the $x * * @todo check the parameter ranges. - * @return number + * @return int|float */ public function inverse(float $target) { @@ -109,7 +109,7 @@ public function above(float $x): float /** * Produce a random number with a particular distribution * - * @return number + * @return float * * @throws \Exception */ @@ -119,7 +119,7 @@ public function rand() } /** - * @return number + * @return int|float */ abstract public function median(); } diff --git a/src/Probability/Distribution/Continuous/ContinuousDistribution.php b/src/Probability/Distribution/Continuous/ContinuousDistribution.php index c4426a82d..20c0aea61 100644 --- a/src/Probability/Distribution/Continuous/ContinuousDistribution.php +++ b/src/Probability/Distribution/Continuous/ContinuousDistribution.php @@ -21,14 +21,14 @@ public function pdf(float $x); * * @param float $x * - * @return mixed + * @return int|float */ public function cdf(float $x); /** * Mean average * - * @return number + * @return int|float */ public function mean(); } diff --git a/src/Probability/Distribution/Continuous/Normal.php b/src/Probability/Distribution/Continuous/Normal.php index 6bb536987..43462c345 100644 --- a/src/Probability/Distribution/Continuous/Normal.php +++ b/src/Probability/Distribution/Continuous/Normal.php @@ -169,6 +169,8 @@ public function variance(): float * Random number - Box–Muller transform * * https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + * + * @return float */ public function rand() { diff --git a/src/Probability/Distribution/Discrete/Categorical.php b/src/Probability/Distribution/Discrete/Categorical.php index ae08fc3af..4c2c2cf2d 100644 --- a/src/Probability/Distribution/Discrete/Categorical.php +++ b/src/Probability/Distribution/Discrete/Categorical.php @@ -20,7 +20,7 @@ class Categorical extends Discrete private $k; /** - * @var array + * @var array * Probability of each category * If associative array, category names are keys. * Otherwise, category names are array indexes. @@ -31,7 +31,7 @@ class Categorical extends Discrete * Distribution constructor * * @param int $k number of categories - * @param array $probabilities of each category - If associative array, category names are keys. + * @param array $probabilities of each category - If associative array, category names are keys. * Otherwise, category names are array indexes. * * @throws Exception\BadParameterException if k does not indicate at least one category @@ -66,7 +66,7 @@ public function __construct(int $k, array $probabilities) * * pmf = p(x = i) = pᵢ * - * @param string|number $x category name/number + * @param int|float $x category name/number * * @return float * diff --git a/src/Probability/Distribution/Discrete/Zipf.php b/src/Probability/Distribution/Discrete/Zipf.php index 78ecc794e..ca47c2979 100644 --- a/src/Probability/Distribution/Discrete/Zipf.php +++ b/src/Probability/Distribution/Discrete/Zipf.php @@ -33,7 +33,7 @@ class Zipf extends Discrete 'k' => '[1,∞)', ]; - /** @var number Characterizing exponent */ + /** @var int|float Characterizing exponent */ protected $s; /** @var int Number of elements */ @@ -59,7 +59,7 @@ public function __construct($s, int $N) * * @param int $k * - * @return number + * @return int|float * * @throws Exception\OutOfBoundsException if k is > N */ @@ -86,7 +86,7 @@ public function pmf(int $k) * * @param int $k * - * @return number + * @return int|float * * @throws Exception\OutOfBoundsException if k is > N */ @@ -112,7 +112,7 @@ public function cdf(int $k) * μ = --------- * Hₙ,ₛ * - * @return number + * @return int|float */ public function mean() { @@ -131,7 +131,7 @@ public function mean() * * μ = 1 * - * @return number + * @return int|float */ public function mode() { diff --git a/src/Probability/Distribution/Multivariate/Hypergeometric.php b/src/Probability/Distribution/Multivariate/Hypergeometric.php index 9b79d3f17..90d00f693 100644 --- a/src/Probability/Distribution/Multivariate/Hypergeometric.php +++ b/src/Probability/Distribution/Multivariate/Hypergeometric.php @@ -29,13 +29,13 @@ class Hypergeometric */ protected $supportLimits = []; - /** @var array */ + /** @var array */ protected $quantities; /** * Multivariate Hypergeometric constructor * - * @param array $quantities + * @param array $quantities * * @throws Exception\BadDataException if the quantities are not positive integers. */ @@ -57,7 +57,7 @@ public function __construct(array $quantities) /** * Probability mass function * - * @param array $picks + * @param array $picks * * @return float * diff --git a/src/Probability/Distribution/Multivariate/Multinomial.php b/src/Probability/Distribution/Multivariate/Multinomial.php index 9c0ab6696..33f13f944 100644 --- a/src/Probability/Distribution/Multivariate/Multinomial.php +++ b/src/Probability/Distribution/Multivariate/Multinomial.php @@ -12,13 +12,13 @@ */ class Multinomial { - /** @var array */ + /** @var array */ protected $probabilities; /** * Multinomial constructor * - * @param array $probabilities + * @param array $probabilities * * @throws Exception\BadDataException if the probabilities do not add up to 1 */ diff --git a/src/Probability/Distribution/Multivariate/Normal.php b/src/Probability/Distribution/Multivariate/Normal.php index 91ce93516..8a5f122a6 100644 --- a/src/Probability/Distribution/Multivariate/Normal.php +++ b/src/Probability/Distribution/Multivariate/Normal.php @@ -14,7 +14,7 @@ */ class Normal { - /** @var array location */ + /** @var array location */ protected $μ; /** @var NumericMatrix covariance matrix */ @@ -23,7 +23,7 @@ class Normal /** * Constructor * - * @param array $μ ∈ Rᵏ location + * @param array $μ ∈ Rᵏ location * @param NumericMatrix $∑ ∈ Rᵏˣᵏ covariance matrix * * @throws Exception\BadDataException if the covariance matrix does not have the same number of rows and columns as number of elements in μ @@ -56,7 +56,7 @@ public function __construct(array $μ, NumericMatrix $∑) * μ is a real k-dimensinoal column vector of means * │∑│ ≡ det(∑) * - * @param array $X ∈ Rᵏ k-dimensional random vector + * @param array $X ∈ Rᵏ k-dimensional random vector * * @return float density * diff --git a/src/Probability/Distribution/Table/ChiSquared.php b/src/Probability/Distribution/Table/ChiSquared.php index 9a1927a69..2e39315d1 100644 --- a/src/Probability/Distribution/Table/ChiSquared.php +++ b/src/Probability/Distribution/Table/ChiSquared.php @@ -312,7 +312,6 @@ class ChiSquared */ public static function getChiSquareValue(int $df, float $p): float { - // @phpstan-ignore-next-line (Offset numeric-string on array in isset() does not exist.) if (isset(self::CHI_SQUARED_SCORES[$df][\sprintf('%1.3f', $p)])) { return self::CHI_SQUARED_SCORES[$df][\sprintf('%1.3f', $p)]; } diff --git a/src/Probability/Distribution/Table/StandardNormal.php b/src/Probability/Distribution/Table/StandardNormal.php index 5ef642291..0a29a3851 100644 --- a/src/Probability/Distribution/Table/StandardNormal.php +++ b/src/Probability/Distribution/Table/StandardNormal.php @@ -120,7 +120,7 @@ public static function getZScoreProbability(float $Z): float } /** * @var string $z - * @var numeric $+0.0x + * @var int|float $+0.0x */ [$z, $+0.0x] = [ $matches[1], $matches[2] ]; return self::Z_SCORES[$z][$+0.0x]; diff --git a/src/Probability/Distribution/Table/TDistribution.php b/src/Probability/Distribution/Table/TDistribution.php index 394f6a78e..a7c483590 100644 --- a/src/Probability/Distribution/Table/TDistribution.php +++ b/src/Probability/Distribution/Table/TDistribution.php @@ -9,7 +9,7 @@ * * Tables for one sided and two sided, * Initial index is degrees of freedom (ν). - * Second index is confidence level precentage, or alpha value (α). + * Second index is confidence level percentage, or alpha value (α). * * https://en.wikipedia.org/wiki/Student%27s_t-distribution#Table_of_selected_values * @@ -21,8 +21,8 @@ class TDistribution { /** * One-sided t distribution table - * Confidence level percentaces - * @var array> + * Confidence level percentages + * @var array> */ private const ONE_SIDED_CONFIDENCE_LEVEL = [ 1 => [ 0 => 0, 75 => 1.000, 80 => 1.376, 85 => 1.963, 90 => 3.078, 95 => 6.314, '97.5' => 12.71, 99 => 31.82, '99.5' => 63.66, '99.75' => 127.3, '99.9' => 318.3, '99.95' => 636.6 ], @@ -112,7 +112,7 @@ class TDistribution /** * Two-sided t distribution table * Confidence level percentaces - * @var array> + * @var array> */ private const TWO_SIDED_CONFIDENCE_LEVEL = [ 1 => [ 0 => 0, 50 => 1.000, 60 => 1.376, 70 => 1.963, 80 => 3.078, 90 => 6.314, 95 => 12.71, 98 => 31.82, 99 => 63.66, '99.5' => 127.3, '99.8' => 318.3, '99.9' => 636.6 ], @@ -157,7 +157,7 @@ class TDistribution /** * Two-sided t distribution table * Alphas - * @var array> + * @var array> */ private const TWO_SIDED_ALPHA = [ 1 => [ '1.00' => 0, '0.50' => 1.000, '0.40' => 1.376, '0.30' => 1.963, '0.20' => 3.078, '0.10' => 6.314, '0.05' => 12.71, '0.02' => 31.82, '0.01' => 63.66, '0.005' => 127.3, '0.002' => 318.3, '0.001' => 636.6 ], diff --git a/src/SampleData/Cereal.php b/src/SampleData/Cereal.php index ab4f506c5..ea8568603 100644 --- a/src/SampleData/Cereal.php +++ b/src/SampleData/Cereal.php @@ -113,7 +113,7 @@ public function getCereals(): array * Raw data without labels * [[0.002682755, 0.003370673, 0.004085942, ... ], [0.002781597, 0.003474863, 0.004191472, ... ], ... ] * - * @return number[][] + * @return float[][] */ public function getXData(): array { @@ -124,11 +124,11 @@ public function getXData(): array * Raw data with each observation labeled * ['B1' => ['X1126.0' => 0.002682755, 'X1134.0' => 0.003370673, 'X1142.0' => 0.004085942, ... ]] * - * @return array> + * @return array> */ public function getLabeledXData(): array { - /** @var array> */ + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::X_LABELS, $data); @@ -141,7 +141,7 @@ function (array $data) { * Raw data without labels * [[18373, 41.61500, 6.565000, ... ], [18536, 41.40500, 6.545000, ... ], ... ] * - * @return number[][] + * @return float[][] */ public function getYData(): array { @@ -152,11 +152,11 @@ public function getYData(): array * Raw data with each observation labeled * ['B1' => ['Heating value' => 18373, 'C' => 41.61500, 'H' => 6.565000, ... ]] * - * @return array> + * @return array> */ public function getLabeledYData(): array { - /** @var array> */ + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::Y_LABELS, $data); @@ -169,7 +169,7 @@ function (array $data) { * Raw data without labels * [[-0.1005049, 0.6265746, -1.1716630, ... ], [0.9233889, 0.1882929, -1.3185289, ... ], ... ] * - * @return number[][] + * @return float[][] */ public function getYscData(): array { diff --git a/src/SampleData/Iris.php b/src/SampleData/Iris.php index 8eb2a7741..81faeeb4a 100644 --- a/src/SampleData/Iris.php +++ b/src/SampleData/Iris.php @@ -187,11 +187,11 @@ public function getData(): array * Raw data with each observation labeled * [['sepalLength' => 5.11, 'sepalWidth' => 3.5, 'petalLength' => 1.4, 'petalWidth' => 0.2, 'species' => 'setosa'], ... ] * - * @return array> + * @return array> */ public function getLabeledData(): array { - /** @var array> */ + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::LABELS, $data); @@ -203,7 +203,7 @@ function (array $data) { /** * Sepal length observations * - * @return number[] + * @return float[] */ public function getSepalLength(): array { @@ -213,7 +213,7 @@ public function getSepalLength(): array /** * Sepal width observations * - * @return number[] + * @return float[] */ public function getSepalWidth(): array { @@ -223,7 +223,7 @@ public function getSepalWidth(): array /** * Petal length observations * - * @return number[] + * @return float[] */ public function getPetalLength(): array { @@ -233,7 +233,7 @@ public function getPetalLength(): array /** * Petal width observations * - * @return number[] + * @return float[] */ public function getPetalWidth(): array { diff --git a/src/SampleData/MtCars.php b/src/SampleData/MtCars.php index 6c267e9aa..718224208 100644 --- a/src/SampleData/MtCars.php +++ b/src/SampleData/MtCars.php @@ -56,7 +56,7 @@ class MtCars * Raw data without labels * [[21, 6, 160, ... ], [30.4, 4, 71.1, ... ], ... ] * - * @return number[][] + * @return int[][]|float[][] */ public function getData(): array { @@ -67,11 +67,11 @@ public function getData(): array * Raw data with each observation labeled * ['Car Model' => ['mpg' => 21, 'cyl' => 6, 'disp' => 160, ... ]] * - * @return array> + * @return array> */ public function getLabeledData(): array { - /** @var array> */ + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::LABELS, $data); @@ -96,11 +96,11 @@ public function getModels(): array * * @param string $model * - * @return array + * @return array */ public function getModelData(string $model): array { - /** @var array */ + /** @var array */ return \array_combine(self::LABELS, self::DATA[$model]); } @@ -108,11 +108,11 @@ public function getModelData(string $model): array * Miles per gallon observations for all models * ['Mazda RX4' => 21, 'Honda civic' => 30.4, ... ] * - * @return array + * @return array */ public function getMpg(): array { - /** @var array */ + /** @var array */ return \array_combine($this->getModels(), \array_column(self::DATA, 0)); } @@ -120,7 +120,7 @@ public function getMpg(): array * Number of cylinders observations for all models * ['Mazda RX4' => 6, 'Honda civic' => 4, ... ] * - * @return number[] + * @return int[] */ public function getCyl(): array { @@ -131,7 +131,7 @@ public function getCyl(): array * Displacement (cubic inches) observations for all models * ['Mazda RX4' => 160, 'Honda civic' => 75.7, ... ] * - * @return number[] + * @return int[]|float[] */ public function getDisp(): array { @@ -142,7 +142,7 @@ public function getDisp(): array * Gross horsepower observations for all models * ['Mazda RX4' => 110, 'Honda civic' => 52, ... ] * - * @return number[] + * @return int[] */ public function getHp(): array { @@ -153,7 +153,7 @@ public function getHp(): array * Rear axle ratio observations for all models * ['Mazda RX4' => 3.9, 'Honda civic' => 4.93, ... ] * - * @return number[] + * @return float[] */ public function getDrat(): array { @@ -164,7 +164,7 @@ public function getDrat(): array * Weight (1,000 pounds) observations for all models * ['Mazda RX4' => 2.62, 'Honda civic' => 1.615, ... ] * - * @return number[] + * @return float[] */ public function getWt(): array { @@ -175,7 +175,7 @@ public function getWt(): array * Quarter-mile time observations for all models * ['Mazda RX4' => 16.46, 'Honda civic' => 18.52, ... ] * - * @return number[] + * @return float[] */ public function getQsec(): array { @@ -186,7 +186,7 @@ public function getQsec(): array * V/S observations for all models * ['Mazda RX4' => 0, 'Honda civic' => 1, ... ] * - * @return number[] + * @return int[] */ public function getVs(): array { @@ -197,7 +197,7 @@ public function getVs(): array * Transmission (automatic: 0, manual: 1) observations for all models * ['Mazda RX4' => 1, 'Honda civic' => 1, ... ] * - * @return number[] + * @return int[] */ public function getAm(): array { @@ -208,7 +208,7 @@ public function getAm(): array * Number of forward gears observations for all models * ['Mazda RX4' => 4, 'Honda civic' => 4, ... ] * - * @return number[] + * @return int[] */ public function getGear(): array { @@ -219,7 +219,7 @@ public function getGear(): array * Number of carburetors observations for all models * ['Mazda RX4' => 4, 'Honda civic' => 2, ... ] * - * @return number[] + * @return int[] */ public function getCarb(): array { diff --git a/src/SampleData/PlantGrowth.php b/src/SampleData/PlantGrowth.php index c449e10eb..19458a056 100644 --- a/src/SampleData/PlantGrowth.php +++ b/src/SampleData/PlantGrowth.php @@ -65,11 +65,11 @@ public function getData(): array * Raw data with each observation labeled * [['weight' => 4.17, 'group' => 'ctrl'], ['weight' => 5.58, 'group' => 'ctrl'], ... ] * - * @return array> + * @return array> */ public function getLabeledData(): array { - /** @var array> */ + /** @var array> */ return \array_map( function (array $data) { return \array_combine(self::LABELS, $data); @@ -81,7 +81,7 @@ function (array $data) { /** * Weight observations * - * @return number[] + * @return float[] */ public function getWeight(): array { diff --git a/src/SampleData/ToothGrowth.php b/src/SampleData/ToothGrowth.php index d786630b5..2cbbdda1d 100644 --- a/src/SampleData/ToothGrowth.php +++ b/src/SampleData/ToothGrowth.php @@ -111,7 +111,7 @@ function (array $data) { /** * Tooth length observations * - * @return number[] + * @return float[] */ public function getLen(): array { @@ -131,7 +131,7 @@ public function getSupp(): array /** * Dose in milligrams/day observations * - * @return number[] + * @return float[] */ public function getDose(): array { diff --git a/src/SampleData/UsArrests.php b/src/SampleData/UsArrests.php index 1cae07a97..80e538cbc 100644 --- a/src/SampleData/UsArrests.php +++ b/src/SampleData/UsArrests.php @@ -74,7 +74,7 @@ class UsArrests * Raw data without labels * [[13.2, 236, 58, 21.2], [10.0, 263, 48, 44.5], ... ] * - * @return number[][] + * @return int[][]|float[][] */ public function getData(): array { @@ -85,13 +85,13 @@ public function getData(): array * Raw data with each observation labeled * ['Alabama' => ['murder' => 13.2, 'assault' => 236, 'urbanPop' => 58, 'rape' => 21.2], ... ] * - * @return array> + * @return array> */ public function getLabeledData(): array { return \array_map( function (array $data) { - /** @var array */ + /** @var array */ return \array_combine(self::LABELS, $data); }, self::DATA @@ -99,7 +99,7 @@ function (array $data) { } /** - * State names names + * State names * * @return string[] */ @@ -114,11 +114,11 @@ public function getStates(): array * * @param string $state * - * @return number[] + * @return int[]|float[] */ public function getStateData(string $state): array { - /** @var array */ + /** @var array */ return \array_combine(self::LABELS, self::DATA[$state]); } diff --git a/src/SetTheory/ImmutableSet.php b/src/SetTheory/ImmutableSet.php index d44fe0f1f..5513e91a5 100644 --- a/src/SetTheory/ImmutableSet.php +++ b/src/SetTheory/ImmutableSet.php @@ -37,11 +37,11 @@ public function add($x): Set /** * Cannot add members to an immutable set * - * @param array $x + * @param array $members * * @return Set (this set unchanged) */ - public function addMulti(array $x): Set + public function addMulti(array $members): Set { return $this; } diff --git a/src/SetTheory/Set.php b/src/SetTheory/Set.php index 735f3ae45..c9e4f68ab 100644 --- a/src/SetTheory/Set.php +++ b/src/SetTheory/Set.php @@ -265,7 +265,7 @@ protected function getKey($x): ?string } elseif (\is_array($x)) { return 'Array(' . serialize($x) . ')'; } elseif (\is_resource($x)) { - return 'Resource(' . \strval($x) . ')'; + return 'Resource(' . $x . ')'; } return null; diff --git a/src/Statistics/Average.php b/src/Statistics/Average.php index a8f377d92..64ee57a01 100644 --- a/src/Statistics/Average.php +++ b/src/Statistics/Average.php @@ -721,9 +721,9 @@ public static function cumulativeMovingAverage(array $numbers): array * * Each weighted average = ∑(weighted values) / ∑(weights) * - * @param array $numbers - * @param int $n n-point moving average - * @param array $weights Weights for each n points + * @param array $numbers + * @param int $n n-point moving average + * @param array $weights Weights for each n points * * @return array of averages * @@ -757,8 +757,8 @@ public static function weightedMovingAverage(array $numbers, int $n, array $weig * where * α: coefficient that represents the degree of weighting decrease, a constant smoothing factor between 0 and 1. * - * @param array $numbers - * @param int $n Length of the EPA + * @param array $numbers + * @param int $n Length of the EPA * * @return array of exponential moving averages */ diff --git a/src/Statistics/Correlation.php b/src/Statistics/Correlation.php index 196a20bab..e3f563567 100644 --- a/src/Statistics/Correlation.php +++ b/src/Statistics/Correlation.php @@ -471,8 +471,8 @@ function ($x, $y) { * cov(rgᵪ, rgᵧ): covariance of the rank variables * σᵣᵪ and σᵣᵧ: standard deviations of the rank variables * - * @param array $X values for random variable X - * @param array $Y values for random variable Y + * @param array $X values for random variable X + * @param array $Y values for random variable Y * * @return float * @@ -538,7 +538,7 @@ public static function describe(array $X, array $Y, bool $population = false): a * will be one larger because the first point and last will be repeated * to ease display. * - * @return array> paired x and y points on an ellipse aligned with the data provided + * @return array> paired x and y points on an ellipse aligned with the data provided * * @throws Exception\BadDataException * @throws Exception\BadParameterException diff --git a/src/Statistics/Descriptive.php b/src/Statistics/Descriptive.php index 9e7a35378..e7bd102ae 100644 --- a/src/Statistics/Descriptive.php +++ b/src/Statistics/Descriptive.php @@ -739,7 +739,7 @@ public static function describe(array $numbers, bool $population = false): array * * https://en.wikipedia.org/wiki/Five-number_summary * - * @param array $numbers + * @param array $numbers * * @return array{ * min: float|int|false, diff --git a/src/Statistics/Distance.php b/src/Statistics/Distance.php index 709ee55c8..8b569a6d7 100644 --- a/src/Statistics/Distance.php +++ b/src/Statistics/Distance.php @@ -49,8 +49,8 @@ class Distance * BC(p,q) = ∑ √(p(x) q(x)) * x∈X * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float distance between distributions * @@ -84,8 +84,8 @@ public static function bhattacharyya(array $p, array $q): float * H(P,Q) = -- √ ∑ (√pᵢ - √qᵢ)² * √2 * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float difference between distributions * @@ -146,8 +146,8 @@ function ($pᵢ, $qᵢ) { * * D(P‖Q) = Kullback-Leibler divergence * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float * diff --git a/src/Statistics/Distribution.php b/src/Statistics/Distribution.php index cca1c09bd..8c7d74fe2 100644 --- a/src/Statistics/Distribution.php +++ b/src/Statistics/Distribution.php @@ -109,7 +109,7 @@ function ($frequency) use ($sample_size) { * * Similar to R: rank(values, ties.method='average') * - * @param array $values to be ranked + * @param array $values to be ranked * * @return array Rankings of the data in the same order the values were input */ @@ -148,7 +148,7 @@ function ($value) use ($rg⟮X⟯) { * * Similar to R: rank(values, ties.method='min') * - * @param array $values to be ranked + * @param array $values to be ranked * * @return array Rankings of the data in the same order the values were input */ @@ -184,7 +184,7 @@ function ($value) use ($ranking⟮X⟯) { * * Similar to R: rank(values, ties.method='max') * - * @param array $values to be ranked + * @param array $values to be ranked * * @return array Rankings of the data in the same order the values were input */ @@ -221,7 +221,7 @@ function ($value) use ($ranking⟮X⟯) { * * Similar to R: rank(values, ties.method='first') * - * @param array $values to be ranked + * @param array $values to be ranked * * @return array Rankings of the data in the same order the values were input */ diff --git a/src/Statistics/Divergence.php b/src/Statistics/Divergence.php index 7162c768a..e387f51ae 100644 --- a/src/Statistics/Divergence.php +++ b/src/Statistics/Divergence.php @@ -35,8 +35,8 @@ class Divergence * * * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float difference between distributions * @@ -99,8 +99,8 @@ function ($P, $Q) { * * D(P‖Q) = Kullback-Leibler divergence * - * @param array $p distribution p - * @param array $q distribution q + * @param array $p distribution p + * @param array $q distribution q * * @return float difference between distributions * diff --git a/src/Statistics/Regression/LOESS.php b/src/Statistics/Regression/LOESS.php index 6fa1b7d0b..9f963d4aa 100644 --- a/src/Statistics/Regression/LOESS.php +++ b/src/Statistics/Regression/LOESS.php @@ -19,7 +19,7 @@ class LOESS extends NonParametricRegression /** * Smoothness parameter - * @var number + * @var int|float */ protected $α; diff --git a/src/Statistics/Regression/Methods/LeastSquares.php b/src/Statistics/Regression/Methods/LeastSquares.php index 74677052d..dfd922b55 100644 --- a/src/Statistics/Regression/Methods/LeastSquares.php +++ b/src/Statistics/Regression/Methods/LeastSquares.php @@ -188,7 +188,7 @@ public function getProjectionMatrix(): NumericMatrix * which is the i-th diagonal element of the project matrix H, * where H = X⟮XᵀX⟯⁻¹Xᵀ where X is the design matrix. * - * @return array + * @return array */ public function leverages(): array { diff --git a/src/Statistics/Significance.php b/src/Statistics/Significance.php index f91899df6..e3cded5ca 100644 --- a/src/Statistics/Significance.php +++ b/src/Statistics/Significance.php @@ -219,7 +219,6 @@ public static function tTest(array $a, $b): array return self::tTestTwoSample($a, $b); } - // @phpstan-ignore-next-line (Unreachable statement - code above always terminates.) throw new Exception\BadParameterException('Second parameter must be numeric for one-sample t-test, or an array for two-sample t-test'); } diff --git a/tests/LinearAlgebra/Matrix/MatrixFactoryTest.php b/tests/LinearAlgebra/Matrix/MatrixFactoryTest.php index bb998bb08..8b2a41a85 100644 --- a/tests/LinearAlgebra/Matrix/MatrixFactoryTest.php +++ b/tests/LinearAlgebra/Matrix/MatrixFactoryTest.php @@ -339,6 +339,22 @@ public function testCheckParamsExceptionEmptyArray() $M = MatrixFactory::create($A); } + /** + * @test check params exception for single dimensional array + * @throws \Exception + */ + public function testCheckParamsExceptionSingleDimensionalArray() + { + // Given + $A = [1, 2, 3]; + + // Then + $this->expectException(Exception\BadDataException::class); + + // When + $M = MatrixFactory::create($A); + } + /** * @test matrix unknown type exception * @throws \Exception diff --git a/tests/phpstan.neon b/tests/phpstan.neon new file mode 100644 index 000000000..6344674e3 --- /dev/null +++ b/tests/phpstan.neon @@ -0,0 +1,5 @@ +parameters: + level: max + paths: + - ../src + treatPhpDocTypesAsCertain: false From ea4f212732c333c62123c6f733edfb735a4e3abd Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Thu, 18 May 2023 21:40:46 -0700 Subject: [PATCH 53/66] Update CHANGELOG for v2.8.1. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebabe823e..215cde3b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # MathPHP Change Log +## v2.8.1 - 2023-05-18 + +### Improvements +* Internal improvements to improve conformance with static analysis tools + ## v2.8.0 - 2023-05-07 ### New Features From da47751ed3bbf7fcd6406737b572159429b3a94a Mon Sep 17 00:00:00 2001 From: Sam <40273116+Aweptimum@users.noreply.github.com> Date: Tue, 7 Nov 2023 21:31:58 -0600 Subject: [PATCH 54/66] Replace array_search with floating-point filter in `Eigenvector::eigenvectors` (#473) * Test Eigenvectors can handle numerical imprecision To mimic the error found in the QR algorithm, we have to test with matrices that have duplicate eigenvalues and introduce numerical precision errors. To do this, a list of perturbed eigenvalues is passed to the eigenvectors method. The perturbation is achieved by adding a random +/- offset on an order of magnitude smaller than the default matrix error. This should allow the math to work out fine while causing the floating point comparison to fail. * Replace array_search with floating-point filter array_search seems to fail in most cases when looking for a float in an array of floats. And even if it does find a match, if the key is 0, php evaluates `!0` to true. To find a match, we can instead loop through and compare the numbers with `Arithmetic::almostEqual` and then explicitly check if `$key === false` --- src/LinearAlgebra/Eigenvector.php | 11 +++- tests/LinearAlgebra/Eigen/EigenvectorTest.php | 57 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/LinearAlgebra/Eigenvector.php b/src/LinearAlgebra/Eigenvector.php index abed66e87..de9c8de63 100644 --- a/src/LinearAlgebra/Eigenvector.php +++ b/src/LinearAlgebra/Eigenvector.php @@ -2,6 +2,7 @@ namespace MathPHP\LinearAlgebra; +use MathPHP\Arithmetic; use MathPHP\Exception; use MathPHP\Exception\MatrixException; use MathPHP\Functions\Map\Single; @@ -66,8 +67,14 @@ public static function eigenvectors(NumericMatrix $A, array $eigenvalues = []): foreach ($eigenvalues as $eigenvalue) { // If this is a duplicate eigenvalue, and this is the second instance, the first // pass already found all the vectors. - $key = \array_search($eigenvalue, \array_column($solution_array, 'eigenvalue')); - if (!$key) { + $key = false; + foreach (\array_column($solution_array, 'eigenvalue') as $i => $v) { + if (Arithmetic::almostEqual($v, $eigenvalue, $A->getError())) { + $key = $i; + break; + } + } + if ($key === false) { $Iλ = MatrixFactory::identity($number)->scalarMultiply($eigenvalue); $T = $A->subtract($Iλ); diff --git a/tests/LinearAlgebra/Eigen/EigenvectorTest.php b/tests/LinearAlgebra/Eigen/EigenvectorTest.php index 0a6e52817..b57cddd86 100644 --- a/tests/LinearAlgebra/Eigen/EigenvectorTest.php +++ b/tests/LinearAlgebra/Eigen/EigenvectorTest.php @@ -131,6 +131,63 @@ public function dataProviderForEigenvector(): array ]; } + /** + * @test eigenvector can handle numerical precision errors + * @dataProvider dataProviderForPerturbedEigenvalues + * @param array $A + * @param array $E + * @param array $S + */ + public function testEigenvectorsPerturbedEigenvalues(array $A, array $E, array $S) + { + // Perturb E + foreach ($E as $i => $component) { + $E[$i] = $component + (random_int(-1, 1) * 10**-12); + } + + // Given + $A = MatrixFactory::create($A); + $S = MatrixFactory::create($S); + + // When + $eigenvectors = Eigenvector::eigenvectors($A, $E); + + // Then + $this->assertEqualsWithDelta($S, $eigenvectors, 0.0001); + } + + public function dataProviderForPerturbedEigenvalues(): array + { + return [ + [ // Matrix has duplicate eigenvalues. One vector is on an axis. + [ + [2, 0, 1], + [2, 1, 2], + [3, 0, 4], + ], + [5, 1, 1], + [ + [1 / \sqrt(14), 0, \M_SQRT1_2], + [2 / \sqrt(14), 1, 0], + [3 / \sqrt(14), 0, -1 * \M_SQRT1_2], + ] + ], + [ // Matrix has duplicate eigenvalues. no solution on the axis + [ + [2, 2, -3], + [2, 5, -6], + [3, 6, -8], + ], + [-3, 1, 1], + [ + [1 / \sqrt(14), 1 / \M_SQRT3, 5 / \sqrt(42)], + [2 / \sqrt(14), 1 / \M_SQRT3, -4 / \sqrt(42)], + [3 / \sqrt(14), 1 / \M_SQRT3, -1 / \sqrt(42)], + ] + ], + ]; + } + /** * @test eigenvectors throws a BadDataException when the matrix is not square */ From 5d133856437f5943d93ac512da27a97ccbe66b7c Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 2 Mar 2024 14:28:04 -0800 Subject: [PATCH 55/66] Update Github actions for PHP 8.3. --- .github/workflows/test_develop_and_master.yml | 20 +++++++++---------- .github/workflows/test_other_branches.yml | 14 ++++++------- .github/workflows/test_pull_request.yml | 20 +++++++++---------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index 3fdc2ffdf..f277c5110 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] steps: - name: Set up PHP @@ -23,12 +23,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -74,12 +74,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -107,12 +107,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index a4cef9afd..9ec7bdbc0 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] steps: - name: Set up PHP @@ -22,12 +22,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -73,12 +73,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index 957cad081..05830e704 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] steps: - name: Set up PHP @@ -19,12 +19,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -70,12 +70,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -103,12 +103,12 @@ jobs: tools: composer:v2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '14.x' + node-version: '20.x' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 From cc0d818b9782ed4cb85ceb18df3c4f8e5ab49b67 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 2 Mar 2024 15:44:15 -0800 Subject: [PATCH 56/66] Add Chebyshev Distance. --- src/Statistics/Distance.php | 31 ++++++++++ tests/Statistics/DistanceTest.php | 94 +++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/src/Statistics/Distance.php b/src/Statistics/Distance.php index 8b569a6d7..553163da8 100644 --- a/src/Statistics/Distance.php +++ b/src/Statistics/Distance.php @@ -470,4 +470,35 @@ function (float $|pᵢ − qᵢ|, float $|pᵢ| + |qᵢ|) { $|p| + |q| )); } + + /** + * Chebyshev Distance + * A metric defined on a real coordinate space where the distance between two points + * is the greatest of their differences along any coordinate dimension. + * + * D(x, y) = max(|xᵢ − yᵢ|) + * + * https://en.wikipedia.org/wiki/Chebyshev_distance + * + * @param array $xs + * @param array $ys + * + * @return float + * + * @throws Exception\BadDataException + */ + public static function chebyshev(array $xs, array $ys): float + { + if (\count($xs) !== \count($ys)) { + throw new Exception\BadDataException('xs and ys must have the same number of elements'); + } + + return \max(\array_map( + function (float $xᵢ, $yᵢ) { + return \abs($xᵢ - $yᵢ); + }, + $xs, + $ys + )); + } } diff --git a/tests/Statistics/DistanceTest.php b/tests/Statistics/DistanceTest.php index 6de04b048..264b76713 100644 --- a/tests/Statistics/DistanceTest.php +++ b/tests/Statistics/DistanceTest.php @@ -1252,4 +1252,98 @@ public function testCanberraExceptionDifferentNumberElements() // When $distance = Distance::canberra($p, $q); } + + /** + * @test chebyshev + * @dataProvider dataProviderForChebyshev + * @param array $x + * @param array $y + * @param float $expected + */ + public function testChebyshev(array $x, array $y, float $expected): void + { + // When + $distance = Distance::chebyshev($x, $y); + + // Then + $this->assertEqualsWithDelta($expected, $distance, 0.0001); + } + + public function dataProviderForChebyshev(): array + { + return [ + [ + [0], + [0], + 0 + ], + [ + [1], + [1], + 0 + ], + [ + [1], + [0], + 1 + ], + [ + [0], + [1], + 1 + ], + [ + [1, 2], + [2, 4], + 2 + ], + [ + [1, 2, 3], + [2, 4, 6], + 3 + ], + [ + [0, 3, 4, 5], + [7, 6, 3, -1], + 7 + ], + [ + [1, 2, 3, 4], + [-5, -6, 7, 8], + 8 + ], + [ + [1, 5, 2, 3, 10], + [4, 15, 20, 5, 5], + 18 + ], + [ + [1, 5, 2, 3, 10], + [1, 5, 2, 3, 10], + 0 + ], + [ + [4, 15, 20, 5, 5], + [4, 15, 20, 5, 5], + 0 + ], + ]; + } + + /** + * @test chebyshev exception when inputs are different lengths + * @throws Exception\BadDataException + */ + public function testChebyshevExceptionDifferentNumberElements() + { + // Given + $xs = [1, 2, 3]; + $ys = [2, 3]; + + // Then + $this->expectException(Exception\BadDataException::class); + + // When + Distance::chebyshev($xs, $ys); + } } From ae967a3f831f25bc9f8d244e0b592963aea31733 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 2 Mar 2024 15:49:13 -0800 Subject: [PATCH 57/66] Add Chebyshev distance to README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 71a125b8e..3fa7f9b42 100644 --- a/README.md +++ b/README.md @@ -2266,6 +2266,7 @@ $d⟮X、Y⟯ = Distance::canberra($X, Y); brayCurtis = Distance::brayCurtis($X, $Y); $cosine = Distance::cosine($X, $Y); $cos⟮α⟯ = Distance::cosineSimilarity($X, $Y); +$D⟮X、Y⟯ = Distance::chebyshev($X, $Y); // Mahalanobis distance $x = new Matrix([[6], [5]]); From 20fd81675427003ce9ce494b44c3e63dd5566eca Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 2 Mar 2024 15:54:19 -0800 Subject: [PATCH 58/66] Add cast for legacy max behavior returning boolean. --- src/Statistics/Distance.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Statistics/Distance.php b/src/Statistics/Distance.php index 553163da8..b292b6f6a 100644 --- a/src/Statistics/Distance.php +++ b/src/Statistics/Distance.php @@ -493,7 +493,7 @@ public static function chebyshev(array $xs, array $ys): float throw new Exception\BadDataException('xs and ys must have the same number of elements'); } - return \max(\array_map( + return (float) \max(\array_map( function (float $xᵢ, $yᵢ) { return \abs($xᵢ - $yᵢ); }, From 9989b9257ba5a39d43437edebb8b5f6fe9ee1837 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 2 Mar 2024 16:20:58 -0800 Subject: [PATCH 59/66] Update documentation. --- src/Statistics/Distance.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Statistics/Distance.php b/src/Statistics/Distance.php index b292b6f6a..ab2875a83 100644 --- a/src/Statistics/Distance.php +++ b/src/Statistics/Distance.php @@ -23,6 +23,7 @@ * - Cosine similarity * - Bray Curtis * - Canberra + * - Chebyshev * * In statistics, probability theory, and information theory, a statistical distance quantifies the distance between * two statistical objects, which can be two random variables, or two probability distributions or samples, or the From 4d4bfad5cd5f2d5dd851fc2c350438325776593c Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sat, 2 Mar 2024 16:21:15 -0800 Subject: [PATCH 60/66] Update CHANGELOG for v2.9.0. --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 215cde3b5..b8891cbec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # MathPHP Change Log +## v2.9.0 - 2024-03-02 + +### New Features +* Distance `chebyshev` + +### Improvements +* Internal build CI/CD improvements + ## v2.8.1 - 2023-05-18 ### Improvements From 70def3f06d1b98898ed3e2800e2c85b8c106cc3f Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Mon, 15 Apr 2024 22:05:25 -0700 Subject: [PATCH 61/66] Add Integer::isPrime. --- src/NumberTheory/Integer.php | 33 + tests/NumberTheory/IntegerAxiomsTest.php | 16 + tests/NumberTheory/IntegerIsPrimeTest.php | 826 ++++++++++++++++++++++ 3 files changed, 875 insertions(+) create mode 100644 tests/NumberTheory/IntegerIsPrimeTest.php diff --git a/src/NumberTheory/Integer.php b/src/NumberTheory/Integer.php index 8695af2aa..02701aa8e 100644 --- a/src/NumberTheory/Integer.php +++ b/src/NumberTheory/Integer.php @@ -349,6 +349,39 @@ function ($m) use ($√n) { return []; } + /** + * Primality test (prime number test) + * https://en.wikipedia.org/wiki/Primality_test + * + * Determines whether a number is a prime number. + * + * @param int $n + * + * @return bool + */ + public static function isPrime(int $n): bool + { + if ($n <= 1) { + return false; + } + + if ($n === 2 || $n === 3) { + return true; + } + + if ($n % 2 === 0 || $n % 3 === 0) { + return false; + } + + for ($i = 5; $i <= \sqrt($n); $i += 6) { + if ($n % $i === 0 || $n % ($i + 2) === 0) { + return false; + } + } + + return true; + } + /** * Prime factorization * The prime factors of an integer. diff --git a/tests/NumberTheory/IntegerAxiomsTest.php b/tests/NumberTheory/IntegerAxiomsTest.php index 79abffab4..1bfe1a8b4 100644 --- a/tests/NumberTheory/IntegerAxiomsTest.php +++ b/tests/NumberTheory/IntegerAxiomsTest.php @@ -15,6 +15,8 @@ * Axioms tested: * - Coprime * - lcm(a, b) = ab + * - Prime factorization + * - All primes */ class IntegerAxiomsTest extends \PHPUnit\Framework\TestCase { @@ -109,4 +111,18 @@ public function dataProviderForCoprime(): array [29, 30], ]; } + + /** + * Axiom: Prime factorization produces only primes + * @return void + */ + public function testPrimeFactorizationAllPrimes(): void + { + for ($i = 2; $i < 10000; $i++) { + $primes = Integer::primeFactorization($i); + foreach ($primes as $prime) { + $this->assertTrue(Integer::isPrime($prime)); + } + } + } } diff --git a/tests/NumberTheory/IntegerIsPrimeTest.php b/tests/NumberTheory/IntegerIsPrimeTest.php new file mode 100644 index 000000000..3d1993fcb --- /dev/null +++ b/tests/NumberTheory/IntegerIsPrimeTest.php @@ -0,0 +1,826 @@ +assertTrue($isPrime); + } + + /** + * @return array + */ + public function dataProviderForPrimeNumbers(): array + { + return [ + [2], + [3], + [5], + [7], + [11], + [13], + [17], + [19], + [23], + [29], + [31], + [37], + [41], + [43], + [47], + [53], + [59], + [61], + [67], + [71], + [73], + [79], + [83], + [89], + [97], + [101], + [103], + [107], + [109], + [113], + [127], + [131], + [137], + [139], + [149], + [151], + [157], + [163], + [167], + [173], + [179], + [181], + [191], + [193], + [197], + [199], + [211], + [223], + [227], + [229], + [233], + [239], + [241], + [251], + [257], + [263], + [269], + [271], + [277], + [281], + [283], + [293], + [307], + [311], + [313], + [317], + [331], + [337], + [347], + [349], + [353], + [359], + [367], + [373], + [379], + [383], + [389], + [397], + [401], + [409], + [419], + [421], + [431], + [433], + [439], + [443], + [449], + [457], + [461], + [463], + [467], + [479], + [487], + [491], + [499], + [503], + [509], + [521], + [523], + [541], + [547], + [557], + [563], + [569], + [571], + [577], + [587], + [593], + [599], + [601], + [607], + [613], + [617], + [619], + [631], + [641], + [643], + [647], + [653], + [659], + [661], + [673], + [677], + [683], + [691], + [701], + [709], + [719], + [727], + [733], + [739], + [743], + [751], + [757], + [761], + [769], + [773], + [787], + [797], + [809], + [811], + [821], + [823], + [827], + [829], + [839], + [853], + [857], + [859], + [863], + [877], + [881], + [883], + [887], + [907], + [911], + [919], + [929], + [937], + [941], + [947], + [953], + [967], + [971], + [977], + [983], + [991], + [997], + [1009], + [1013], + [1019], + [1021], + [1031], + [1033], + [1039], + [1049], + [1051], + [1061], + [1063], + [1069], + [1087], + [1091], + [1093], + [1097], + [1103], + [1109], + [1117], + [1123], + [1129], + [1151], + [1153], + [1163], + [1171], + [1181], + [1187], + [1193], + [1201], + [1213], + [1217], + [1223], + [1229], + [1231], + [1237], + [1249], + [1259], + [1277], + [1279], + [1283], + [1289], + [1291], + [1297], + [1301], + [1303], + [1307], + [1319], + [1321], + [1327], + [1361], + [1367], + [1373], + [1381], + [1399], + [1409], + [1423], + [1427], + [1429], + [1433], + [1439], + [1447], + [1451], + [1453], + [1459], + [1471], + [1481], + [1483], + [1487], + [1489], + [1493], + [1499], + [1511], + [1523], + [1531], + [1543], + [1549], + [1553], + [1559], + [1567], + [1571], + [1579], + [1583], + [1597], + [1601], + [1607], + [1609], + [1613], + [1619], + [1621], + [1627], + [1637], + [1657], + [1663], + [1667], + [1669], + [1693], + [1697], + [1699], + [1709], + [1721], + [1723], + [1733], + [1741], + [1747], + [1753], + [1759], + [1777], + [1783], + [1787], + [1789], + [1801], + [1811], + [1823], + [1831], + [1847], + [1861], + [1867], + [1871], + [1873], + [1877], + [1879], + [1889], + [1901], + [1907], + [1913], + [1931], + [1933], + [1949], + [1951], + [1973], + [1979], + [1987], + [1993], + [1997], + [1999], + [2003], + [2011], + [2017], + [2027], + [2029], + [2039], + [2053], + [2063], + [2069], + [2081], + [2083], + [2087], + [2089], + [2099], + [2111], + [2113], + [2129], + [2131], + [2137], + [2141], + [2143], + [2153], + [2161], + [2179], + [2203], + [2207], + [2213], + [2221], + [2237], + [2239], + [2243], + [2251], + [2267], + [2269], + [2273], + [2281], + [2287], + [2293], + [2297], + [2309], + [2311], + [2333], + [2339], + [2341], + [2347], + [2351], + [2357], + [2371], + [2377], + [2381], + [2383], + [2389], + [2393], + [2399], + [2411], + [2417], + [2423], + [2437], + [2441], + [2447], + [2459], + [2467], + [2473], + [2477], + [2503], + [2521], + [2531], + [2539], + [2543], + [2549], + [2551], + [2557], + [2579], + [2591], + [2593], + [2609], + [2617], + [2621], + [2633], + [2647], + [2657], + [2659], + [2663], + [2671], + [2677], + [2683], + [2687], + [2689], + [2693], + [2699], + [2707], + [2711], + [2713], + [2719], + [2729], + [2731], + [2741], + [2749], + [2753], + [2767], + [2777], + [2789], + [2791], + [2797], + [2801], + [2803], + [2819], + [2833], + [2837], + [2843], + [2851], + [2857], + [2861], + [2879], + [2887], + [2897], + [2903], + [2909], + [2917], + [2927], + [2939], + [2953], + [2957], + [2963], + [2969], + [2971], + [2999], + [3001], + [3011], + [3019], + [3023], + [3037], + [3041], + [3049], + [3061], + [3067], + [3079], + [3083], + [3089], + [3109], + [3119], + [3121], + [3137], + [3163], + [3167], + [3169], + [3181], + [3187], + [3191], + [3203], + [3209], + [3217], + [3221], + [3229], + [3251], + [3253], + [3257], + [3259], + [3271], + [3299], + [3301], + [3307], + [3313], + [3319], + [3323], + [3329], + [3331], + [3343], + [3347], + [3359], + [3361], + [3371], + [3373], + [3389], + [3391], + [3407], + [3413], + [3433], + [3449], + [3457], + [3461], + [3463], + [3467], + [3469], + [3491], + [3499], + [3511], + [3517], + [3527], + [3529], + [3533], + [3539], + [3541], + [3547], + [3557], + [3559], + [3571], + [3581], + [3583], + [3593], + [3607], + [3613], + [3617], + [3623], + [3631], + [3637], + [3643], + [3659], + [3671], + [3673], + [3677], + [3691], + [3697], + [3701], + [3709], + [3719], + [3727], + [3733], + [3739], + [3761], + [3767], + [3769], + [3779], + [3793], + [3797], + [3803], + [3821], + [3823], + [3833], + [3847], + [3851], + [3853], + [3863], + [3877], + [3881], + [3889], + [3907], + [3911], + [3917], + [3919], + [3923], + [3929], + [3931], + [3943], + [3947], + [3967], + [3989], + [4001], + [4003], + [4007], + [4013], + [4019], + [4021], + [4027], + [4049], + [4051], + [4057], + [4073], + [4079], + [4091], + [4093], + [4099], + [4111], + [4127], + [4129], + [4133], + [4139], + [4153], + [4157], + [4159], + [4177], + [4201], + [4211], + [4217], + [4219], + [4229], + [4231], + [4241], + [4243], + [4253], + [4259], + [4261], + [4271], + [4273], + [4283], + [4289], + [4297], + [4327], + [4337], + [4339], + [4349], + [4357], + [4363], + [4373], + [4391], + [4397], + [4409], + [4421], + [4423], + [4441], + [4447], + [4451], + [4457], + [4463], + [4481], + [4483], + [4493], + [4507], + [4513], + [4517], + [4519], + [4523], + [4547], + [4549], + [4561], + [4567], + [4583], + [4591], + [4597], + [4603], + [4621], + [4637], + [4639], + [4643], + [4649], + [4651], + [4657], + [4663], + [4673], + [4679], + [4691], + [4703], + [4721], + [4723], + [4729], + [4733], + [4751], + [4759], + [4783], + [4787], + [4789], + [4793], + [4799], + [4801], + [4813], + [4817], + [4831], + [4861], + [4871], + [4877], + [4889], + [4903], + [4909], + [4919], + [4931], + [4933], + [4937], + [4943], + [4951], + [4957], + [4967], + [4969], + [4973], + [4987], + [4993], + [4999], + ]; + } + + /** + * @return array + */ + public function dataProviderForSuperPrimeNumbers(): array + { + return [ + [4535189], + [131807699], + [2724711961], + [64988430769], + [1765037224331], + [53982894593057], + ]; + } + + /** + * @test isPrime - not prime + * @dataProvider dataProviderForNonPrimeNumbers + * @param int $n + */ + public function testIsNotPrime(int $n) + { + // When + $isPrime = Integer::isPrime($n); + + // Then + $this->assertFalse($isPrime); + } + + /** + * @return array + */ + public function dataProviderForNonPrimeNumbers(): array + { + return [ + [-3], + [-2], + [-1], + [0], + [1], + [4], + [6], + [8], + [9], + [10], + [12], + [14], + [15], + [16], + [18], + [21], + [20], + [22], + [24], + [25], + [26], + [27], + [28], + [30], + [32], + [33], + [34], + [35], + [36], + [38], + [39], + [40], + [42], + [44], + [45], + [46], + [48], + [49], + [50], + [51], + [52], + [54], + [56], + [55], + [57], + [58], + [60], + [63], + [62], + [64], + [65], + [66], + [69], + [68], + [70], + [72], + [75], + [74], + [76], + [78], + [77], + [80], + ]; + } + + /** + * @test isPrime + * @dataProvider dataProviderForPrimeNumberSequence + * @param int $n + */ + public function testIsPrimeUsingPrimeSequence(int $n) + { + // When + $isPrime = Integer::isPrime($n); + + // Then + $this->assertTrue($isPrime); + } + + /** + * @return \Generator + */ + public function dataProviderForPrimeNumberSequence(): \Generator + { + foreach (Advanced::primesUpTo(100) as $prime) { + yield [$prime]; + } + } +} From 5963799324d8a71dfb0c59ec8848c1e6a0e6c251 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Mon, 15 Apr 2024 22:06:58 -0700 Subject: [PATCH 62/66] Update README. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fa7f9b42..11dafa8f0 100644 --- a/README.md +++ b/README.md @@ -865,7 +865,8 @@ use MathPHP\NumberTheory\Integer; $n = 225; -// Prime factorization +// Prime numbers +$bool = Integer::isPrime($n); $factors = Integer::primeFactorization($n); // Divisor function From e587bfe3aadddfba0f3a40f49d2ed91132f30c5a Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Tue, 16 Apr 2024 17:09:51 -0700 Subject: [PATCH 63/66] Update CHANGELOG for v2.10.0. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8891cbec..446ae4d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # MathPHP Change Log +## v2.10.0 - 2024-04-16 + +### New Features +* NumberTheory\Integer `isPrime` + ## v2.9.0 - 2024-03-02 ### New Features From c85f142a1a1b3bf22890cc6c031bfc05ab0616aa Mon Sep 17 00:00:00 2001 From: "M. Vugteveen" Date: Tue, 14 Jan 2025 07:08:10 +0100 Subject: [PATCH 64/66] Fix php8.4 deprecated notices (#485) --- src/Functions/BaseEncoderDecoder.php | 2 +- src/LinearAlgebra/MatrixFactory.php | 2 +- src/LinearAlgebra/NumericMatrix.php | 4 ++-- src/Probability/Combinatorics.php | 2 +- src/Statistics/Distance.php | 2 +- src/Statistics/KernelDensityEstimation.php | 4 ++-- src/Statistics/Multivariate/PCA.php | 8 ++++---- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Functions/BaseEncoderDecoder.php b/src/Functions/BaseEncoderDecoder.php index 7f9a0ac58..a3d13095d 100644 --- a/src/Functions/BaseEncoderDecoder.php +++ b/src/Functions/BaseEncoderDecoder.php @@ -91,7 +91,7 @@ public static function toBase(ArbitraryInteger $number, int $base, $alphabet = n * * @throws Exception\BadParameterException if the string is empty or base is greater than 256 */ - public static function createArbitraryInteger(string $number, int $base, string $offset = null): ArbitraryInteger + public static function createArbitraryInteger(string $number, int $base, ?string $offset = null): ArbitraryInteger { if ($number == '') { throw new Exception\BadParameterException("String cannot be empty."); diff --git a/src/LinearAlgebra/MatrixFactory.php b/src/LinearAlgebra/MatrixFactory.php index 8a16fc99a..6e2c90cbb 100644 --- a/src/LinearAlgebra/MatrixFactory.php +++ b/src/LinearAlgebra/MatrixFactory.php @@ -425,7 +425,7 @@ public static function one(int $m, int $n): NumericMatrix * @throws Exception\MathException * @throws Exception\OutOfBoundsException if m, n, or k are < 0; if k >= n */ - public static function eye(int $m, int $n, int $k, float $x = null): NumericMatrix + public static function eye(int $m, int $n, int $k, ?float $x = null): NumericMatrix { if ($n < 0 || $m < 0 || $k < 0) { throw new Exception\OutOfBoundsException("m, n and k must be ≥ 0. m = $m, n = $n, k = $k"); diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index 52970dced..94492310c 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -3029,7 +3029,7 @@ private function solveRref(Vector $b): Vector * @throws Exception\MatrixException if method is not a valid eigenvalue method * @throws Exception\MathException */ - public function eigenvalues(string $method = null): array + public function eigenvalues(?string $method = null): array { if (!$this->isSquare()) { throw new Exception\MatrixException('Eigenvalues can only be calculated on square matrices'); @@ -3068,7 +3068,7 @@ public function eigenvalues(string $method = null): array * @throws Exception\MatrixException if method is not a valid eigenvalue method * @throws Exception\MathException */ - public function eigenvectors(string $method = null): NumericMatrix + public function eigenvectors(?string $method = null): NumericMatrix { if ($method === null) { return Eigenvector::eigenvectors($this, $this->eigenvalues()); diff --git a/src/Probability/Combinatorics.php b/src/Probability/Combinatorics.php index 389b3c2e4..64b649c04 100644 --- a/src/Probability/Combinatorics.php +++ b/src/Probability/Combinatorics.php @@ -228,7 +228,7 @@ public static function subfactorial(int $n): float * * @throws Exception\OutOfBoundsException if n is negative or k is larger than n */ - public static function permutations(int $n, int $k = null): float + public static function permutations(int $n, ?int $k = null): float { if ($n < 0) { throw new Exception\OutOfBoundsException('Cannot compute negative permutations.'); diff --git a/src/Statistics/Distance.php b/src/Statistics/Distance.php index ab2875a83..3ec6f62c2 100644 --- a/src/Statistics/Distance.php +++ b/src/Statistics/Distance.php @@ -191,7 +191,7 @@ public static function jensenShannon(array $p, array $q): float * @throws Exception\OutOfBoundsException * @throws Exception\VectorException */ - public static function mahalanobis(NumericMatrix $x, NumericMatrix $data, NumericMatrix $y = null): float + public static function mahalanobis(NumericMatrix $x, NumericMatrix $data, ?NumericMatrix $y = null): float { $Centroid = $data->rowMeans()->asColumnMatrix(); $Nx = $x->getN(); diff --git a/src/Statistics/KernelDensityEstimation.php b/src/Statistics/KernelDensityEstimation.php index 7d182338e..5828217ee 100644 --- a/src/Statistics/KernelDensityEstimation.php +++ b/src/Statistics/KernelDensityEstimation.php @@ -49,7 +49,7 @@ class KernelDensityEstimation * @throws Exception\OutOfBoundsException h ≤ 0 * @throws Exception\BadParameterException */ - public function __construct(array $data, float $h = null, $kernel = null) + public function __construct(array $data, ?float $h = null, $kernel = null) { $this->n = \count($data); if ($this->n === 0) { @@ -68,7 +68,7 @@ public function __construct(array $data, float $h = null, $kernel = null) * * @throws Exception\OutOfBoundsException if h ≤ 0 */ - public function setBandwidth(float $h = null): void + public function setBandwidth(?float $h = null): void { if ($h === null) { $this->h = $this->getDefaultBandwidth(); diff --git a/src/Statistics/Multivariate/PCA.php b/src/Statistics/Multivariate/PCA.php index b9bc1b77f..7430944de 100644 --- a/src/Statistics/Multivariate/PCA.php +++ b/src/Statistics/Multivariate/PCA.php @@ -106,7 +106,7 @@ private function checkNewData(NumericMatrix $newData): void * * @throws Exception\MathException */ - public function standardizeData(NumericMatrix $new_data = null): NumericMatrix + public function standardizeData(?NumericMatrix $new_data = null): NumericMatrix { if ($new_data === null) { $X = $this->data; @@ -164,7 +164,7 @@ public function getEigenvalues(): Vector * * @throws Exception\MathException */ - public function getScores(NumericMatrix $new_data = null): NumericMatrix + public function getScores(?NumericMatrix $new_data = null): NumericMatrix { if ($new_data === null) { $scaled_data = $this->data; @@ -220,7 +220,7 @@ public function getCumR2(): array * * @throws Exception\MathException */ - public function getQResiduals(NumericMatrix $new_data = null): NumericMatrix + public function getQResiduals(?NumericMatrix $new_data = null): NumericMatrix { $vars = $this->data->getN(); @@ -265,7 +265,7 @@ public function getQResiduals(NumericMatrix $new_data = null): NumericMatrix * * @throws Exception\MathException */ - public function getT2Distances(NumericMatrix $new_data = null): NumericMatrix + public function getT2Distances(?NumericMatrix $new_data = null): NumericMatrix { $vars = $this->data->getN(); From 6d6042f80aa6ee60538a95f0ddbc8bc3bd4d5d74 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 26 Jan 2025 12:01:52 -0800 Subject: [PATCH 65/66] Changes for PHP 8.4. --- .github/workflows/test_develop_and_master.yml | 4 ++-- .github/workflows/test_other_branches.yml | 4 ++-- .github/workflows/test_pull_request.yml | 4 ++-- Makefile | 2 +- src/LinearAlgebra/NumericMatrix.php | 2 -- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test_develop_and_master.yml b/.github/workflows/test_develop_and_master.yml index f277c5110..b17eecd2d 100644 --- a/.github/workflows/test_develop_and_master.yml +++ b/.github/workflows/test_develop_and_master.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - name: Set up PHP @@ -63,7 +63,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2'] + php: ['8.4'] steps: - name: Set up PHP diff --git a/.github/workflows/test_other_branches.yml b/.github/workflows/test_other_branches.yml index 9ec7bdbc0..c873b515e 100644 --- a/.github/workflows/test_other_branches.yml +++ b/.github/workflows/test_other_branches.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - name: Set up PHP @@ -62,7 +62,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2'] + php: ['8.4'] steps: - name: Set up PHP diff --git a/.github/workflows/test_pull_request.yml b/.github/workflows/test_pull_request.yml index 05830e704..f1e06a7c4 100644 --- a/.github/workflows/test_pull_request.yml +++ b/.github/workflows/test_pull_request.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - name: Set up PHP @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2'] + php: ['8.4'] steps: - name: Set up PHP diff --git a/Makefile b/Makefile index 9eb7ee0b8..3cf723361 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ style : vendor/bin/phpcs --standard=tests/coding_standard.xml --ignore=vendor -s . phpstan : - vendor/bin/phpstan analyze -c tests/phpstan.neon + vendor/bin/phpstan analyze -c tests/phpstan.neon --memory-limit 1G phpmd : vendor/bin/phpmd src/ ansi cleancode,codesize,design,unusedcode,naming diff --git a/src/LinearAlgebra/NumericMatrix.php b/src/LinearAlgebra/NumericMatrix.php index 94492310c..63b3cbf13 100644 --- a/src/LinearAlgebra/NumericMatrix.php +++ b/src/LinearAlgebra/NumericMatrix.php @@ -1283,13 +1283,11 @@ public function multiply($B): NumericMatrix $R[$i] = \array_fill(0, $B->n, 0); foreach ($Bᵀ as $j => $Bᶜᵒˡ⟦j⟧) { foreach ($Aʳᵒʷ⟦i⟧ as $k => $A⟦i⟧⟦k⟧) { - // @phpstan-ignore-next-line (Remove in PHP 8.0, no longer returns false) $R[$i][$j] += $A⟦i⟧⟦k⟧ * $Bᶜᵒˡ⟦j⟧[$k]; } } } - // @phpstan-ignore-next-line (Due to above false from array_fill) return MatrixFactory::createNumeric($R, $this->ε); } From ae499f31513821a62f3d2fb8c6f0d3a333e8b591 Mon Sep 17 00:00:00 2001 From: Mark Rogoyski Date: Sun, 26 Jan 2025 12:16:06 -0800 Subject: [PATCH 66/66] Update CHANGELOG for v2.11.0. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 446ae4d0c..1da5da562 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # MathPHP Change Log +## v2.11.0 - 2025-01-26 + +### Improvements +* Minor changes for PHP 8.4 compatibility + ## v2.10.0 - 2024-04-16 ### New Features