Update dev dependencies (#187)

* composer: update dev dependencies

* phpstan fixes

* phpstan fixes

* phpstan fixes

* phpstan fixes

* drop probably forgotten humbug configs

* apply cs

* fix cs bug

* compsoer: add coding standard and phsptan dev friendly scripts

* ecs: add skipped errors

* cs: fix PHP 7.1

* fix cs

* ecs: exclude strict fixer that break code

* ecs: cleanup commented sets

* travis: use composer scripts for testing to prevent duplicated setup
This commit is contained in:
Tomáš Votruba 2018-01-06 21:25:47 +01:00 committed by Arkadiusz Kondas
parent a348111e97
commit 6660645ecd
25 changed files with 457 additions and 454 deletions

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
/vendor/ /vendor/
humbuglog.*
.php_cs.cache .php_cs.cache
/build /build

View File

@ -30,8 +30,8 @@ install:
script: script:
- vendor/bin/phpunit $PHPUNIT_FLAGS - vendor/bin/phpunit $PHPUNIT_FLAGS
- if [[ $STATIC_ANALYSIS != "" ]]; then vendor/bin/ecs check src tests; fi - if [[ $STATIC_ANALYSIS != "" ]]; then composer check-cs; fi
- if [[ $STATIC_ANALYSIS != "" ]]; then vendor/bin/phpstan.phar analyse src tests --level max --configuration phpstan.neon; fi - if [[ $STATIC_ANALYSIS != "" ]]; then composer phpstan; fi
after_success: after_success:
- | - |

View File

@ -15,11 +15,10 @@
"php": "^7.1" "php": "^7.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6.4", "phpunit/phpunit": "^6.5",
"symplify/easy-coding-standard": "v3.0.0-RC3", "symplify/easy-coding-standard": "^3.1",
"symplify/coding-standard": "v3.0.0-RC3", "symplify/coding-standard": "^3.1",
"symplify/package-builder": "v3.0.0-RC3", "phpstan/phpstan-shim": "^0.9"
"phpstan/phpstan-shim": "^0.8"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -30,5 +29,10 @@
"psr-4": { "psr-4": {
"Phpml\\Tests\\": "tests/Phpml" "Phpml\\Tests\\": "tests/Phpml"
} }
},
"scripts": {
"check-cs": "vendor/bin/ecs check src tests bin",
"fix-cs": "vendor/bin/ecs check src tests bin --fix",
"phpstan": "vendor/bin/phpstan.phar analyse src tests bin --level max --configuration phpstan.neon"
} }
} }

744
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,8 @@
includes: includes:
- vendor/symplify/easy-coding-standard/config/psr2.neon - vendor/symplify/easy-coding-standard/config/psr2.neon
- vendor/symplify/easy-coding-standard/config/php70.neon - vendor/symplify/easy-coding-standard/config/php71.neon
- vendor/symplify/easy-coding-standard/config/clean-code.neon - vendor/symplify/easy-coding-standard/config/clean-code.neon
- vendor/symplify/easy-coding-standard/config/common/array.neon - vendor/symplify/easy-coding-standard/config/common.neon
- vendor/symplify/easy-coding-standard/config/common/docblock.neon
- vendor/symplify/easy-coding-standard/config/common/namespaces.neon
- vendor/symplify/easy-coding-standard/config/common/control-structures.neon
# many errors, need help
#- vendor/symplify/easy-coding-standard/config/common/strict.neon
checkers: checkers:
# spacing # spacing
@ -33,13 +27,16 @@ checkers:
- Symplify\CodingStandard\Fixer\Import\ImportNamespacedNameFixer - Symplify\CodingStandard\Fixer\Import\ImportNamespacedNameFixer
- Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer - Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer
- Symplify\CodingStandard\Fixer\Property\ArrayPropertyDefaultValueFixer - Symplify\CodingStandard\Fixer\Property\ArrayPropertyDefaultValueFixer
- Symplify\CodingStandard\Fixer\ClassNotation\PropertyAndConstantSeparationFixer
- Symplify\CodingStandard\Fixer\ArrayNotation\StandaloneLineInMultilineArrayFixer - Symplify\CodingStandard\Fixer\ArrayNotation\StandaloneLineInMultilineArrayFixer
parameters: parameters:
exclude_checkers: exclude_checkers:
# from strict.neon # from strict.neon
- PhpCsFixer\Fixer\PhpUnit\PhpUnitStrictFixer - PhpCsFixer\Fixer\PhpUnit\PhpUnitStrictFixer
- PhpCsFixer\Fixer\Strict\StrictComparisonFixer
# personal prefference
- PhpCsFixer\Fixer\Operator\NotOperatorWithSuccessorSpaceFixer
skip: skip:
PhpCsFixer\Fixer\Alias\RandomApiMigrationFixer: PhpCsFixer\Fixer\Alias\RandomApiMigrationFixer:
# random_int() breaks code # random_int() breaks code
@ -47,6 +44,15 @@ parameters:
SlevomatCodingStandard\Sniffs\Classes\UnusedPrivateElementsSniff: SlevomatCodingStandard\Sniffs\Classes\UnusedPrivateElementsSniff:
# magic calls # magic calls
- src/Phpml/Preprocessing/Normalizer.php - src/Phpml/Preprocessing/Normalizer.php
PhpCsFixer\Fixer\StringNotation\ExplicitStringVariableFixer:
# bugged
- src/Phpml/Classification/DecisionTree/DecisionTreeLeaf.php
Symplify\CodingStandard\Fixer\Commenting\RemoveUselessDocBlockFixer:
# bug in fixer
- src/Phpml/Math/LinearAlgebra/LUDecomposition.php
PhpCsFixer\Fixer\FunctionNotation\VoidReturnFixer:
# covariant return types
- src/Phpml/Classification/Linear/Perceptron.php
skip_codes: skip_codes:
# missing typehints # missing typehints
@ -56,3 +62,4 @@ parameters:
- SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff.MissingTraversableReturnTypeHintSpecification - SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff.MissingTraversableReturnTypeHintSpecification
- SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff.MissingPropertyTypeHint - SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff.MissingPropertyTypeHint
- SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff.MissingTraversablePropertyTypeHintSpecification - SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff.MissingTraversablePropertyTypeHintSpecification
- PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\AssignmentInConditionSniff.Found

View File

@ -1,11 +0,0 @@
{
"source": {
"directories": [
"src"
]
},
"timeout": 10,
"logs": {
"text": "humbuglog.txt"
}
}

View File

@ -1,19 +1,15 @@
parameters: parameters:
ignoreErrors: ignoreErrors:
- '#Phpml\\Dataset\\FilesDataset::__construct\(\) does not call parent constructor from Phpml\\Dataset\\ArrayDataset#' - '#Phpml\\Dataset\\FilesDataset::__construct\(\) does not call parent constructor from Phpml\\Dataset\\ArrayDataset#'
- '#Parameter \#2 \$predictedLabels of static method Phpml\\Metric\\Accuracy::score\(\) expects mixed\[\], mixed\[\]\|string given#'
# should be always defined # mocks
- '#Undefined variable: \$j#' - '#PHPUnit_Framework_MockObject_MockObject#'
# bugged # wide range cases
- '#expects [a-z\\\|\[\]]*, [a-z\\\|\(\)\[\]]*\[\] given#' - '#Call to function count\(\) with argument type array<int>\|Phpml\\Clustering\\KMeans\\Point will always result in number 1#'
- '#Parameter \#1 \$coordinates of class Phpml\\Clustering\\KMeans\\Point constructor expects array, array<int>\|Phpml\\Clustering\\KMeans\\Point given#'
# mock
- '#Parameter \#1 \$node of class Phpml\\NeuralNetwork\\Node\\Neuron\\Synapse constructor expects Phpml\\NeuralNetwork\\Node, Phpml\\NeuralNetwork\\Node\\Neuron\|PHPUnit_Framework_MockObject_MockObject given#'
- '#Parameter \#1 \$(activationFunction|synapse) of class Phpml\\NeuralNetwork\\Node\\Neuron constructor expects Phpml\\NeuralNetwork\\ActivationFunction|null, Phpml\\NeuralNetwork\\ActivationFunction\\BinaryStep|PHPUnit_Framework_MockObject_MockObject given#'
# probably known value # probably known value
- '#Variable \$j might not be defined#'
- '#Method Phpml\\Classification\\DecisionTree::getBestSplit\(\) should return Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf but returns Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf\|null#' - '#Method Phpml\\Classification\\DecisionTree::getBestSplit\(\) should return Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf but returns Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf\|null#'
- '#Method Phpml\\Classification\\Linear\\DecisionStump::getBestNumericalSplit\(\) should return mixed\[\] but returns \(float\|int\|mixed\|string\)\[\]\|null#' - '#Call to an undefined method Phpml\\Helper\\Optimizer\\Optimizer::getCostValues\(\)#'
- '#Method Phpml\\Classification\\Linear\\DecisionStump::getBestNominalSplit\(\) should return mixed\[\] but returns mixed\[\]\|null#'

View File

@ -64,9 +64,9 @@ class DecisionTree implements Classifier
private $featureImportances; private $featureImportances;
/** /**
* @var array|null * @var array
*/ */
private $columnNames; private $columnNames = [];
public function __construct(int $maxDepth = 10) public function __construct(int $maxDepth = 10)
{ {
@ -89,7 +89,7 @@ class DecisionTree implements Classifier
// If column names are given or computed before, then there is no // If column names are given or computed before, then there is no
// need to init it and accidentally remove the previous given names // need to init it and accidentally remove the previous given names
if ($this->columnNames === null) { if ($this->columnNames === []) {
$this->columnNames = range(0, $this->featureCount - 1); $this->columnNames = range(0, $this->featureCount - 1);
} elseif (count($this->columnNames) > $this->featureCount) { } elseif (count($this->columnNames) > $this->featureCount) {
$this->columnNames = array_slice($this->columnNames, 0, $this->featureCount); $this->columnNames = array_slice($this->columnNames, 0, $this->featureCount);
@ -380,9 +380,9 @@ class DecisionTree implements Classifier
$median = Mean::median($values); $median = Mean::median($values);
foreach ($values as &$value) { foreach ($values as &$value) {
if ($value <= $median) { if ($value <= $median) {
$value = "<= $median"; $value = "<= ${median}";
} else { } else {
$value = "> $median"; $value = "> ${median}";
} }
} }
} }

View File

@ -122,7 +122,7 @@ class DecisionTreeLeaf
public function getHTML($columnNames = null): string public function getHTML($columnNames = null): string
{ {
if ($this->isTerminal) { if ($this->isTerminal) {
$value = "<b>$this->classValue</b>"; $value = "<b>${this}->classValue</b>";
} else { } else {
$value = $this->value; $value = $this->value;
if ($columnNames !== null) { if ($columnNames !== null) {
@ -132,13 +132,13 @@ class DecisionTreeLeaf
} }
if (!preg_match('/^[<>=]{1,2}/', (string) $value)) { if (!preg_match('/^[<>=]{1,2}/', (string) $value)) {
$value = "=$value"; $value = "=${value}";
} }
$value = "<b>$col $value</b><br>Gini: ".number_format($this->giniIndex, 2); $value = "<b>${col} ${value}</b><br>Gini: ".number_format($this->giniIndex, 2);
} }
$str = "<table ><tr><td colspan=3 align=center style='border:1px solid;'>$value</td></tr>"; $str = "<table ><tr><td colspan=3 align=center style='border:1px solid;'>${value}</td></tr>";
if ($this->leftLeaf || $this->rightLeaf) { if ($this->leftLeaf || $this->rightLeaf) {
$str .= '<tr>'; $str .= '<tr>';

View File

@ -86,7 +86,7 @@ class DecisionStump extends WeightedClassifier
public function __toString(): string public function __toString(): string
{ {
return "IF $this->column $this->operator $this->value ". return "IF ${this}->column ${this}->operator ${this}->value ".
'THEN '.$this->binaryLabels[0].' '. 'THEN '.$this->binaryLabels[0].' '.
'ELSE '.$this->binaryLabels[1]; 'ELSE '.$this->binaryLabels[1];
} }
@ -176,14 +176,14 @@ class DecisionStump extends WeightedClassifier
$maxValue = max($values); $maxValue = max($values);
$stepSize = ($maxValue - $minValue) / $this->numSplitCount; $stepSize = ($maxValue - $minValue) / $this->numSplitCount;
$split = null; $split = [];
foreach (['<=', '>'] as $operator) { foreach (['<=', '>'] as $operator) {
// Before trying all possible split points, let's first try // Before trying all possible split points, let's first try
// the average value for the cut point // the average value for the cut point
$threshold = array_sum($values) / (float) count($values); $threshold = array_sum($values) / (float) count($values);
[$errorRate, $prob] = $this->calculateErrorRate($targets, $threshold, $operator, $values); [$errorRate, $prob] = $this->calculateErrorRate($targets, $threshold, $operator, $values);
if ($split == null || $errorRate < $split['trainingErrorRate']) { if ($split === [] || $errorRate < $split['trainingErrorRate']) {
$split = [ $split = [
'value' => $threshold, 'value' => $threshold,
'operator' => $operator, 'operator' => $operator,
@ -218,13 +218,13 @@ class DecisionStump extends WeightedClassifier
$valueCounts = array_count_values($values); $valueCounts = array_count_values($values);
$distinctVals = array_keys($valueCounts); $distinctVals = array_keys($valueCounts);
$split = null; $split = [];
foreach (['=', '!='] as $operator) { foreach (['=', '!='] as $operator) {
foreach ($distinctVals as $val) { foreach ($distinctVals as $val) {
[$errorRate, $prob] = $this->calculateErrorRate($targets, $val, $operator, $values); [$errorRate, $prob] = $this->calculateErrorRate($targets, $val, $operator, $values);
if ($split === null || $split['trainingErrorRate'] < $errorRate) { if ($split === [] || $split['trainingErrorRate'] < $errorRate) {
$split = [ $split = [
'value' => $val, 'value' => $val,
'operator' => $operator, 'operator' => $operator,

View File

@ -34,7 +34,7 @@ class Perceptron implements Classifier, IncrementalEstimator
protected $featureCount = 0; protected $featureCount = 0;
/** /**
* @var array|null * @var array
*/ */
protected $weights = []; protected $weights = [];
@ -146,7 +146,7 @@ class Perceptron implements Classifier, IncrementalEstimator
$this->labels = []; $this->labels = [];
$this->optimizer = null; $this->optimizer = null;
$this->featureCount = 0; $this->featureCount = 0;
$this->weights = null; $this->weights = [];
$this->costValues = []; $this->costValues = [];
} }
@ -174,7 +174,7 @@ class Perceptron implements Classifier, IncrementalEstimator
* Executes a Gradient Descent algorithm for * Executes a Gradient Descent algorithm for
* the given cost function * the given cost function
*/ */
protected function runGradientDescent(array $samples, array $targets, Closure $gradientFunc, bool $isBatch = false): void protected function runGradientDescent(array $samples, array $targets, Closure $gradientFunc, bool $isBatch = false)
{ {
$class = $isBatch ? GD::class : StochasticGD::class; $class = $isBatch ? GD::class : StochasticGD::class;

View File

@ -78,7 +78,7 @@ class FuzzyCMeans implements Clusterer
} }
/** /**
* @param array|Point[] $samples * @param Point[]|int[][] $samples
*/ */
public function cluster(array $samples): array public function cluster(array $samples): array
{ {

View File

@ -25,7 +25,7 @@ class StopWords
public static function factory(string $language = 'English'): self public static function factory(string $language = 'English'): self
{ {
$className = __NAMESPACE__."\\StopWords\\$language"; $className = __NAMESPACE__."\\StopWords\\${language}";
if (!class_exists($className)) { if (!class_exists($className)) {
throw InvalidArgumentException::invalidStopWordsLanguage($language); throw InvalidArgumentException::invalidStopWordsLanguage($language);

View File

@ -164,7 +164,7 @@ trait OneVsRest
*/ */
private function binarizeTargets(array $targets, $label): array private function binarizeTargets(array $targets, $label): array
{ {
$notLabel = "not_$label"; $notLabel = "not_${label}";
foreach ($targets as $key => $target) { foreach ($targets as $key => $target) {
$targets[$key] = $target == $label ? $label : $notLabel; $targets[$key] = $target == $label ? $label : $notLabel;
} }

View File

@ -47,7 +47,7 @@ abstract class Optimizer
public function setInitialTheta(array $theta) public function setInitialTheta(array $theta)
{ {
if (count($theta) != $this->dimensions) { if (count($theta) != $this->dimensions) {
throw new Exception("Number of values in the weights array should be $this->dimensions"); throw new Exception("Number of values in the weights array should be ${this}->dimensions");
} }
$this->theta = $theta; $this->theta = $theta;

View File

@ -10,7 +10,7 @@ use IteratorAggregate;
class Set implements IteratorAggregate class Set implements IteratorAggregate
{ {
/** /**
* @var string[]|int[]|float[] * @var string[]|int[]|float[]|bool[]
*/ */
private $elements = []; private $elements = [];
@ -135,7 +135,7 @@ class Set implements IteratorAggregate
} }
/** /**
* @return string[]|int[]|float[] * @return string[]|int[]|float[]|bool[]
*/ */
public function toArray(): array public function toArray(): array
{ {
@ -160,9 +160,9 @@ class Set implements IteratorAggregate
/** /**
* Removes duplicates and rewrites index. * Removes duplicates and rewrites index.
* *
* @param string[]|int[]|float[] $elements * @param string[]|int[]|float[]|bool[] $elements
* *
* @return string[]|int[]|float[] * @return string[]|int[]|float[]|bool[]
*/ */
private static function sanitize(array $elements): array private static function sanitize(array $elements): array
{ {

View File

@ -15,14 +15,14 @@ class Backpropagation
private $learningRate; private $learningRate;
/** /**
* @var array|null * @var array
*/ */
private $sigmas; private $sigmas = [];
/** /**
* @var array|null * @var array
*/ */
private $prevSigmas; private $prevSigmas = [];
public function __construct(float $learningRate) public function __construct(float $learningRate)
{ {
@ -57,8 +57,8 @@ class Backpropagation
} }
// Clean some memory (also it helps make MLP persistency & children more maintainable). // Clean some memory (also it helps make MLP persistency & children more maintainable).
$this->sigmas = null; $this->sigmas = [];
$this->prevSigmas = null; $this->prevSigmas = [];
} }
private function getSigma(Neuron $neuron, int $targetClass, int $key, bool $lastLayer): float private function getSigma(Neuron $neuron, int $targetClass, int $key, bool $lastLayer): float

View File

@ -10,6 +10,7 @@ use Phpml\Math\Matrix;
class LeastSquares implements Regression class LeastSquares implements Regression
{ {
use Predictable; use Predictable;
/** /**
* @var array * @var array
*/ */

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace tests\Phpml\Classification\Linear; namespace Phpml\Tests\Classification\Linear;
use Phpml\Classification\Linear\LogisticRegression; use Phpml\Classification\Linear\LogisticRegression;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -55,12 +55,12 @@ class LogisticRegressionTest extends TestCase
$zero = $method->invoke($predictor, [0.1, 0.1], 0); $zero = $method->invoke($predictor, [0.1, 0.1], 0);
$one = $method->invoke($predictor, [0.1, 0.1], 1); $one = $method->invoke($predictor, [0.1, 0.1], 1);
$this->assertEquals(1, $zero + $one, null, 1e-6); $this->assertEquals(1, $zero + $one, '', 1e-6);
$this->assertTrue($zero > $one); $this->assertTrue($zero > $one);
$zero = $method->invoke($predictor, [0.9, 0.9], 0); $zero = $method->invoke($predictor, [0.9, 0.9], 0);
$one = $method->invoke($predictor, [0.9, 0.9], 1); $one = $method->invoke($predictor, [0.9, 0.9], 1);
$this->assertEquals(1, $zero + $one, null, 1e-6); $this->assertEquals(1, $zero + $one, '', 1e-6);
$this->assertTrue($zero < $one); $this->assertTrue($zero < $one);
} }
@ -97,9 +97,9 @@ class LogisticRegressionTest extends TestCase
$two = $method->invoke($predictor, [3.0, 9.5], 2); $two = $method->invoke($predictor, [3.0, 9.5], 2);
$not_two = $method->invoke($predictor, [3.0, 9.5], 'not_2'); $not_two = $method->invoke($predictor, [3.0, 9.5], 'not_2');
$this->assertEquals(1, $zero + $not_zero, null, 1e-6); $this->assertEquals(1, $zero + $not_zero, '', 1e-6);
$this->assertEquals(1, $one + $not_one, null, 1e-6); $this->assertEquals(1, $one + $not_one, '', 1e-6);
$this->assertEquals(1, $two + $not_two, null, 1e-6); $this->assertEquals(1, $two + $not_two, '', 1e-6);
$this->assertTrue($zero < $two); $this->assertTrue($zero < $two);
$this->assertTrue($one < $two); $this->assertTrue($one < $two);
} }

View File

@ -45,7 +45,7 @@ class AccuracyTest extends TestCase
$classifier = new SVC(Kernel::RBF); $classifier = new SVC(Kernel::RBF);
$classifier->train($dataset->getTrainSamples(), $dataset->getTrainLabels()); $classifier->train($dataset->getTrainSamples(), $dataset->getTrainLabels());
$predicted = $classifier->predict($dataset->getTestSamples()); $predicted = (array) $classifier->predict($dataset->getTestSamples());
$accuracy = Accuracy::score($dataset->getTestLabels(), $predicted); $accuracy = Accuracy::score($dataset->getTestLabels(), $predicted);

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace tests\Phpml\NeuralNetwork\Network; namespace Phpml\Tests\NeuralNetwork\Network;
use Phpml\NeuralNetwork\Network\MultilayerPerceptron; use Phpml\NeuralNetwork\Network\MultilayerPerceptron;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -11,6 +11,7 @@ class MultilayerPerceptronTest extends TestCase
{ {
public function testLearningRateSetter(): void public function testLearningRateSetter(): void
{ {
/** @var MultilayerPerceptron $mlp */
$mlp = $this->getMockForAbstractClass( $mlp = $this->getMockForAbstractClass(
MultilayerPerceptron::class, MultilayerPerceptron::class,
[5, [3], [0, 1], 1000, null, 0.42] [5, [3], [0, 1], 1000, null, 0.42]