Commit db82afa2 authored by Marcin Michalski's avatar Marcin Michalski Committed by Arkadiusz Kondas
Browse files

Update to phpunit 8 and bump min php to 7.2 (#367)

* Update to phpunit 8

* Require at least PHP 7.2
parent cefb4fc7
/vendor/
.php_cs.cache
/build
/tests/Performance/Data/*.csv
.php_cs.cache
.phpunit.result.cache
......@@ -4,14 +4,10 @@ matrix:
fast_finish: true
include:
- os: linux
php: '7.1'
env: DISABLE_XDEBUG="true" STATIC_ANALYSIS="true"
- os: linux
php: '7.2'
env: PHPUNIT_FLAGS="--coverage-clover build/logs/clover.xml"
env: PHPUNIT_FLAGS="--coverage-clover build/logs/clover.xml" DISABLE_XDEBUG="true" STATIC_ANALYSIS="true"
- os: linux
php: '7.3'
......
# PHP-ML - Machine Learning library for PHP
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.1-8892BF.svg)](https://php.net/)
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.2-8892BF.svg)](https://php.net/)
[![Latest Stable Version](https://img.shields.io/packagist/v/php-ai/php-ml.svg)](https://packagist.org/packages/php-ai/php-ml)
[![Build Status](https://travis-ci.org/php-ai/php-ml.svg?branch=master)](https://travis-ci.org/php-ai/php-ml)
[![Documentation Status](https://readthedocs.org/projects/php-ml/badge/?version=master)](http://php-ml.readthedocs.org/)
......@@ -15,7 +15,7 @@
Fresh approach to Machine Learning in PHP. Algorithms, Cross Validation, Neural Network, Preprocessing, Feature Extraction and much more in one library.
PHP-ML requires PHP >= 7.1.
PHP-ML requires PHP >= 7.2.
Simple example of classification:
```php
......
......@@ -20,14 +20,14 @@
}
],
"require": {
"php": "^7.1"
"php": "^7.2"
},
"require-dev": {
"phpbench/phpbench": "^0.14.0",
"phpstan/phpstan-phpunit": "^0.11",
"phpstan/phpstan-shim": "^0.11",
"phpstan/phpstan-strict-rules": "^0.11",
"phpunit/phpunit": "^7.0.0",
"phpunit/phpunit": "^8.0",
"symplify/coding-standard": "^5.1",
"symplify/easy-coding-standard": "^5.1"
},
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dee9be6daf48915171d2778b17d941fa",
"content-hash": "b329ea9fc7b690ad2d498e85a445d214",
"packages": [],
"packages-dev": [
{
......@@ -1881,40 +1881,40 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "6.1.4",
"version": "7.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d"
"reference": "0317a769a81845c390e19684d9ba25d7f6aa4707"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
"reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0317a769a81845c390e19684d9ba25d7f6aa4707",
"reference": "0317a769a81845c390e19684d9ba25d7f6aa4707",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlwriter": "*",
"php": "^7.1",
"phpunit/php-file-iterator": "^2.0",
"php": "^7.2",
"phpunit/php-file-iterator": "^2.0.2",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^3.0",
"phpunit/php-token-stream": "^3.0.1",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.1 || ^4.0",
"sebastian/environment": "^4.1",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1"
},
"require-dev": {
"phpunit/phpunit": "^7.0"
"phpunit/phpunit": "^8.0"
},
"suggest": {
"ext-xdebug": "^2.6.0"
"ext-xdebug": "^2.6.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.1-dev"
"dev-master": "7.0-dev"
}
},
"autoload": {
......@@ -1940,7 +1940,7 @@
"testing",
"xunit"
],
"time": "2018-10-31T16:06:48+00:00"
"time": "2019-02-26T07:38:26+00:00"
},
{
"name": "phpunit/php-file-iterator",
......@@ -2133,16 +2133,16 @@
},
{
"name": "phpunit/phpunit",
"version": "7.5.7",
"version": "8.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "eb343b86753d26de07ecba7868fa983104361948"
"reference": "19cbed2120839772c4a00e8b28456b0c77d1a7b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/eb343b86753d26de07ecba7868fa983104361948",
"reference": "eb343b86753d26de07ecba7868fa983104361948",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/19cbed2120839772c4a00e8b28456b0c77d1a7b4",
"reference": "19cbed2120839772c4a00e8b28456b0c77d1a7b4",
"shasum": ""
},
"require": {
......@@ -2152,27 +2152,25 @@
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.7",
"phar-io/manifest": "^1.0.2",
"phar-io/version": "^2.0",
"php": "^7.1",
"php": "^7.2",
"phpspec/prophecy": "^1.7",
"phpunit/php-code-coverage": "^6.0.7",
"phpunit/php-code-coverage": "^7.0",
"phpunit/php-file-iterator": "^2.0.1",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^2.1",
"sebastian/comparator": "^3.0",
"sebastian/diff": "^3.0",
"sebastian/environment": "^4.0",
"sebastian/environment": "^4.1",
"sebastian/exporter": "^3.1",
"sebastian/global-state": "^2.0",
"sebastian/global-state": "^3.0",
"sebastian/object-enumerator": "^3.0.3",
"sebastian/resource-operations": "^2.0",
"sebastian/version": "^2.0.1"
},
"conflict": {
"phpunit/phpunit-mock-objects": "*"
},
"require-dev": {
"ext-pdo": "*"
},
......@@ -2187,7 +2185,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.5-dev"
"dev-master": "8.0-dev"
}
},
"autoload": {
......@@ -2213,7 +2211,7 @@
"testing",
"xunit"
],
"time": "2019-03-16T07:31:17+00:00"
"time": "2019-03-16T07:33:46+00:00"
},
{
"name": "psr/cache",
......@@ -2692,23 +2690,26 @@
},
{
"name": "sebastian/global-state",
"version": "2.0.0",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
"reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
"reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
"reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
"shasum": ""
},
"require": {
"php": "^7.0"
"php": "^7.2",
"sebastian/object-reflector": "^1.1.1",
"sebastian/recursion-context": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
"ext-dom": "*",
"phpunit/phpunit": "^8.0"
},
"suggest": {
"ext-uopz": "*"
......@@ -2716,7 +2717,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
"dev-master": "3.0-dev"
}
},
"autoload": {
......@@ -2739,7 +2740,7 @@
"keywords": [
"global state"
],
"time": "2017-04-27T15:39:26+00:00"
"time": "2019-02-01T05:30:01+00:00"
},
{
"name": "sebastian/object-enumerator",
......@@ -4749,7 +4750,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^7.1"
"php": "^7.2"
},
"platform-dev": []
}
# PHP-ML - Machine Learning library for PHP
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.1-8892BF.svg)](https://php.net/)
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.2-8892BF.svg)](https://php.net/)
[![Latest Stable Version](https://img.shields.io/packagist/v/php-ai/php-ml.svg)](https://packagist.org/packages/php-ai/php-ml)
[![Build Status](https://travis-ci.org/php-ai/php-ml.svg?branch=master)](https://travis-ci.org/php-ai/php-ml)
[![Documentation Status](https://readthedocs.org/projects/php-ml/badge/?version=master)](http://php-ml.readthedocs.org/)
......@@ -15,7 +15,7 @@
Fresh approach to Machine Learning in PHP. Algorithms, Cross Validation, Neural Network, Preprocessing, Feature Extraction and much more in one library.
PHP-ML requires PHP >= 7.1.
PHP-ML requires PHP >= 7.2.
Simple example of classification:
```php
......
......@@ -171,12 +171,12 @@ class LogisticRegressionTest extends TestCase
$zero = $method->invoke($predictor, [0.1, 0.1], 0);
$one = $method->invoke($predictor, [0.1, 0.1], 1);
self::assertEquals(1, $zero + $one, '', 1e-6);
self::assertEqualsWithDelta(1, $zero + $one, 1e-6);
self::assertTrue($zero > $one);
$zero = $method->invoke($predictor, [0.9, 0.9], 0);
$one = $method->invoke($predictor, [0.9, 0.9], 1);
self::assertEquals(1, $zero + $one, '', 1e-6);
self::assertEqualsWithDelta(1, $zero + $one, 1e-6);
self::assertTrue($zero < $one);
}
......@@ -213,9 +213,9 @@ class LogisticRegressionTest extends TestCase
$two = $method->invoke($predictor, [3.0, 9.5], 2);
$not_two = $method->invoke($predictor, [3.0, 9.5], 'not_2');
self::assertEquals(1, $zero + $not_zero, '', 1e-6);
self::assertEquals(1, $one + $not_one, '', 1e-6);
self::assertEquals(1, $two + $not_two, '', 1e-6);
self::assertEqualsWithDelta(1, $zero + $not_zero, 1e-6);
self::assertEqualsWithDelta(1, $one + $not_one, 1e-6);
self::assertEqualsWithDelta(1, $two + $not_two, 1e-6);
self::assertTrue($zero < $two);
self::assertTrue($one < $two);
}
......
......@@ -33,14 +33,14 @@ class KernelPCATest extends TestCase
[-0.13128352866095], [-0.20865959471756], [-0.17531601535848], [0.4240660966961],
[0.36351946685163], [-0.14334173054136], [0.22454914091011], [0.15035027480881], ];
$kpca = new KernelPCA(KernelPCA::KERNEL_RBF, null, 1, 15);
$kpca = new KernelPCA(KernelPCA::KERNEL_RBF, null, 1, 15.);
$reducedData = $kpca->fit($data);
// Due to the fact that the sign of values can be flipped
// during the calculation of eigenValues, we have to compare
// absolute value of the values
array_map(function ($val1, $val2) use ($epsilon): void {
self::assertEquals(abs($val1), abs($val2), '', $epsilon);
self::assertEqualsWithDelta(abs($val1), abs($val2), $epsilon);
}, $transformed, $reducedData);
// Fitted KernelPCA object can also transform an arbitrary sample of the
......@@ -48,7 +48,7 @@ class KernelPCATest extends TestCase
$newData = [1.25, 2.25];
$newTransformed = [0.18956227539216];
$newTransformed2 = $kpca->transform($newData);
self::assertEquals(abs($newTransformed[0]), abs($newTransformed2[0]), '', $epsilon);
self::assertEqualsWithDelta(abs($newTransformed[0]), abs($newTransformed2[0]), $epsilon);
}
public function testKernelPCAThrowWhenKernelInvalid(): void
......
......@@ -51,7 +51,7 @@ class LDATest extends TestCase
// absolute value of the values
$row1 = array_map('abs', $row1);
$row2 = array_map('abs', $row2);
self::assertEquals($row1, $row2, '', $epsilon);
self::assertEqualsWithDelta($row1, $row2, $epsilon);
};
array_map($check, $control, $transformed2);
......
......@@ -42,7 +42,7 @@ class PCATest extends TestCase
// during the calculation of eigenValues, we have to compare
// absolute value of the values
array_map(function ($val1, $val2) use ($epsilon): void {
self::assertEquals(abs($val1), abs($val2), '', $epsilon);
self::assertEqualsWithDelta(abs($val1), abs($val2), $epsilon);
}, $transformed, $reducedData);
// Test fitted PCA object to transform an arbitrary sample of the
......@@ -52,7 +52,7 @@ class PCATest extends TestCase
$newRow2 = $pca->transform($row);
array_map(function ($val1, $val2) use ($epsilon): void {
self::assertEquals(abs($val1), abs($val2), '', $epsilon);
self::assertEqualsWithDelta(abs($val1), abs($val2), $epsilon);
}, $newRow, $newRow2);
}
}
......
......@@ -54,6 +54,6 @@ class TfIdfTransformerTest extends TestCase
$transformer = new TfIdfTransformer($samples);
$transformer->transform($samples);
self::assertEquals($tfIdfSamples, $samples, '', 0.001);
self::assertEqualsWithDelta($tfIdfSamples, $samples, 0.001);
}
}
......@@ -15,10 +15,9 @@ final class ANOVAFValueTest extends TestCase
$dataset = new IrisDataset();
$function = new ANOVAFValue();
self::assertEquals(
self::assertEqualsWithDelta(
[119.2645, 47.3644, 1179.0343, 959.3244],
$function->score($dataset->getSamples(), $dataset->getTargets()),
'',
0.0001
);
}
......
......@@ -15,7 +15,7 @@ final class UnivariateLinearRegressionTest extends TestCase
$targets = [2000, 2750, 15500, 960, 4400, 8800, 7100, 2550, 1025, 5900, 4600, 4400];
$function = new UnivariateLinearRegression();
self::assertEquals([6.97286, 6.48558], $function->score($samples, $targets), '', 0.0001);
self::assertEqualsWithDelta([6.97286, 6.48558], $function->score($samples, $targets), 0.0001);
}
public function testRegressionScoreWithoutCenter(): void
......@@ -24,6 +24,6 @@ final class UnivariateLinearRegressionTest extends TestCase
$targets = [2000, 2750, 15500, 960, 4400, 8800, 7100, 2550, 1025, 5900, 4600, 4400];
$function = new UnivariateLinearRegression(false);
self::assertEquals([1.74450, 18.08347], $function->score($samples, $targets), '', 0.0001);
self::assertEqualsWithDelta([1.74450, 18.08347], $function->score($samples, $targets), 0.0001);
}
}
......@@ -33,7 +33,7 @@ class ConjugateGradientTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
self::assertEquals([-1, 2], $theta, '', 0.1);
self::assertEqualsWithDelta([-1, 2], $theta, 0.1);
}
public function testRunOptimizationWithCustomInitialTheta(): void
......@@ -61,7 +61,7 @@ class ConjugateGradientTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
self::assertEquals([-1.087708, 2.212034], $theta, '', 0.000001);
self::assertEqualsWithDelta([-1.087708, 2.212034], $theta, 0.000001);
}
public function testRunOptimization2Dim(): void
......@@ -89,7 +89,7 @@ class ConjugateGradientTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
self::assertEquals([-1, 2, -3], $theta, '', 0.1);
self::assertEqualsWithDelta([-1, 2, -3], $theta, 0.1);
}
public function testThrowExceptionOnInvalidTheta(): void
......
......@@ -32,7 +32,7 @@ class GDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
self::assertEquals([-1, 2], $theta, '', 0.1);
self::assertEqualsWithDelta([-1, 2], $theta, 0.1);
}
public function testRunOptimization2Dim(): void
......@@ -60,6 +60,6 @@ class GDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
self::assertEquals([-1, 2, -3], $theta, '', 0.1);
self::assertEqualsWithDelta([-1, 2, -3], $theta, 0.1);
}
}
......@@ -32,7 +32,7 @@ class StochasticGDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
self::assertEquals([-1, 2], $theta, '', 0.1);
self::assertEqualsWithDelta([-1, 2], $theta, 0.1);
}
public function testRunOptimization2Dim(): void
......@@ -60,6 +60,6 @@ class StochasticGDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
self::assertEquals([-1, 2, -3], $theta, '', 0.1);
self::assertEqualsWithDelta([-1, 2, -3], $theta, 0.1);
}
}
......@@ -47,7 +47,7 @@ class MinkowskiTest extends TestCase
$expectedDistance = 2.080;
$actualDistance = $this->distanceMetric->distance($a, $b);
self::assertEquals($expectedDistance, $actualDistance, '', $delta = 0.001);
self::assertEqualsWithDelta($expectedDistance, $actualDistance, $delta = 0.001);
}
public function testCalculateDistanceForThreeDimensions(): void
......@@ -58,7 +58,7 @@ class MinkowskiTest extends TestCase
$expectedDistance = 5.819;
$actualDistance = $this->distanceMetric->distance($a, $b);
self::assertEquals($expectedDistance, $actualDistance, '', $delta = 0.001);
self::assertEqualsWithDelta($expectedDistance, $actualDistance, $delta = 0.001);
}
public function testCalculateDistanceForThreeDimensionsWithDifferentLambda(): void
......@@ -71,6 +71,6 @@ class MinkowskiTest extends TestCase
$expectedDistance = 5.300;
$actualDistance = $distanceMetric->distance($a, $b);
self::assertEquals($expectedDistance, $actualDistance, '', $delta = 0.001);
self::assertEqualsWithDelta($expectedDistance, $actualDistance, $delta = 0.001);
}
}
......@@ -15,13 +15,13 @@ class RBFTest extends TestCase
$rbf = new RBF($gamma = 0.001);
self::assertEquals(1, $rbf->compute([1, 2], [1, 2]));
self::assertEquals(0.97336, $rbf->compute([1, 2, 3], [4, 5, 6]), '', $delta = 0.0001);
self::assertEquals(0.00011, $rbf->compute([4, 5], [1, 100]), '', $delta = 0.0001);
self::assertEqualsWithDelta(0.97336, $rbf->compute([1, 2, 3], [4, 5, 6]), $delta = 0.0001);
self::assertEqualsWithDelta(0.00011, $rbf->compute([4, 5], [1, 100]), $delta = 0.0001);
$rbf = new RBF($gamma = 0.2);
self::assertEquals(1, $rbf->compute([1, 2], [1, 2]));
self::assertEquals(0.00451, $rbf->compute([1, 2, 3], [4, 5, 6]), '', $delta = 0.0001);
self::assertEqualsWithDelta(0.00451, $rbf->compute([1, 2, 3], [4, 5, 6]), $delta = 0.0001);
self::assertEquals(0, $rbf->compute([4, 5], [1, 100]));
}
......
......@@ -21,11 +21,11 @@ class EigenvalueDecompositionTest extends TestCase
$decomp = new EigenvalueDecomposition($matrix);
self::assertEquals([0.0490833989, 1.28402771], $decomp->getRealEigenvalues(), '', 0.001);
self::assertEquals([
self::assertEqualsWithDelta([0.0490833989, 1.28402771], $decomp->getRealEigenvalues(), 0.001);
self::assertEqualsWithDelta([
[-0.735178656, 0.677873399],
[-0.677873399, -0.735178656],
], $decomp->getEigenvectors(), '', 0.001);
], $decomp->getEigenvectors(), 0.001);
}
public function testMatrixWithAllZeroRow(): void
......@@ -39,12 +39,12 @@ class EigenvalueDecompositionTest extends TestCase
$decomp = new EigenvalueDecomposition($matrix);
self::assertEquals([0.0, 6.0, 10.0], $decomp->getRealEigenvalues(), '', 0.0001);
self::assertEquals([
self::assertEqualsWithDelta([0.0, 6.0, 10.0], $decomp->getRealEigenvalues(), 0.0001);
self::assertEqualsWithDelta([
[0, 0, 1],
[0, 1, 0],
[1, 0, 0],
], $decomp->getEigenvectors(), '', 0.0001);
], $decomp->getEigenvectors(), 0.0001);
}
public function testMatrixThatCauseErrorWithStrictComparision(): void
......@@ -58,12 +58,12 @@ class EigenvalueDecompositionTest extends TestCase
$decomp = new EigenvalueDecomposition($matrix);
self::assertEquals([-5.2620873481, 1.0, 10.2620873481], $decomp->getRealEigenvalues(), '', 0.000001);
self::assertEquals([
self::assertEqualsWithDelta([-5.2620873481, 1.0, 10.2620873481], $decomp->getRealEigenvalues(), 0.000001);
self::assertEqualsWithDelta([
[-0.3042688, -0.709960552, 0.63511928],
[-0.9191450, 0.393919298, 0.0],
[0.25018574, 0.5837667, 0.7724140],
], $decomp->getEigenvectors(), '', 0.0001);
], $decomp->getEigenvectors(), 0.0001);
}
public function testRandomSymmetricMatrixEigenPairs(): void
......@@ -98,7 +98,7 @@ class EigenvalueDecompositionTest extends TestCase
$leftSide = $m1->multiply($m2)->toArray();
$rightSide = $m2->multiplyByScalar($lambda)->toArray();
self::assertEquals($leftSide, $rightSide, '', $epsilon);
self::assertEqualsWithDelta($leftSide, $rightSide, $epsilon);
}
}
}
......@@ -60,7 +60,7 @@ class MatrixTest extends TestCase
[1 / 4, 4, 1, 0, 2, 3 / 7],
[1, 8, 7, 5, 4, 4 / 5],
]);
self::assertEquals(1116.5035, $matrix->getDeterminant(), '', $delta = 0.0001);
self::assertEqualsWithDelta(1116.5035, $matrix->getDeterminant(), $delta = 0.0001);
}
public function testMatrixTranspose(): void
......@@ -157,7 +157,7 @@ class MatrixTest extends TestCase
[-1 / 2, 1 / 2, -1 / 2],
];
self::assertEquals($inverseMatrix, $matrix->inverse()->toArray(), '', $delta = 0.0001);
self::assertEqualsWithDelta($inverseMatrix, $matrix->inverse()->toArray(), $delta = 0.0001);
}
public function testCrossOutMatrix(): void
......@@ -256,7 +256,7 @@ class MatrixTest extends TestCase
*/
public function testFrobeniusNorm(array $matrix, float $norm): void
{
self::assertEquals($norm, (new Matrix($matrix))->frobeniusNorm(), '', 0.0001);
self::assertEqualsWithDelta($norm, (new Matrix($matrix))->frobeniusNorm(), 0.0001);
}
public function dataProviderForFrobeniusNorm(): array
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment