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

Update phpstan to 0.10.5 (#320)

parent d9b85e84
......@@ -19,6 +19,7 @@ This changelog references the relevant changes done in PHP-ML library.
* fix SVM locale (non-locale aware) (#288)
* typo, tests, code styles and documentation fixes (#265, #261, #254, #253, #251, #250, #248, #245, #243)
* change [MLPClassifier] return labels in output (#315)
* enhancement Update phpstan to 0.10.5 (#320)
* 0.6.2 (2018-02-22)
* Fix Apriori array keys (#238)
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "cb4240c977f956be78a7fa686c77d0f2",
"content-hash": "9ec1ca6b843d05e0870bd777026d7a8b",
"packages": [],
"packages-dev": [
{
......@@ -1511,83 +1511,42 @@
],
"time": "2018-08-05T17:53:17+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "0.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "ed3223362174b8067729930439e139794e9e514a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ed3223362174b8067729930439e139794e9e514a",
"reference": "ed3223362174b8067729930439e139794e9e514a",
"shasum": ""
},
"require": {
"php": "~7.1"
},
"require-dev": {
"consistence/coding-standard": "^2.0.0",
"jakub-onderka/php-parallel-lint": "^0.9.2",
"phing/phing": "^2.16.0",
"phpstan/phpstan": "^0.10@dev",
"phpunit/phpunit": "^6.3",
"slevomat/coding-standard": "^3.3.0",
"symfony/process": "^3.4 || ^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.3-dev"
}
},
"autoload": {
"psr-4": {
"PHPStan\\PhpDocParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"time": "2018-06-20T17:48:01+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "0.9.4",
"version": "0.10",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "852411f841a37aeca2fa5af0002b0272c485c9bf"
"reference": "6feecc7faae187daa6be44140cd0f1ba210e6aa0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/852411f841a37aeca2fa5af0002b0272c485c9bf",
"reference": "852411f841a37aeca2fa5af0002b0272c485c9bf",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6feecc7faae187daa6be44140cd0f1ba210e6aa0",
"reference": "6feecc7faae187daa6be44140cd0f1ba210e6aa0",
"shasum": ""
},
"require": {
"php": "~7.0",
"phpstan/phpstan": "^0.9.1",
"phpunit/phpunit": "^6.3 || ~7.0"
"nikic/php-parser": "^4.0",
"php": "~7.1",
"phpstan/phpstan": "^0.10"
},
"conflict": {
"phpunit/phpunit": "<7.0"
},
"require-dev": {
"consistence/coding-standard": "^2.0",
"jakub-onderka/php-parallel-lint": "^0.9.2",
"consistence/coding-standard": "^3.0.1",
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.4",
"jakub-onderka/php-parallel-lint": "^1.0",
"phing/phing": "^2.16.0",
"phpstan/phpstan-strict-rules": "^0.9",
"phpstan/phpstan-strict-rules": "^0.10",
"phpunit/phpunit": "^7.0",
"satooshi/php-coveralls": "^1.0",
"slevomat/coding-standard": "^3.3.0"
"slevomat/coding-standard": "^4.5.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.9-dev"
"dev-master": "0.10-dev"
}
},
"autoload": {
......@@ -1600,26 +1559,28 @@
"MIT"
],
"description": "PHPUnit extensions and rules for PHPStan",
"time": "2018-02-02T09:45:47+00:00"
"time": "2018-06-22T18:12:17+00:00"
},
{
"name": "phpstan/phpstan-shim",
"version": "0.9.2",
"version": "0.10.5",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-shim.git",
"reference": "e4720fb2916be05de02869780072253e7e0e8a75"
"reference": "a274185548d140a7f48cc1eed5b94f3a9068c674"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-shim/zipball/e4720fb2916be05de02869780072253e7e0e8a75",
"reference": "e4720fb2916be05de02869780072253e7e0e8a75",
"url": "https://api.github.com/repos/phpstan/phpstan-shim/zipball/a274185548d140a7f48cc1eed5b94f3a9068c674",
"reference": "a274185548d140a7f48cc1eed5b94f3a9068c674",
"shasum": ""
},
"require": {
"php": "~7.0"
"php": "~7.1"
},
"replace": {
"nikic/php-parser": "^4.0.2",
"phpstan/phpdoc-parser": "^0.3",
"phpstan/phpstan": "self.version"
},
"bin": [
......@@ -1629,46 +1590,53 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.9-dev"
"dev-master": "0.10-dev"
}
},
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan Phar distribution",
"time": "2018-01-28T14:29:27+00:00"
"time": "2018-10-20T17:45:03+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "0.9",
"version": "0.10.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "15be9090622c6b85c079922308f831018d8d9e23"
"reference": "18c0b6e8899606b127c680402ab473a7b67166db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/15be9090622c6b85c079922308f831018d8d9e23",
"reference": "15be9090622c6b85c079922308f831018d8d9e23",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/18c0b6e8899606b127c680402ab473a7b67166db",
"reference": "18c0b6e8899606b127c680402ab473a7b67166db",
"shasum": ""
},
"require": {
"php": "~7.0",
"phpstan/phpstan": "^0.9"
"nikic/php-parser": "^4.0",
"php": "~7.1",
"phpstan/phpstan": "^0.10"
},
"require-dev": {
"consistence/coding-standard": "^2.0.0",
"jakub-onderka/php-parallel-lint": "^0.9.2",
"consistence/coding-standard": "^3.0.1",
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.4",
"jakub-onderka/php-parallel-lint": "^1.0",
"phing/phing": "^2.16.0",
"phpstan/phpstan-phpunit": "^0.9",
"phpunit/phpunit": "^6.4",
"slevomat/coding-standard": "^3.3.0"
"phpstan/phpstan-phpunit": "^0.10",
"phpunit/phpunit": "^7.0",
"slevomat/coding-standard": "^4.5.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.9-dev"
"dev-master": "0.10-dev"
}
},
"autoload": {
......@@ -1681,7 +1649,7 @@
"MIT"
],
"description": "Extra strict and opinionated rules for PHPStan",
"time": "2017-11-26T20:12:30+00:00"
"time": "2018-07-06T20:36:44+00:00"
},
{
"name": "phpunit/php-code-coverage",
......
......@@ -2,14 +2,13 @@ includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-phpunit/strictRules.neon
parameters:
ignoreErrors:
- '#Property Phpml\\Clustering\\KMeans\\Cluster\:\:\$points \(iterable\<Phpml\\Clustering\\KMeans\\Point\>\&SplObjectStorage\) does not accept SplObjectStorage#'
- '#Phpml\\Dataset\\FilesDataset::__construct\(\) does not call parent constructor from Phpml\\Dataset\\ArrayDataset#'
# wide range cases
- '#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#'
# probably known value
......
......@@ -64,11 +64,11 @@ class Apriori implements Associator
*/
public function getRules(): array
{
if (empty($this->large)) {
if (count($this->large) === 0) {
$this->large = $this->apriori();
}
if (!empty($this->rules)) {
if (count($this->rules) > 0) {
return $this->rules;
}
......@@ -89,7 +89,7 @@ class Apriori implements Associator
$L = [];
$items = $this->frequent($this->items());
for ($k = 1; !empty($items); ++$k) {
for ($k = 1; isset($items[0]); ++$k) {
$L[$k] = $items;
$items = $this->frequent($this->candidates($items));
}
......@@ -118,7 +118,7 @@ class Apriori implements Associator
*/
private function generateAllRules(): void
{
for ($k = 2; !empty($this->large[$k]); ++$k) {
for ($k = 2; isset($this->large[$k]); ++$k) {
foreach ($this->large[$k] as $frequent) {
$this->generateRules($frequent);
}
......@@ -241,7 +241,7 @@ class Apriori implements Associator
continue;
}
foreach ((array) $this->samples as $sample) {
foreach ($this->samples as $sample) {
if ($this->subset($sample, $candidate)) {
$candidates[] = $candidate;
......@@ -316,7 +316,7 @@ class Apriori implements Associator
*/
private function subset(array $set, array $subset): bool
{
return !array_diff($subset, array_intersect($subset, $set));
return count(array_diff($subset, array_intersect($subset, $set))) === 0;
}
/**
......
......@@ -249,7 +249,7 @@ class DecisionTree implements Classifier
foreach ($records as $recordNo) {
// Check if the previous record is the same with the current one
$record = $this->samples[$recordNo];
if ($prevRecord && $prevRecord != $record) {
if ($prevRecord !== null && $prevRecord != $record) {
$allSame = false;
}
......@@ -275,13 +275,13 @@ class DecisionTree implements Classifier
if ($allSame || $depth >= $this->maxDepth || count($remainingTargets) === 1) {
$split->isTerminal = true;
arsort($remainingTargets);
$split->classValue = key($remainingTargets);
$split->classValue = (string) key($remainingTargets);
} else {
if (!empty($leftRecords)) {
if (isset($leftRecords[0])) {
$split->leftLeaf = $this->getSplitLeaf($leftRecords, $depth + 1);
}
if (!empty($rightRecords)) {
if (isset($rightRecords[0])) {
$split->rightLeaf = $this->getSplitLeaf($rightRecords, $depth + 1);
}
}
......@@ -292,8 +292,10 @@ class DecisionTree implements Classifier
protected function getBestSplit(array $records): DecisionTreeLeaf
{
$targets = array_intersect_key($this->targets, array_flip($records));
$samples = array_intersect_key($this->samples, array_flip($records));
$samples = array_combine($records, $this->preprocess($samples));
$samples = (array) array_combine(
$records,
$this->preprocess(array_intersect_key($this->samples, array_flip($records)))
);
$bestGiniVal = 1;
$bestSplit = null;
$features = $this->getSelectedFeatures();
......@@ -306,6 +308,10 @@ class DecisionTree implements Classifier
$counts = array_count_values($colValues);
arsort($counts);
$baseValue = key($counts);
if ($baseValue === null) {
continue;
}
$gini = $this->getGiniIndex($baseValue, $colValues, $targets);
if ($bestSplit === null || $bestGiniVal > $gini) {
$split = new DecisionTreeLeaf();
......@@ -349,11 +355,11 @@ class DecisionTree implements Classifier
protected function getSelectedFeatures(): array
{
$allFeatures = range(0, $this->featureCount - 1);
if ($this->numUsableFeatures === 0 && empty($this->selectedFeatures)) {
if ($this->numUsableFeatures === 0 && count($this->selectedFeatures) === 0) {
return $allFeatures;
}
if (!empty($this->selectedFeatures)) {
if (count($this->selectedFeatures) > 0) {
return $this->selectedFeatures;
}
......@@ -406,7 +412,7 @@ class DecisionTree implements Classifier
// all values in that column (Lower than or equal to %20 of all values)
$numericValues = array_filter($columnValues, 'is_numeric');
$floatValues = array_filter($columnValues, 'is_float');
if (!empty($floatValues)) {
if (count($floatValues) > 0) {
return false;
}
......@@ -463,7 +469,7 @@ class DecisionTree implements Classifier
$node = $this->tree;
do {
if ($node->isTerminal) {
break;
return $node->classValue;
}
if ($node->evaluate($sample)) {
......@@ -473,6 +479,6 @@ class DecisionTree implements Classifier
}
} while ($node);
return $node !== null ? $node->classValue : $this->labels[0];
return $this->labels[0];
}
}
......@@ -119,7 +119,7 @@ class DecisionTreeLeaf
/**
* Returns HTML representation of the node including children nodes
*/
public function getHTML($columnNames = null): string
public function getHTML(?array $columnNames = null): string
{
if ($this->isTerminal) {
$value = "<b>${this}->classValue</b>";
......@@ -131,7 +131,7 @@ class DecisionTreeLeaf
$col = "col_$this->columnIndex";
}
if (!preg_match('/^[<>=]{1,2}/', (string) $value)) {
if ((bool) preg_match('/^[<>=]{1,2}/', (string) $value) === false) {
$value = "=${value}";
}
......
......@@ -100,7 +100,7 @@ class AdaBoost implements Classifier
{
// Initialize usual variables
$this->labels = array_keys(array_count_values($targets));
if (count($this->labels) != 2) {
if (count($this->labels) !== 2) {
throw new InvalidArgumentException('AdaBoost is a binary classifier and can classify between two classes only');
}
......@@ -159,13 +159,10 @@ class AdaBoost implements Classifier
protected function getBestClassifier(): Classifier
{
$ref = new ReflectionClass($this->baseClassifier);
if (!empty($this->classifierOptions)) {
$classifier = $ref->newInstanceArgs($this->classifierOptions);
} else {
$classifier = $ref->newInstance();
}
/** @var Classifier $classifier */
$classifier = count($this->classifierOptions) === 0 ? $ref->newInstance() : $ref->newInstanceArgs($this->classifierOptions);
if (is_subclass_of($classifier, WeightedClassifier::class)) {
if ($classifier instanceof WeightedClassifier) {
$classifier->setSampleWeights($this->weights);
$classifier->train($this->samples, $this->targets);
} else {
......
......@@ -51,16 +51,6 @@ class Bagging implements Classifier
*/
protected $subsetRatio = 0.7;
/**
* @var array
*/
private $targets = [];
/**
* @var array
*/
private $samples = [];
/**
* Creates an ensemble classifier with given number of base classifiers
* Default number of base classifiers is 50.
......@@ -146,11 +136,8 @@ class Bagging implements Classifier
$classifiers = [];
for ($i = 0; $i < $this->numClassifier; ++$i) {
$ref = new ReflectionClass($this->classifier);
if (!empty($this->classifierOptions)) {
$obj = $ref->newInstanceArgs($this->classifierOptions);
} else {
$obj = $ref->newInstance();
}
/** @var Classifier $obj */
$obj = count($this->classifierOptions) === 0 ? $ref->newInstance() : $ref->newInstanceArgs($this->classifierOptions);
$classifiers[] = $this->initSingleClassifier($obj);
}
......
......@@ -45,8 +45,7 @@ class KNearestNeighbors implements Classifier
protected function predictSample(array $sample)
{
$distances = $this->kNeighborsDistances($sample);
$predictions = array_combine(array_values($this->targets), array_fill(0, count($this->targets), 0));
$predictions = (array) array_combine(array_values($this->targets), array_fill(0, count($this->targets), 0));
foreach (array_keys($distances) as $index) {
++$predictions[$this->targets[$index]];
......
......@@ -55,7 +55,7 @@ class Adaline extends Perceptron
* Adapts the weights with respect to given samples and targets
* by use of gradient descent learning rule
*/
protected function runTraining(array $samples, array $targets)
protected function runTraining(array $samples, array $targets): void
{
// The cost function is the sum of squares
$callback = function ($weights, $sample, $target) {
......@@ -70,6 +70,6 @@ class Adaline extends Perceptron
$isBatch = $this->trainingType == self::BATCH_TRAINING;
return parent::runGradientDescent($samples, $targets, $callback, $isBatch);
parent::runGradientDescent($samples, $targets, $callback, $isBatch);
}
}
......@@ -119,13 +119,13 @@ class DecisionStump extends WeightedClassifier
// Check the size of the weights given.
// If none given, then assign 1 as a weight to each sample
if (!empty($this->weights)) {
if (count($this->weights) === 0) {
$this->weights = array_fill(0, count($samples), 1);
} else {
$numWeights = count($this->weights);
if ($numWeights != count($samples)) {
if ($numWeights !== count($samples)) {
throw new InvalidArgumentException('Number of sample weights does not match with number of samples');
}
} else {
$this->weights = array_fill(0, count($samples), 1);
}
// Determine type of each column as either "continuous" or "nominal"
......@@ -134,7 +134,7 @@ class DecisionStump extends WeightedClassifier
// Try to find the best split in the columns of the dataset
// by calculating error rate for each split point in each column
$columns = range(0, count($samples[0]) - 1);
if ($this->givenColumnIndex != self::AUTO_SELECT) {
if ($this->givenColumnIndex !== self::AUTO_SELECT) {
$columns = [$this->givenColumnIndex];
}
......@@ -184,7 +184,7 @@ class DecisionStump extends WeightedClassifier
// the average value for the cut point
$threshold = array_sum($values) / (float) count($values);
[$errorRate, $prob] = $this->calculateErrorRate($targets, $threshold, $operator, $values);
if ($split === [] || $errorRate < $split['trainingErrorRate']) {
if (!isset($split['trainingErrorRate']) || $errorRate < $split['trainingErrorRate']) {
$split = [
'value' => $threshold,
'operator' => $operator,
......@@ -224,8 +224,7 @@ class DecisionStump extends WeightedClassifier
foreach (['=', '!='] as $operator) {
foreach ($distinctVals as $val) {
[$errorRate, $prob] = $this->calculateErrorRate($targets, $val, $operator, $values);
if ($split === [] || $split['trainingErrorRate'] < $errorRate) {
if (!isset($split['trainingErrorRate']) || $split['trainingErrorRate'] < $errorRate) {
$split = [
'value' => $val,
'operator' => $operator,
......
......@@ -60,11 +60,6 @@ class Perceptron implements Classifier, IncrementalEstimator
*/
protected $enableEarlyStop = true;
/**
* @var array
*/
protected $costValues = [];
/**
* Initalize a perceptron classifier with given learning rate and maximum
* number of iterations used while training the perceptron
......@@ -156,7 +151,7 @@ class Perceptron implements Classifier, IncrementalEstimator
* Trains the perceptron model with Stochastic Gradient Descent optimization
* to get the correct set of weights
*/
protected function runTraining(array $samples, array $targets)
protected function runTraining(array $samples, array $targets): void
{
// The cost function is the sum of squares
$callback = function ($weights, $sample, $target) {
......@@ -176,7 +171,7 @@ class Perceptron implements Classifier, IncrementalEstimator
* Executes a Gradient Descent algorithm for
* the given cost function
*/
protected function runGradientDescent(array $samples, array $targets, Closure $gradientFunc, bool $isBatch = false)
protected function runGradientDescent(array $samples, array $targets, Closure $gradientFunc, bool $isBatch = false): void
{
$class = $isBatch ? GD::class : StochasticGD::class;
......
......@@ -108,8 +108,7 @@ class FuzzyCMeans implements Clusterer
$column = array_column($this->membership, $k);
arsort($column);
reset($column);
$i = key($column);
$cluster = $this->clusters[$i];
$cluster = $this->clusters[key($column)];
$cluster->attach(new Point($this->samples[$k]));
}
......@@ -152,7 +151,7 @@ class FuzzyCMeans implements Clusterer
protected function updateClusters(): void
{
$dim = $this->space->getDimension();
if (empty($this->clusters)) {
if (count($this->clusters) === 0) {
for ($i = 0; $i < $this->clustersNumber; ++$i) {
$this->clusters[] = new Cluster($this->space, array_fill(0, $dim, 0.0));
}
......@@ -171,11 +170,11 @@ class FuzzyCMeans implements Clusterer
}
}
protected function getMembershipRowTotal(int $row, int $col, bool $multiply)
protected function getMembershipRowTotal(int $row, int $col, bool $multiply): float
{
$sum = 0.0;
for ($k = 0; $k < $this->sampleCount; ++$k) {
$val = pow($this->membership[$row][$k], $this->fuzziness);
$val = $this->membership[$row][$k] ** $this->fuzziness;
if ($multiply) {
$val *= $this->samples[$k][$col];
}
......@@ -211,7 +210,7 @@ class FuzzyCMeans implements Clusterer
$this->samples[$col]
);
$val = pow($dist1 / $dist2, 2.0 / ($this->fuzziness - 1));
$val = ($dist1 / $dist2) ** 2.0 / ($this->fuzziness - 1);
$sum += $val;