Update phpstan to 0.10.5 (#320)

This commit is contained in:
Marcin Michalski 2018-10-28 07:44:52 +01:00 committed by Arkadiusz Kondas
parent d9b85e841f
commit 53c5a6b9e5
131 changed files with 1010 additions and 974 deletions

View File

@ -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)

View File

@ -24,9 +24,9 @@
},
"require-dev": {
"phpbench/phpbench": "^0.14.0",
"phpstan/phpstan-phpunit": "^0.9.4",
"phpstan/phpstan-shim": "^0.9",
"phpstan/phpstan-strict-rules": "^0.9.0",
"phpstan/phpstan-phpunit": "^0.10",
"phpstan/phpstan-shim": "^0.10",
"phpstan/phpstan-strict-rules": "^0.10",
"phpunit/phpunit": "^7.0.0",
"symplify/coding-standard": "^5.1",
"symplify/easy-coding-standard": "^5.1"

128
composer.lock generated
View File

@ -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",

View File

@ -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

View File

@ -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;
}
/**

View File

@ -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];
}
}

View File

@ -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}";
}

View File

@ -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 {

View File

@ -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);
}

View File

@ -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]];

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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;

View File

@ -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;
}
@ -223,7 +222,7 @@ class FuzzyCMeans implements Clusterer
* and all cluster centers. This method returns the summation of all
* these distances
*/
protected function getObjective()
protected function getObjective(): float
{
$sum = 0.0;
$distance = new Euclidean();

View File

@ -4,12 +4,11 @@ declare(strict_types=1);
namespace Phpml\Clustering\KMeans;
use Countable;
use IteratorAggregate;
use LogicException;
use SplObjectStorage;
class Cluster extends Point implements IteratorAggregate, Countable
class Cluster extends Point implements IteratorAggregate
{
/**
* @var Space
@ -32,10 +31,10 @@ class Cluster extends Point implements IteratorAggregate, Countable
{
$points = [];
foreach ($this->points as $point) {
if (!empty($point->label)) {
$points[$point->label] = $point->toArray();
} else {
if (count($point->label) === 0) {
$points[] = $point->toArray();
} else {
$points[$point->label] = $point->toArray();
}
}
@ -106,10 +105,7 @@ class Cluster extends Point implements IteratorAggregate, Countable
return $this->points;
}
/**
* @return mixed
*/
public function count()
public function count(): int
{
return count($this->points);
}

View File

@ -6,7 +6,7 @@ namespace Phpml\Clustering\KMeans;
use ArrayAccess;
class Point implements ArrayAccess
class Point implements ArrayAccess, \Countable
{
/**
* @var int
@ -23,6 +23,9 @@ class Point implements ArrayAccess
*/
protected $label;
/**
* @param mixed $label
*/
public function __construct(array $coordinates, $label = null)
{
$this->dimension = count($coordinates);
@ -36,7 +39,7 @@ class Point implements ArrayAccess
}
/**
* @return int|mixed
* @return float|int
*/
public function getDistanceWith(self $point, bool $precise = true)
{
@ -50,9 +53,9 @@ class Point implements ArrayAccess
}
/**
* @return mixed
* @param Point[] $points
*/
public function getClosest(array $points)
public function getClosest(array $points): ?self
{
$minPoint = null;
@ -114,4 +117,9 @@ class Point implements ArrayAccess
{
unset($this->coordinates[$offset]);
}
public function count(): int
{
return count($this->coordinates);
}
}

View File

@ -28,6 +28,8 @@ class Space extends SplObjectStorage
public function toArray(): array
{
$points = [];
/** @var Point $point */
foreach ($this as $point) {
$points[] = $point->toArray();
}
@ -35,9 +37,12 @@ class Space extends SplObjectStorage
return ['points' => $points];
}
/**
* @param mixed $label
*/
public function newPoint(array $coordinates, $label = null): Point
{
if (count($coordinates) != $this->dimension) {
if (count($coordinates) !== $this->dimension) {
throw new LogicException('('.implode(',', $coordinates).') is not a point of this space');
}
@ -45,7 +50,8 @@ class Space extends SplObjectStorage
}
/**
* @param null $data
* @param mixed $label
* @param mixed $data
*/
public function addPoint(array $coordinates, $label = null, $data = null): void
{
@ -53,8 +59,8 @@ class Space extends SplObjectStorage
}
/**
* @param Point $point
* @param null $data
* @param object $point
* @param mixed $data
*/
public function attach($point, $data = null): void
{
@ -82,10 +88,16 @@ class Space extends SplObjectStorage
$min = $this->newPoint(array_fill(0, $this->dimension, null));
$max = $this->newPoint(array_fill(0, $this->dimension, null));
/** @var self $point */
foreach ($this as $point) {
for ($n = 0; $n < $this->dimension; ++$n) {
($min[$n] > $point[$n] || $min[$n] === null) && $min[$n] = $point[$n];
($max[$n] < $point[$n] || $max[$n] === null) && $max[$n] = $point[$n];
if ($min[$n] === null || $min[$n] > $point[$n]) {
$min[$n] = $point[$n];
}
if ($max[$n] === null || $max[$n] < $point[$n]) {
$max[$n] = $point[$n];
}
}
}
@ -141,7 +153,10 @@ class Space extends SplObjectStorage
return $clusters;
}
protected function iterate($clusters): bool
/**
* @param Cluster[] $clusters
*/
protected function iterate(array $clusters): bool
{
$convergence = true;
@ -164,10 +179,12 @@ class Space extends SplObjectStorage
}
}
/** @var Cluster $cluster */
foreach ($attach as $cluster) {
$cluster->attachAll($attach[$cluster]);
}
/** @var Cluster $cluster */
foreach ($detach as $cluster) {
$cluster->detachAll($detach[$cluster]);
}
@ -179,23 +196,36 @@ class Space extends SplObjectStorage
return $convergence;
}
/**
* @return Cluster[]
*/
protected function initializeKMPPClusters(int $clustersNumber): array
{
$clusters = [];
$this->rewind();
$clusters[] = new Cluster($this, $this->current()->getCoordinates());
/** @var Point $current */
$current = $this->current();
$clusters[] = new Cluster($this, $current->getCoordinates());
$distances = new SplObjectStorage();
for ($i = 1; $i < $clustersNumber; ++$i) {
$sum = 0;
/** @var Point $point */
foreach ($this as $point) {
$distance = $point->getDistanceWith($point->getClosest($clusters));
$closest = $point->getClosest($clusters);
if ($closest === null) {
continue;
}
$distance = $point->getDistanceWith($closest);
$sum += $distances[$point] = $distance;
}
$sum = random_int(0, (int) $sum);
/** @var Point $point */
foreach ($this as $point) {
$sum -= $distances[$point];
@ -212,6 +242,9 @@ class Space extends SplObjectStorage
return $clusters;
}
/**
* @return Cluster[]
*/
private function initializeRandomClusters(int $clustersNumber): array
{
$clusters = [];

View File

@ -60,7 +60,7 @@ abstract class Split
return $this->testLabels;
}
abstract protected function splitDataset(Dataset $dataset, float $testSize);
abstract protected function splitDataset(Dataset $dataset, float $testSize): void;
protected function seedGenerator(?int $seed = null): void
{

View File

@ -27,6 +27,7 @@ class StratifiedRandomSplit extends RandomSplit
$samples = $dataset->getSamples();
$uniqueTargets = array_unique($targets);
/** @var array $split */
$split = array_combine($uniqueTargets, array_fill(0, count($uniqueTargets), []));
foreach ($samples as $key => $sample) {

View File

@ -29,14 +29,14 @@ class CsvDataset extends ArrayDataset
if ($headingRow) {
$data = fgetcsv($handle, $maxLineLength, $delimiter);
$this->columnNames = array_slice($data, 0, $features);
$this->columnNames = array_slice((array) $data, 0, $features);
} else {
$this->columnNames = range(0, $features - 1);
}
$samples = $targets = [];
while (($data = fgetcsv($handle, $maxLineLength, $delimiter)) !== false) {
$samples[] = array_slice($data, 0, $features);
$samples[] = array_slice((array) $data, 0, $features);
$targets[] = $data[$features];
}

View File

@ -23,8 +23,8 @@ class SvmDataset extends ArrayDataset
$samples = [];
$targets = [];
$maxIndex = 0;
while (($line = fgets($handle)) !== false) {
[$sample, $target, $maxIndex] = self::processLine($line, $maxIndex);
while (false !== $line = fgets($handle)) {
[$sample, $target, $maxIndex] = self::processLine((string) $line, $maxIndex);
$samples[] = $sample;
$targets[] = $target;
}
@ -38,6 +38,9 @@ class SvmDataset extends ArrayDataset
return [$samples, $targets];
}
/**
* @return resource
*/
private static function openFile(string $filePath)
{
if (!file_exists($filePath)) {

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Phpml\DimensionReduction;
use Closure;
use Exception;
use Phpml\Exception\InvalidArgumentException;
use Phpml\Exception\InvalidOperationException;
use Phpml\Math\Distance\Euclidean;
@ -59,8 +58,7 @@ class KernelPCA extends PCA
*/
public function __construct(int $kernel = self::KERNEL_RBF, ?float $totalVariance = null, ?int $numFeatures = null, ?float $gamma = null)
{
$availableKernels = [self::KERNEL_RBF, self::KERNEL_SIGMOID, self::KERNEL_LAPLACIAN, self::KERNEL_LINEAR];
if (!in_array($kernel, $availableKernels, true)) {
if (!in_array($kernel, [self::KERNEL_RBF, self::KERNEL_SIGMOID, self::KERNEL_LAPLACIAN, self::KERNEL_LINEAR], true)) {
throw new InvalidArgumentException('KernelPCA can be initialized with the following kernels only: Linear, RBF, Sigmoid and Laplacian');
}
@ -190,7 +188,7 @@ class KernelPCA extends PCA
return function ($x, $y) {
$res = Matrix::dot($x, $y)[0] + 1.0;
return tanh($this->gamma * $res);
return tanh((float) $this->gamma * $res);
};
case self::KERNEL_LAPLACIAN:
@ -203,7 +201,7 @@ class KernelPCA extends PCA
default:
// Not reached
throw new Exception(sprintf('KernelPCA initialized with invalid kernel: %d', $this->kernel));
throw new InvalidArgumentException(sprintf('KernelPCA initialized with invalid kernel: %d', $this->kernel));
}
}

View File

@ -115,7 +115,7 @@ class PCA extends EigenTransformerBase
*/
protected function normalize(array $data, int $n): array
{
if (empty($this->means)) {
if (count($this->means) === 0) {
$this->calculateMeans($data, $n);
}

View File

@ -6,7 +6,7 @@ namespace Phpml;
interface Estimator
{
public function train(array $samples, array $targets);
public function train(array $samples, array $targets): void;
/**
* @return mixed

View File

@ -15,7 +15,7 @@ class TfIdfTransformer implements Transformer
public function __construct(array $samples = [])
{
if (!empty($samples)) {
if (count($samples) > 0) {
$this->fit($samples);
}
}

View File

@ -43,7 +43,7 @@ final class SelectKBest implements Transformer
public function fit(array $samples, ?array $targets = null): void
{
if ($targets === null || empty($targets)) {
if ($targets === null || count($targets) === 0) {
throw new InvalidArgumentException('The array has zero elements');
}

View File

@ -51,18 +51,13 @@ trait OneVsRest
protected function trainByLabel(array $samples, array $targets, array $allLabels = []): void
{
// Overwrites the current value if it exist. $allLabels must be provided for each partialTrain run.
if (!empty($allLabels)) {
$this->allLabels = $allLabels;
} else {
$this->allLabels = array_keys(array_count_values($targets));
}
$this->allLabels = count($allLabels) === 0 ? array_keys(array_count_values($targets)) : $allLabels;
sort($this->allLabels, SORT_STRING);
// If there are only two targets, then there is no need to perform OvR
if (count($this->allLabels) == 2) {
if (count($this->allLabels) === 2) {
// Init classifier if required.
if (empty($this->classifiers)) {
if (count($this->classifiers) === 0) {
$this->classifiers[0] = $this->getClassifierCopy();
}
@ -72,7 +67,7 @@ trait OneVsRest
foreach ($this->allLabels as $label) {
// Init classifier if required.
if (empty($this->classifiers[$label])) {
if (!isset($this->classifiers[$label])) {
$this->classifiers[$label] = $this->getClassifierCopy();
}
@ -92,10 +87,8 @@ trait OneVsRest
/**
* Returns an instance of the current class after cleaning up OneVsRest stuff.
*
* @return Classifier|OneVsRest
*/
protected function getClassifierCopy()
protected function getClassifierCopy(): Classifier
{
// Clone the current classifier, so that
// we don't mess up its variables while training
@ -111,7 +104,7 @@ trait OneVsRest
*/
protected function predictSample(array $sample)
{
if (count($this->allLabels) == 2) {
if (count($this->allLabels) === 2) {
return $this->classifiers[0]->predictSampleBinary($sample);
}

View File

@ -91,7 +91,7 @@ class ConjugateGradient extends GD
{
[$cost] = parent::gradient($theta);
return array_sum($cost) / $this->sampleCount;
return array_sum($cost) / (int) $this->sampleCount;
}
/**

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Phpml\Helper\Optimizer;
use Closure;
use Phpml\Exception\InvalidOperationException;
/**
* Batch version of Gradient Descent to optimize the weights
@ -59,6 +60,10 @@ class GD extends StochasticGD
$gradient = [];
$totalPenalty = 0;
if ($this->gradientCb === null) {
throw new InvalidOperationException('Gradient callback is not defined');
}
foreach ($this->samples as $index => $sample) {
$target = $this->targets[$index];

View File

@ -37,9 +37,9 @@ abstract class Optimizer
}
}
public function setTheta(array $theta)
public function setTheta(array $theta): self
{
if (count($theta) != $this->dimensions) {
if (count($theta) !== $this->dimensions) {
throw new InvalidArgumentException(sprintf('Number of values in the weights array should be %s', $this->dimensions));
}
@ -52,5 +52,5 @@ abstract class Optimizer
* Executes the optimization with the given samples & targets
* and returns the weights
*/
abstract public function runOptimization(array $samples, array $targets, Closure $gradientCb);
abstract public function runOptimization(array $samples, array $targets, Closure $gradientCb): array;
}

View File

@ -6,6 +6,7 @@ namespace Phpml\Helper\Optimizer;
use Closure;
use Phpml\Exception\InvalidArgumentException;
use Phpml\Exception\InvalidOperationException;
/**
* Stochastic Gradient Descent optimization method
@ -34,7 +35,7 @@ class StochasticGD extends Optimizer
*
* @var \Closure|null
*/
protected $gradientCb = null;
protected $gradientCb;
/**
* Maximum number of iterations used to train the model
@ -89,9 +90,9 @@ class StochasticGD extends Optimizer
$this->dimensions = $dimensions;
}
public function setTheta(array $theta)
public function setTheta(array $theta): Optimizer
{
if (count($theta) != $this->dimensions + 1) {
if (count($theta) !== $this->dimensions + 1) {
throw new InvalidArgumentException(sprintf('Number of values in the weights array should be %s', $this->dimensions + 1));
}
@ -156,7 +157,7 @@ class StochasticGD extends Optimizer
* The cost function to minimize and the gradient of the function are to be
* handled by the callback function provided as the third parameter of the method.
*/
public function runOptimization(array $samples, array $targets, Closure $gradientCb): ?array
public function runOptimization(array $samples, array $targets, Closure $gradientCb): array
{
$this->samples = $samples;
$this->targets = $targets;
@ -175,7 +176,7 @@ class StochasticGD extends Optimizer
// Save the best theta in the "pocket" so that
// any future set of theta worse than this will be disregarded
if ($bestTheta == null || $cost <= $bestScore) {
if ($bestTheta === null || $cost <= $bestScore) {
$bestTheta = $theta;
$bestScore = $cost;
}
@ -210,6 +211,10 @@ class StochasticGD extends Optimizer
$jValue = 0.0;
$theta = $this->theta;
if ($this->gradientCb === null) {
throw new InvalidOperationException('Gradient callback is not defined');
}
foreach ($this->samples as $index => $sample) {
$target = $this->targets[$index];
@ -254,7 +259,7 @@ class StochasticGD extends Optimizer
// Check if the last two cost values are almost the same
$costs = array_slice($this->costValues, -2);
if (count($costs) == 2 && abs($costs[1] - $costs[0]) < $this->threshold) {
if (count($costs) === 2 && abs($costs[1] - $costs[0]) < $this->threshold) {
return true;
}

View File

@ -6,5 +6,5 @@ namespace Phpml;
interface IncrementalEstimator
{
public function partialTrain(array $samples, array $targets, array $labels = []);
public function partialTrain(array $samples, array $targets, array $labels = []): void;
}

View File

@ -9,6 +9,9 @@ use Phpml\Exception\InvalidArgumentException;
class Comparison
{
/**
* @param mixed $a
* @param mixed $b
*
* @throws InvalidArgumentException
*/
public static function compare($a, $b, string $operator): bool

View File

@ -3,25 +3,25 @@
declare(strict_types=1);
/**
* Class to obtain eigenvalues and eigenvectors of a real matrix.
* Class to obtain eigenvalues and eigenvectors of a real matrix.
*
* If A is symmetric, then A = V*D*V' where the eigenvalue matrix D
* is diagonal and the eigenvector matrix V is orthogonal (i.e.
* A = V.times(D.times(V.transpose())) and V.times(V.transpose())
* equals the identity matrix).
* If A is symmetric, then A = V*D*V' where the eigenvalue matrix D
* is diagonal and the eigenvector matrix V is orthogonal (i.e.
* A = V.times(D.times(V.transpose())) and V.times(V.transpose())
* equals the identity matrix).
*
* If A is not symmetric, then the eigenvalue matrix D is block diagonal
* with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
* lambda + i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda]. The
* columns of V represent the eigenvectors in the sense that A*V = V*D,
* i.e. A.times(V) equals V.times(D). The matrix V may be badly
* conditioned, or even singular, so the validity of the equation
* A = V*D*inverse(V) depends upon V.cond().
* If A is not symmetric, then the eigenvalue matrix D is block diagonal
* with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
* lambda + i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda]. The
* columns of V represent the eigenvectors in the sense that A*V = V*D,
* i.e. A.times(V) equals V.times(D). The matrix V may be badly
* conditioned, or even singular, so the validity of the equation
* A = V*D*inverse(V) depends upon V.cond().
*
* @author Paul Meagher
* @license PHP v3.0
* @author Paul Meagher
* @license PHP v3.0
*
* @version 1.1
* @version 1.1
*
* Slightly changed to adapt the original code to PHP-ML library
* @date 2017/04/11
@ -36,83 +36,79 @@ use Phpml\Math\Matrix;
class EigenvalueDecomposition
{
/**
* Row and column dimension (square matrix).
* Row and column dimension (square matrix).
*
* @var int
* @var int
*/
private $n;
/**
* Internal symmetry flag.
* Arrays for internal storage of eigenvalues.
*
* @var bool
*/
private $symmetric;
/**
* Arrays for internal storage of eigenvalues.
*
* @var array
* @var array
*/
private $d = [];
/**
* @var array
*/
private $e = [];
/**
* Array for internal storage of eigenvectors.
* Array for internal storage of eigenvectors.
*
* @var array
* @var array
*/
private $V = [];
/**
* Array for internal storage of nonsymmetric Hessenberg form.
* Array for internal storage of nonsymmetric Hessenberg form.
*
* @var array
* @var array
*/
private $H = [];
/**
* Working storage for nonsymmetric algorithm.
* Working storage for nonsymmetric algorithm.
*
* @var array
* @var array
*/
private $ort = [];
/**
* Used for complex scalar division.
* Used for complex scalar division.
*
* @var float
* @var float
*/
private $cdivr;
/**
* @var float
*/
private $cdivi;
private $A;
/**
* Constructor: Check for symmetry, then construct the eigenvalue decomposition
* Constructor: Check for symmetry, then construct the eigenvalue decomposition
*/
public function __construct(array $Arg)
public function __construct(array $arg)
{
$this->A = $Arg;
$this->n = count($Arg[0]);
$this->symmetric = true;
$this->n = count($arg[0]);
$symmetric = true;
for ($j = 0; ($j < $this->n) & $this->symmetric; ++$j) {
for ($i = 0; ($i < $this->n) & $this->symmetric; ++$i) {
$this->symmetric = ($this->A[$i][$j] == $this->A[$j][$i]);
for ($j = 0; ($j < $this->n) & $symmetric; ++$j) {
for ($i = 0; ($i < $this->n) & $symmetric; ++$i) {
$symmetric = $arg[$i][$j] == $arg[$j][$i];
}
}
if ($this->symmetric) {
$this->V = $this->A;
if ($symmetric) {
$this->V = $arg;
// Tridiagonalize.
$this->tred2();
// Diagonalize.
$this->tql2();
} else {
$this->H = $this->A;
$this->H = $arg;
$this->ort = [];
// Reduce to Hessenberg form.
$this->orthes();
@ -148,7 +144,7 @@ class EigenvalueDecomposition
}
/**
* Return the real parts of the eigenvalues<br>
* Return the real parts of the eigenvalues<br>
* d = real(diag(D));
*/
public function getRealEigenvalues(): array
@ -157,7 +153,7 @@ class EigenvalueDecomposition
}
/**
* Return the imaginary parts of the eigenvalues <br>
* Return the imaginary parts of the eigenvalues <br>
* d = imag(diag(D))
*/
public function getImagEigenvalues(): array
@ -166,7 +162,7 @@ class EigenvalueDecomposition
}
/**
* Return the block diagonal eigenvalue matrix
* Return the block diagonal eigenvalue matrix
*/
public function getDiagonalEigenvalues(): array
{
@ -187,7 +183,7 @@ class EigenvalueDecomposition
}
/**
* Symmetric Householder reduction to tridiagonal form.
* Symmetric Householder reduction to tridiagonal form.
*/
private function tred2(): void
{
@ -308,12 +304,12 @@ class EigenvalueDecomposition
}
/**
* Symmetric tridiagonal QL algorithm.
* Symmetric tridiagonal QL algorithm.
*
* This is derived from the Algol procedures tql2, by
* Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
* Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
* Fortran subroutine in EISPACK.
* This is derived from the Algol procedures tql2, by
* Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
* Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
* Fortran subroutine in EISPACK.
*/
private function tql2(): void
{
@ -341,10 +337,7 @@ class EigenvalueDecomposition
// If m == l, $this->d[l] is an eigenvalue,
// otherwise, iterate.
if ($m > $l) {
$iter = 0;
do {
// Could check iteration count here.
++$iter;
// Compute implicit shift
$g = $this->d[$l];
$p = ($this->d[$l + 1] - $g) / (2.0 * $this->e[$l]);
@ -423,12 +416,12 @@ class EigenvalueDecomposition
}
/**
* Nonsymmetric reduction to Hessenberg form.
* Nonsymmetric reduction to Hessenberg form.
*
* This is derived from the Algol procedures orthes and ortran,
* by Martin and Wilkinson, Handbook for Auto. Comp.,
* Vol.ii-Linear Algebra, and the corresponding
* Fortran subroutines in EISPACK.
* This is derived from the Algol procedures orthes and ortran,
* by Martin and Wilkinson, Handbook for Auto. Comp.,
* Vol.ii-Linear Algebra, and the corresponding
* Fortran subroutines in EISPACK.
*/
private function orthes(): void
{
@ -541,12 +534,12 @@ class EigenvalueDecomposition
}
/**
* Nonsymmetric reduction from Hessenberg to real Schur form.
* Nonsymmetric reduction from Hessenberg to real Schur form.
*
* Code is derived from the Algol procedure hqr2,
* by Martin and Wilkinson, Handbook for Auto. Comp.,
* Vol.ii-Linear Algebra, and the corresponding
* Fortran subroutine in EISPACK.
* Code is derived from the Algol procedure hqr2,
* by Martin and Wilkinson, Handbook for Auto. Comp.,
* Vol.ii-Linear Algebra, and the corresponding
* Fortran subroutine in EISPACK.
*/
private function hqr2(): void
{
@ -911,7 +904,7 @@ class EigenvalueDecomposition
$y = $this->H[$i + 1][$i];
$vr = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i] - $q * $q;
$vi = ($this->d[$i] - $p) * 2.0 * $q;
if ($vr == 0.0 & $vi == 0.0) {
if ($vr == 0.0 && $vi == 0.0) {
$vr = $eps * $norm * (abs($w) + abs($q) + abs($x) + abs($y) + abs($z));
}
@ -943,7 +936,7 @@ class EigenvalueDecomposition
// Vectors of isolated roots
for ($i = 0; $i < $nn; ++$i) {
if ($i < $low | $i > $high) {
if ($i < $low || $i > $high) {
for ($j = $i; $j < $nn; ++$j) {
$this->V[$i][$j] = $this->H[$i][$j];
}

View File

@ -80,7 +80,7 @@ class LUDecomposition
*/
public function __construct(Matrix $A)
{
if ($A->getRows() != $A->getColumns()) {
if ($A->getRows() !== $A->getColumns()) {
throw new MatrixException('Matrix is not square matrix');
}
@ -118,7 +118,7 @@ class LUDecomposition
// Find pivot and exchange if necessary.
$p = $j;
for ($i = $j + 1; $i < $this->m; ++$i) {
if (abs($LUcolj[$i]) > abs($LUcolj[$p])) {
if (abs($LUcolj[$i] ?? 0) > abs($LUcolj[$p] ?? 0)) {
$p = $i;
}
}
@ -204,7 +204,7 @@ class LUDecomposition
*
* @see getPivot
*/
public function getDoublePivot()
public function getDoublePivot(): array
{
return $this->getPivot();
}

View File

@ -89,7 +89,7 @@ class Matrix
/**
* @throws MatrixException
*/
public function getColumnValues($column): array
public function getColumnValues(int $column): array
{
if ($column >= $this->columns) {
throw new MatrixException('Column out of range');
@ -125,7 +125,7 @@ class Matrix
public function transpose(): self
{
if ($this->rows == 1) {
if ($this->rows === 1) {
$matrix = array_map(function ($el) {
return [$el];
}, $this->matrix[0]);
@ -138,7 +138,7 @@ class Matrix
public function multiply(self $matrix): self
{
if ($this->columns != $matrix->getRows()) {
if ($this->columns !== $matrix->getRows()) {
throw new InvalidArgumentException('Inconsistent matrix supplied');
}
@ -166,6 +166,9 @@ class Matrix
return new self($product, false);
}
/**
* @param float|int $value
*/
public function divideByScalar($value): self
{
$newMatrix = [];
@ -178,6 +181,9 @@ class Matrix
return new self($newMatrix, false);
}
/**
* @param float|int $value
*/
public function multiplyByScalar($value): self
{
$newMatrix = [];

View File

@ -14,7 +14,7 @@ class Product
$product = 0;
foreach ($a as $index => $value) {
if (is_numeric($value) && is_numeric($b[$index])) {
$product += $value * $b[$index];
$product += (float) $value * (float) $b[$index];
}
}

View File

@ -131,7 +131,7 @@ class Set implements IteratorAggregate
*/
public function containsAll(array $elements): bool
{
return !array_diff($elements, $this->elements);
return count(array_diff($elements, $this->elements)) === 0;
}
/**
@ -149,7 +149,7 @@ class Set implements IteratorAggregate
public function isEmpty(): bool
{
return $this->cardinality() == 0;
return $this->cardinality() === 0;
}
public function cardinality(): int

View File

@ -31,7 +31,7 @@ final class ANOVA
$samplesPerClass = array_map(function (array $class): int {
return count($class);
}, $samples);
$allSamples = array_sum($samplesPerClass);
$allSamples = (int) array_sum($samplesPerClass);
$ssAllSamples = self::sumOfSquaresPerFeature($samples);
$sumSamples = self::sumOfFeaturesPerClass($samples);
$squareSumSamples = self::sumOfSquares($sumSamples);

View File

@ -15,11 +15,11 @@ class Covariance
*/
public static function fromXYArrays(array $x, array $y, bool $sample = true, ?float $meanX = null, ?float $meanY = null): float
{
if (empty($x) || empty($y)) {
$n = count($x);
if ($n === 0 || count($y) === 0) {
throw new InvalidArgumentException('The array has zero elements');
}
$n = count($x);
if ($sample && $n === 1) {
throw new InvalidArgumentException('The array must have at least 2 elements');
}
@ -53,7 +53,7 @@ class Covariance
*/
public static function fromDataset(array $data, int $i, int $k, bool $sample = true, ?float $meanX = null, ?float $meanY = null): float
{
if (empty($data)) {
if (count($data) === 0) {
throw new InvalidArgumentException('The array has zero elements');
}
@ -87,7 +87,7 @@ class Covariance
// with a slight cost of CPU utilization.
$sum = 0.0;
foreach ($data as $row) {
$val = [];
$val = [0, 0];
foreach ($row as $index => $col) {
if ($index == $i) {
$val[0] = $col - $meanX;

View File

@ -58,7 +58,7 @@ class Mean
*/
private static function checkArrayLength(array $array): void
{
if (empty($array)) {
if (count($array) === 0) {
throw new InvalidArgumentException('The array has zero elements');
}
}

View File

@ -13,12 +13,11 @@ class StandardDeviation
*/
public static function population(array $numbers, bool $sample = true): float
{
if (empty($numbers)) {
$n = count($numbers);
if ($n === 0) {
throw new InvalidArgumentException('The array has zero elements');
}
$n = count($numbers);
if ($sample && $n === 1) {
throw new InvalidArgumentException('The array must have at least 2 elements');
}
@ -33,7 +32,7 @@ class StandardDeviation
--$n;
}
return sqrt((float) ($carry / $n));
return sqrt($carry / $n);
}
/**
@ -44,7 +43,7 @@ class StandardDeviation
*/
public static function sumOfSquares(array $numbers): float
{
if (empty($numbers)) {
if (count($numbers) === 0) {
throw new InvalidArgumentException('The array has zero elements');
}

View File

@ -142,9 +142,9 @@ class ClassificationReport
private function computeMicroAverage(): void
{
$truePositive = array_sum($this->truePositive);
$falsePositive = array_sum($this->falsePositive);
$falseNegative = array_sum($this->falseNegative);
$truePositive = (int) array_sum($this->truePositive);
$falsePositive = (int) array_sum($this->falsePositive);
$falseNegative = (int) array_sum($this->falseNegative);
$precision = $this->computePrecision($truePositive, $falsePositive);
$recall = $this->computeRecall($truePositive, $falseNegative);
@ -227,6 +227,6 @@ class ClassificationReport
$labels = array_values(array_unique(array_merge($actualLabels, $predictedLabels)));
sort($labels);
return array_combine($labels, array_fill(0, count($labels), 0));
return (array) array_combine($labels, array_fill(0, count($labels), 0));
}
}

View File

@ -8,13 +8,13 @@ class ConfusionMatrix
{
public static function compute(array $actualLabels, array $predictedLabels, array $labels = []): array
{
$labels = !empty($labels) ? array_flip($labels) : self::getUniqueLabels($actualLabels);
$labels = count($labels) === 0 ? self::getUniqueLabels($actualLabels) : array_flip($labels);
$matrix = self::generateMatrixWithZeros($labels);
foreach ($actualLabels as $index => $actual) {
$predicted = $predictedLabels[$index];
if (!isset($labels[$actual]) || !isset($labels[$predicted])) {
if (!isset($labels[$actual], $labels[$predicted])) {
continue;
}

View File

@ -16,7 +16,7 @@ class ModelManager
}
$serialized = serialize($estimator);
if (empty($serialized)) {
if (!isset($serialized[0])) {
throw new SerializeException(sprintf('Class "%s" can not be serialized.', gettype($estimator)));
}
@ -32,7 +32,7 @@ class ModelManager
throw new FileException(sprintf('File "%s" can\'t be open.', basename($filepath)));
}
$object = unserialize(file_get_contents($filepath));
$object = unserialize((string) file_get_contents($filepath), [Estimator::class]);
if ($object === false) {
throw new SerializeException(sprintf('"%s" can not be unserialized.', basename($filepath)));
}

View File

@ -13,7 +13,7 @@ interface Network
public function getOutput(): array;
public function addLayer(Layer $layer);
public function addLayer(Layer $layer): void;
/**
* @return Layer[]

View File

@ -61,7 +61,7 @@ abstract class MultilayerPerceptron extends LayeredNetwork implements Estimator,
*/
public function __construct(int $inputLayerFeatures, array $hiddenLayers, array $classes, int $iterations = 10000, ?ActivationFunction $activationFunction = null, float $learningRate = 1)
{
if (empty($hiddenLayers)) {
if (count($hiddenLayers) === 0) {
throw new InvalidArgumentException('Provide at least 1 hidden layer');
}
@ -95,7 +95,7 @@ abstract class MultilayerPerceptron extends LayeredNetwork implements Estimator,
*/
public function partialTrain(array $samples, array $targets, array $classes = []): void
{
if (!empty($classes) && array_values($classes) !== $this->classes) {
if (count($classes) > 0 && array_values($classes) !== $this->classes) {
// We require the list of classes in the constructor.
throw new InvalidArgumentException(
'The provided classes don\'t match the classes provided in the constructor'
@ -126,7 +126,7 @@ abstract class MultilayerPerceptron extends LayeredNetwork implements Estimator,
/**
* @param mixed $target
*/
abstract protected function trainSample(array $sample, $target);
abstract protected function trainSample(array $sample, $target): void;
/**
* @return mixed

View File

@ -49,6 +49,6 @@ class Synapse
protected function generateRandomWeight(): float
{
return 1 / random_int(5, 25) * (random_int(0, 1) ? -1 : 1);
return (1 / random_int(5, 25) * random_int(0, 1)) > 0 ? -1 : 1;
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Phpml\NeuralNetwork;
interface Training
{
public function train(array $samples, array $targets);
}

View File

@ -26,7 +26,7 @@ class DataTransformer
public static function testSet(array $samples): string
{
if (empty($samples)) {
if (count($samples) === 0) {
throw new InvalidArgumentException('The array has zero elements');
}
@ -62,7 +62,7 @@ class DataTransformer
$predictions = explode(PHP_EOL, trim($rawPredictions));
$header = array_shift($predictions);
$headerColumns = explode(' ', $header);
$headerColumns = explode(' ', (string) $header);
array_shift($headerColumns);
$columnLabels = [];

View File

@ -165,7 +165,7 @@ class SupportVectorMachine
);
}
$this->model = file_get_contents($modelFileName);
$this->model = (string) file_get_contents($modelFileName);
unlink($modelFileName);
}
@ -241,7 +241,7 @@ class SupportVectorMachine
unlink($testSetFileName);
unlink($modelFileName);
$predictions = file_get_contents($outputFileName);
$predictions = (string) file_get_contents($outputFileName);
unlink($outputFileName);

View File

@ -4,10 +4,17 @@ declare(strict_types=1);
namespace Phpml\Tokenization;
use Phpml\Exception\InvalidArgumentException;
class WhitespaceTokenizer implements Tokenizer
{
public function tokenize(string $text): array
{
return preg_split('/[\pZ\pC]+/u', $text, -1, PREG_SPLIT_NO_EMPTY);
$substrings = preg_split('/[\pZ\pC]+/u', $text, -1, PREG_SPLIT_NO_EMPTY);
if ($substrings === false) {
throw new InvalidArgumentException('preg_split failed on: '.$text);
}
return $substrings;
}
}

View File

@ -11,6 +11,9 @@ use ReflectionClass;
class AprioriTest extends TestCase
{
/**
* @var array
*/
private $sampleGreek = [
['alpha', 'beta', 'epsilon'],
['alpha', 'beta', 'theta'],
@ -18,6 +21,9 @@ class AprioriTest extends TestCase
['alpha', 'beta', 'theta'],
];
/**
* @var array
*/
private $sampleChars = [
['E', 'D', 'N', 'E+N', 'EN'],
['E', 'R', 'N', 'E+R', 'E+N', 'ER', 'EN'],
@ -31,6 +37,9 @@ class AprioriTest extends TestCase
['N'],
];
/**
* @var array
*/
private $sampleBasket = [
[1, 2, 3, 4],
[1, 2, 4],
@ -48,16 +57,16 @@ class AprioriTest extends TestCase
$predicted = $apriori->predict([['alpha', 'epsilon'], ['beta', 'theta']]);
$this->assertCount(2, $predicted);
$this->assertEquals([['beta']], $predicted[0]);
$this->assertEquals([['alpha']], $predicted[1]);
self::assertCount(2, $predicted);
self::assertEquals([['beta']], $predicted[0]);
self::assertEquals([['alpha']], $predicted[1]);
}
public function testPowerSet(): void
{
$apriori = new Apriori();
$this->assertCount(8, self::invoke($apriori, 'powerSet', [['a', 'b', 'c']]));
self::assertCount(8, self::invoke($apriori, 'powerSet', [['a', 'b', 'c']]));
}
public function testApriori(): void
@ -67,13 +76,13 @@ class AprioriTest extends TestCase
$L = $apriori->apriori();
$this->assertCount(4, $L[2]);
$this->assertTrue(self::invoke($apriori, 'contains', [$L[2], [1, 2]]));
$this->assertFalse(self::invoke($apriori, 'contains', [$L[2], [1, 3]]));
$this->assertFalse(self::invoke($apriori, 'contains', [$L[2], [1, 4]]));
$this->assertTrue(self::invoke($apriori, 'contains', [$L[2], [2, 3]]));
$this->assertTrue(self::invoke($apriori, 'contains', [$L[2], [2, 4]]));
$this->assertTrue(self::invoke($apriori, 'contains', [$L[2], [3, 4]]));
self::assertCount(4, $L[2]);
self::assertTrue(self::invoke($apriori, 'contains', [$L[2], [1, 2]]));
self::assertFalse(self::invoke($apriori, 'contains', [$L[2], [1, 3]]));
self::assertFalse(self::invoke($apriori, 'contains', [$L[2], [1, 4]]));
self::assertTrue(self::invoke($apriori, 'contains', [$L[2], [2, 3]]));
self::assertTrue(self::invoke($apriori, 'contains', [$L[2], [2, 4]]));
self::assertTrue(self::invoke($apriori, 'contains', [$L[2], [3, 4]]));
}
public function testAprioriEmpty(): void
@ -85,7 +94,7 @@ class AprioriTest extends TestCase
$L = $apriori->apriori();
$this->assertEmpty($L);
self::assertEmpty($L);
}
public function testAprioriSingleItem(): void
@ -97,8 +106,8 @@ class AprioriTest extends TestCase
$L = $apriori->apriori();
$this->assertEquals([1], array_keys($L));
$this->assertEquals([['a']], $L[1]);
self::assertEquals([1], array_keys($L));
self::assertEquals([['a']], $L[1]);
}
public function testAprioriL3(): void
@ -110,7 +119,7 @@ class AprioriTest extends TestCase
$L = $apriori->apriori();
$this->assertEquals([['a', 'b', 'c']], $L[3]);
self::assertEquals([['a', 'b', 'c']], $L[3]);
}
public function testGetRules(): void
@ -118,7 +127,7 @@ class AprioriTest extends TestCase
$apriori = new Apriori(0.4, 0.8);
$apriori->train($this->sampleChars, []);
$this->assertCount(19, $apriori->getRules());
self::assertCount(19, $apriori->getRules());
}
public function testGetRulesSupportAndConfidence(): void
@ -130,14 +139,14 @@ class AprioriTest extends TestCase
$rules = $apriori->getRules();
$this->assertCount(4, $rules);
$this->assertContains([
self::assertCount(4, $rules);
self::assertContains([
Apriori::ARRAY_KEY_ANTECEDENT => ['a'],
Apriori::ARRAY_KEY_CONSEQUENT => ['b'],
Apriori::ARRAY_KEY_SUPPORT => 0.5,
Apriori::ARRAY_KEY_CONFIDENCE => 0.5,
], $rules);
$this->assertContains([
self::assertContains([
Apriori::ARRAY_KEY_ANTECEDENT => ['b'],
Apriori::ARRAY_KEY_CONSEQUENT => ['a'],
Apriori::ARRAY_KEY_SUPPORT => 0.5,
@ -149,14 +158,14 @@ class AprioriTest extends TestCase
{
$apriori = new Apriori();
$this->assertCount(6, self::invoke($apriori, 'antecedents', [['a', 'b', 'c']]));
self::assertCount(6, self::invoke($apriori, 'antecedents', [['a', 'b', 'c']]));
}
public function testItems(): void
{
$apriori = new Apriori();
$apriori->train($this->sampleGreek, []);
$this->assertCount(4, self::invoke($apriori, 'items', []));
self::assertCount(4, self::invoke($apriori, 'items', []));
}
public function testFrequent(): void
@ -164,8 +173,8 @@ class AprioriTest extends TestCase
$apriori = new Apriori(0.51);
$apriori->train($this->sampleGreek, []);
$this->assertCount(0, self::invoke($apriori, 'frequent', [[['epsilon'], ['theta']]]));
$this->assertCount(2, self::invoke($apriori, 'frequent', [[['alpha'], ['beta']]]));
self::assertCount(0, self::invoke($apriori, 'frequent', [[['epsilon'], ['theta']]]));
self::assertCount(2, self::invoke($apriori, 'frequent', [[['alpha'], ['beta']]]));
}
public function testCandidates(): void
@ -175,10 +184,10 @@ class AprioriTest extends TestCase
$candidates = self::invoke($apriori, 'candidates', [[['alpha'], ['beta'], ['theta']]]);
$this->assertCount(3, $candidates);
$this->assertEquals(['alpha', 'beta'], $candidates[0]);
$this->assertEquals(['alpha', 'theta'], $candidates[1]);
$this->assertEquals(['beta', 'theta'], $candidates[2]);
self::assertCount(3, $candidates);
self::assertEquals(['alpha', 'beta'], $candidates[0]);
self::assertEquals(['alpha', 'theta'], $candidates[1]);
self::assertEquals(['beta', 'theta'], $candidates[2]);
}
public function testConfidence(): void
@ -186,8 +195,8 @@ class AprioriTest extends TestCase
$apriori = new Apriori();
$apriori->train($this->sampleGreek, []);
$this->assertEquals(0.5, self::invoke($apriori, 'confidence', [['alpha', 'beta', 'theta'], ['alpha', 'beta']]));
$this->assertEquals(1, self::invoke($apriori, 'confidence', [['alpha', 'beta'], ['alpha']]));
self::assertEquals(0.5, self::invoke($apriori, 'confidence', [['alpha', 'beta', 'theta'], ['alpha', 'beta']]));
self::assertEquals(1, self::invoke($apriori, 'confidence', [['alpha', 'beta'], ['alpha']]));
}
public function testSupport(): void
@ -195,8 +204,8 @@ class AprioriTest extends TestCase
$apriori = new Apriori();
$apriori->train($this->sampleGreek, []);
$this->assertEquals(1.0, self::invoke($apriori, 'support', [['alpha', 'beta']]));
$this->assertEquals(0.5, self::invoke($apriori, 'support', [['epsilon']]));
self::assertEquals(1.0, self::invoke($apriori, 'support', [['alpha', 'beta']]));
self::assertEquals(0.5, self::invoke($apriori, 'support', [['epsilon']]));
}
public function testFrequency(): void
@ -204,35 +213,35 @@ class AprioriTest extends TestCase
$apriori = new Apriori();
$apriori->train($this->sampleGreek, []);
$this->assertEquals(4, self::invoke($apriori, 'frequency', [['alpha', 'beta']]));
$this->assertEquals(2, self::invoke($apriori, 'frequency', [['epsilon']]));
self::assertEquals(4, self::invoke($apriori, 'frequency', [['alpha', 'beta']]));
self::assertEquals(2, self::invoke($apriori, 'frequency', [['epsilon']]));
}
public function testContains(): void
{
$apriori = new Apriori();
$this->assertTrue(self::invoke($apriori, 'contains', [[['a'], ['b']], ['a']]));
$this->assertTrue(self::invoke($apriori, 'contains', [[[1, 2]], [1, 2]]));
$this->assertFalse(self::invoke($apriori, 'contains', [[['a'], ['b']], ['c']]));
self::assertTrue(self::invoke($apriori, 'contains', [[['a'], ['b']], ['a']]));
self::assertTrue(self::invoke($apriori, 'contains', [[[1, 2]], [1, 2]]));
self::assertFalse(self::invoke($apriori, 'contains', [[['a'], ['b']], ['c']]));
}
public function testSubset(): void
{
$apriori = new Apriori();
$this->assertTrue(self::invoke($apriori, 'subset', [['a', 'b'], ['a']]));
$this->assertTrue(self::invoke($apriori, 'subset', [['a'], ['a']]));
$this->assertFalse(self::invoke($apriori, 'subset', [['a'], ['a', 'b']]));
self::assertTrue(self::invoke($apriori, 'subset', [['a', 'b'], ['a']]));
self::assertTrue(self::invoke($apriori, 'subset', [['a'], ['a']]));
self::assertFalse(self::invoke($apriori, 'subset', [['a'], ['a', 'b']]));
}
public function testEquals(): void
{
$apriori = new Apriori();
$this->assertTrue(self::invoke($apriori, 'equals', [['a'], ['a']]));
$this->assertFalse(self::invoke($apriori, 'equals', [['a'], []]));
$this->assertFalse(self::invoke($apriori, 'equals', [['a'], ['b', 'a']]));
self::assertTrue(self::invoke($apriori, 'equals', [['a'], ['a']]));
self::assertFalse(self::invoke($apriori, 'equals', [['a'], []]));
self::assertFalse(self::invoke($apriori, 'equals', [['a'], ['b', 'a']]));
}
public function testSaveAndRestore(): void
@ -243,14 +252,14 @@ class AprioriTest extends TestCase
$testSamples = [['alpha', 'epsilon'], ['beta', 'theta']];
$predicted = $classifier->predict($testSamples);
$filename = 'apriori-test-'.random_int(100, 999).'-'.uniqid();
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filename = 'apriori-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
/**
@ -261,7 +270,7 @@ class AprioriTest extends TestCase
*
* @return mixed
*/
private static function invoke(&$object, string $method, array $params = [])
private static function invoke(Apriori $object, string $method, array $params = [])
{
$reflection = new ReflectionClass(get_class($object));
$method = $reflection->getMethod($method);

View File

@ -21,7 +21,10 @@ class DecisionTreeLeafTest extends TestCase
$leaf->rightLeaf = $rightLeaf;
$this->assertEquals('<table ><tr><td colspan=3 align=center style=\'border:1px solid;\'><b>col_0 =1</b><br>Gini: 0.00</td></tr><tr><td></td><td>&nbsp;</td><td valign=top align=right><b>No |</b><br><table ><tr><td colspan=3 align=center style=\'border:1px solid;\'><b>col_1 <= 2</b><br>Gini: 0.00</td></tr></table></td></tr></table>', $leaf->getHTML());
self::assertEquals(
'<table ><tr><td colspan=3 align=center style=\'border:1px solid;\'><b>col_0 =1</b><br>Gini: 0.00</td></tr><tr><td></td><td>&nbsp;</td><td valign=top align=right><b>No |</b><br><table ><tr><td colspan=3 align=center style=\'border:1px solid;\'><b>col_1 <= 2</b><br>Gini: 0.00</td></tr></table></td></tr></table>',
$leaf->getHTML()
);
}
public function testNodeImpurityDecreaseShouldBeZeroWhenLeafIsTerminal(): void
@ -29,7 +32,7 @@ class DecisionTreeLeafTest extends TestCase
$leaf = new DecisionTreeLeaf();
$leaf->isTerminal = true;
$this->assertEquals(0.0, $leaf->getNodeImpurityDecrease(1));
self::assertEquals(0.0, $leaf->getNodeImpurityDecrease(1));
}
public function testNodeImpurityDecrease(): void
@ -45,6 +48,6 @@ class DecisionTreeLeafTest extends TestCase
$leaf->rightLeaf->records = [];
$leaf->rightLeaf->giniIndex = 0.3;
$this->assertSame(0.75, $leaf->getNodeImpurityDecrease(2));
self::assertSame(0.75, $leaf->getNodeImpurityDecrease(2));
}
}

View File

@ -10,6 +10,9 @@ use PHPUnit\Framework\TestCase;
class DecisionTreeTest extends TestCase
{
/**
* @var array
*/
private $data = [
['sunny', 85, 85, 'false', 'Dont_play'],
['sunny', 80, 90, 'true', 'Dont_play'],
@ -27,26 +30,27 @@ class DecisionTreeTest extends TestCase
['rain', 71, 80, 'true', 'Dont_play'],
];
/**
* @var array
*/
private $extraData = [
['scorching', 90, 95, 'false', 'Dont_play'],
['scorching', 100, 93, 'true', 'Dont_play'],
];
public function testPredictSingleSample()
public function testPredictSingleSample(): void
{
[$data, $targets] = $this->getData($this->data);
$classifier = new DecisionTree(5);
$classifier->train($data, $targets);
$this->assertEquals('Dont_play', $classifier->predict(['sunny', 78, 72, 'false']));
$this->assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
$this->assertEquals('Dont_play', $classifier->predict(['rain', 60, 60, 'true']));
self::assertEquals('Dont_play', $classifier->predict(['sunny', 78, 72, 'false']));
self::assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
self::assertEquals('Dont_play', $classifier->predict(['rain', 60, 60, 'true']));
[$data, $targets] = $this->getData($this->extraData);
$classifier->train($data, $targets);
$this->assertEquals('Dont_play', $classifier->predict(['scorching', 95, 90, 'true']));
$this->assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
return $classifier;
self::assertEquals('Dont_play', $classifier->predict(['scorching', 95, 90, 'true']));
self::assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
}
public function testSaveAndRestore(): void
@ -58,14 +62,14 @@ class DecisionTreeTest extends TestCase
$testSamples = [['sunny', 78, 72, 'false'], ['overcast', 60, 60, 'false']];
$predicted = $classifier->predict($testSamples);
$filename = 'decision-tree-test-'.random_int(100, 999).'-'.uniqid();
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filename = 'decision-tree-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
public function testTreeDepth(): void
@ -73,10 +77,10 @@ class DecisionTreeTest extends TestCase
[$data, $targets] = $this->getData($this->data);
$classifier = new DecisionTree(5);
$classifier->train($data, $targets);
$this->assertTrue($classifier->actualDepth <= 5);
self::assertTrue($classifier->actualDepth <= 5);
}
private function getData($input)
private function getData(array $input): array
{
$targets = array_column($input, 4);
array_walk($input, function (&$v): void {

View File

@ -37,27 +37,27 @@ class AdaBoostTest extends TestCase
$targets = [0, 0, 0, 1, 1, 1];
$classifier = new AdaBoost();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.2]));
$this->assertEquals(0, $classifier->predict([0.1, 0.99]));
$this->assertEquals(1, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0.1, 0.2]));
self::assertEquals(0, $classifier->predict([0.1, 0.99]));
self::assertEquals(1, $classifier->predict([1.1, 0.8]));
// OR problem
$samples = [[0, 0], [0.1, 0.2], [0.2, 0.1], [1, 0], [0, 1], [1, 1]];
$targets = [0, 0, 0, 1, 1, 1];
$classifier = new AdaBoost();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.2]));
$this->assertEquals(1, $classifier->predict([0.1, 0.99]));
$this->assertEquals(1, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0.1, 0.2]));
self::assertEquals(1, $classifier->predict([0.1, 0.99]));
self::assertEquals(1, $classifier->predict([1.1, 0.8]));
// XOR problem
$samples = [[0.1, 0.2], [1., 1.], [0.9, 0.8], [0., 1.], [1., 0.], [0.2, 0.8]];
$targets = [0, 0, 0, 1, 1, 1];
$classifier = new AdaBoost(5);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.1]));
$this->assertEquals(1, $classifier->predict([0, 0.999]));
$this->assertEquals(0, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0.1, 0.1]));
self::assertEquals(1, $classifier->predict([0, 0.999]));
self::assertEquals(0, $classifier->predict([1.1, 0.8]));
}
public function testSaveAndRestore(): void
@ -70,13 +70,13 @@ class AdaBoostTest extends TestCase
$testSamples = [[0, 1], [1, 1], [0.2, 0.1]];
$predicted = $classifier->predict($testSamples);
$filename = 'adaboost-test-'.random_int(100, 999).'-'.uniqid();
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filename = 'adaboost-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Phpml\Tests\Classification\Ensemble;
use Phpml\Classification\Classifier;
use Phpml\Classification\DecisionTree;
use Phpml\Classification\Ensemble\Bagging;
use Phpml\Classification\NaiveBayes;
@ -13,6 +14,9 @@ use PHPUnit\Framework\TestCase;
class BaggingTest extends TestCase
{
/**
* @var array
*/
private $data = [
['sunny', 85, 85, 'false', 'Dont_play'],
['sunny', 80, 90, 'true', 'Dont_play'],
@ -30,6 +34,9 @@ class BaggingTest extends TestCase
['rain', 71, 80, 'true', 'Dont_play'],
];
/**
* @var array
*/
private $extraData = [
['scorching', 90, 95, 'false', 'Dont_play'],
['scorching', 0, 0, 'false', 'Dont_play'],
@ -49,14 +56,14 @@ class BaggingTest extends TestCase
$classifier = $this->getClassifier();
// Testing with default options
$classifier->train($data, $targets);
$this->assertEquals('Dont_play', $classifier->predict(['sunny', 78, 72, 'false']));
$this->assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
$this->assertEquals('Dont_play', $classifier->predict(['rain', 60, 60, 'true']));
self::assertEquals('Dont_play', $classifier->predict(['sunny', 78, 72, 'false']));
self::assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
self::assertEquals('Dont_play', $classifier->predict(['rain', 60, 60, 'true']));
[$data, $targets] = $this->getData($this->extraData);
$classifier->train($data, $targets);
$this->assertEquals('Dont_play', $classifier->predict(['scorching', 95, 90, 'true']));
$this->assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
self::assertEquals('Dont_play', $classifier->predict(['scorching', 95, 90, 'true']));
self::assertEquals('Play', $classifier->predict(['overcast', 60, 60, 'false']));
}
public function testSaveAndRestore(): void
@ -68,14 +75,14 @@ class BaggingTest extends TestCase
$testSamples = [['sunny', 78, 72, 'false'], ['overcast', 60, 60, 'false']];
$predicted = $classifier->predict($testSamples);
$filename = 'bagging-test-'.random_int(100, 999).'-'.uniqid();
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filename = 'bagging-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
public function testBaseClassifiers(): void
@ -94,12 +101,15 @@ class BaggingTest extends TestCase
foreach ($testData as $test) {
$result = $classifier->predict($test);
$baseResult = $classifier->predict($test);
$this->assertEquals($result, $baseResult);
self::assertEquals($result, $baseResult);
}
}
}
protected function getClassifier($numBaseClassifiers = 50)
/**
* @return Bagging
*/
protected function getClassifier(int $numBaseClassifiers = 50): Classifier
{
$classifier = new Bagging($numBaseClassifiers);
$classifier->setSubsetRatio(1.0);
@ -108,7 +118,7 @@ class BaggingTest extends TestCase
return $classifier;
}
protected function getAvailableBaseClassifiers()
protected function getAvailableBaseClassifiers(): array
{
return [
DecisionTree::class => ['depth' => 5],
@ -116,7 +126,7 @@ class BaggingTest extends TestCase
];
}
private function getData($input)
private function getData(array $input): array
{
// Populating input data to a size large enough
// for base classifiers that they can work with a subset of it

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Phpml\Tests\Classification\Ensemble;
use Phpml\Classification\Classifier;
use Phpml\Classification\DecisionTree;
use Phpml\Classification\Ensemble\RandomForest;
use Phpml\Classification\NaiveBayes;
@ -47,7 +48,10 @@ class RandomForestTest extends BaggingTest
$classifier->setFeatureSubsetRatio('pow');
}
protected function getClassifier($numBaseClassifiers = 50)
/**
* @return RandomForest
*/
protected function getClassifier(int $numBaseClassifiers = 50): Classifier
{
$classifier = new RandomForest($numBaseClassifiers);
$classifier->setFeatureSubsetRatio('log');
@ -55,7 +59,7 @@ class RandomForestTest extends BaggingTest
return $classifier;
}
protected function getAvailableBaseClassifiers()
protected function getAvailableBaseClassifiers(): array
{
return [DecisionTree::class => ['depth' => 5]];
}

View File

@ -19,15 +19,15 @@ class KNearestNeighborsTest extends TestCase
$classifier = new KNearestNeighbors();
$classifier->train($samples, $labels);
$this->assertEquals('b', $classifier->predict([3, 2]));
$this->assertEquals('b', $classifier->predict([5, 1]));
$this->assertEquals('b', $classifier->predict([4, 3]));
$this->assertEquals('b', $classifier->predict([4, -5]));
self::assertEquals('b', $classifier->predict([3, 2]));
self::assertEquals('b', $classifier->predict([5, 1]));
self::assertEquals('b', $classifier->predict([4, 3]));
self::assertEquals('b', $classifier->predict([4, -5]));
$this->assertEquals('a', $classifier->predict([2, 3]));
$this->assertEquals('a', $classifier->predict([1, 2]));
$this->assertEquals('a', $classifier->predict([1, 5]));
$this->assertEquals('a', $classifier->predict([3, 10]));
self::assertEquals('a', $classifier->predict([2, 3]));
self::assertEquals('a', $classifier->predict([1, 2]));
self::assertEquals('a', $classifier->predict([1, 5]));
self::assertEquals('a', $classifier->predict([3, 10]));
}
public function testPredictArrayOfSamples(): void
@ -42,7 +42,7 @@ class KNearestNeighborsTest extends TestCase
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$this->assertEquals($testLabels, $predicted);
self::assertEquals($testLabels, $predicted);
}
public function testPredictArrayOfSamplesUsingChebyshevDistanceMetric(): void
@ -57,7 +57,7 @@ class KNearestNeighborsTest extends TestCase
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$this->assertEquals($testLabels, $predicted);
self::assertEquals($testLabels, $predicted);
}
public function testSaveAndRestore(): void
@ -73,12 +73,12 @@ class KNearestNeighborsTest extends TestCase
$predicted = $classifier->predict($testSamples);
$filename = 'knearest-neighbors-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
}

View File

@ -31,18 +31,18 @@ class AdalineTest extends TestCase
$targets = [0, 0, 0, 1];
$classifier = new Adaline();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.2]));
$this->assertEquals(0, $classifier->predict([0.1, 0.99]));
$this->assertEquals(1, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0.1, 0.2]));
self::assertEquals(0, $classifier->predict([0.1, 0.99]));
self::assertEquals(1, $classifier->predict([1.1, 0.8]));
// OR problem
$samples = [[0, 0], [1, 0], [0, 1], [1, 1]];
$targets = [0, 1, 1, 1];
$classifier = new Adaline();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.2]));
$this->assertEquals(1, $classifier->predict([0.1, 0.99]));
$this->assertEquals(1, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0.1, 0.2]));
self::assertEquals(1, $classifier->predict([0.1, 0.99]));
self::assertEquals(1, $classifier->predict([1.1, 0.8]));
// By use of One-v-Rest, Adaline can perform multi-class classification
// The samples should be separable by lines perpendicular to the dimensions
@ -55,15 +55,15 @@ class AdalineTest extends TestCase
$classifier = new Adaline();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.5, 0.5]));
$this->assertEquals(1, $classifier->predict([6.0, 5.0]));
$this->assertEquals(2, $classifier->predict([3.0, 9.5]));
self::assertEquals(0, $classifier->predict([0.5, 0.5]));
self::assertEquals(1, $classifier->predict([6.0, 5.0]));
self::assertEquals(2, $classifier->predict([3.0, 9.5]));
// Extra partial training should lead to the same results.
$classifier->partialTrain([[0, 1], [1, 0]], [0, 0], [0, 1, 2]);
$this->assertEquals(0, $classifier->predict([0.5, 0.5]));
$this->assertEquals(1, $classifier->predict([6.0, 5.0]));
$this->assertEquals(2, $classifier->predict([3.0, 9.5]));
self::assertEquals(0, $classifier->predict([0.5, 0.5]));
self::assertEquals(1, $classifier->predict([6.0, 5.0]));
self::assertEquals(2, $classifier->predict([3.0, 9.5]));
// Train should clear previous data.
$samples = [
@ -73,9 +73,9 @@ class AdalineTest extends TestCase
];
$targets = [2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1];
$classifier->train($samples, $targets);
$this->assertEquals(2, $classifier->predict([0.5, 0.5]));
$this->assertEquals(0, $classifier->predict([6.0, 5.0]));
$this->assertEquals(1, $classifier->predict([3.0, 9.5]));
self::assertEquals(2, $classifier->predict([0.5, 0.5]));
self::assertEquals(0, $classifier->predict([6.0, 5.0]));
self::assertEquals(1, $classifier->predict([3.0, 9.5]));
}
public function testSaveAndRestore(): void
@ -89,12 +89,12 @@ class AdalineTest extends TestCase
$predicted = $classifier->predict($testSamples);
$filename = 'adaline-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
}

View File

@ -23,7 +23,7 @@ class DecisionStumpTest extends TestCase
$classifier->train($samples, $targets);
}
public function testPredictSingleSample()
public function testPredictSingleSample(): void
{
// Samples should be separable with a line perpendicular
// to any dimension given in the dataset
@ -33,20 +33,20 @@ class DecisionStumpTest extends TestCase
$targets = [0, 0, 1, 1];
$classifier = new DecisionStump();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.2]));
$this->assertEquals(0, $classifier->predict([1.1, 0.2]));
$this->assertEquals(1, $classifier->predict([0.1, 0.99]));
$this->assertEquals(1, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0.1, 0.2]));
self::assertEquals(0, $classifier->predict([1.1, 0.2]));
self::assertEquals(1, $classifier->predict([0.1, 0.99]));
self::assertEquals(1, $classifier->predict([1.1, 0.8]));
// Then: vertical test
$samples = [[0, 0], [1, 0], [0, 1], [1, 1]];
$targets = [0, 1, 0, 1];
$classifier = new DecisionStump();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.2]));
$this->assertEquals(0, $classifier->predict([0.1, 1.1]));
$this->assertEquals(1, $classifier->predict([1.0, 0.99]));
$this->assertEquals(1, $classifier->predict([1.1, 0.1]));
self::assertEquals(0, $classifier->predict([0.1, 0.2]));
self::assertEquals(0, $classifier->predict([0.1, 1.1]));
self::assertEquals(1, $classifier->predict([1.0, 0.99]));
self::assertEquals(1, $classifier->predict([1.1, 0.1]));
// By use of One-v-Rest, DecisionStump can perform multi-class classification
// The samples should be separable by lines perpendicular to the dimensions
@ -59,11 +59,9 @@ class DecisionStumpTest extends TestCase
$classifier = new DecisionStump();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.5, 0.5]));
$this->assertEquals(1, $classifier->predict([6.0, 5.0]));
$this->assertEquals(2, $classifier->predict([3.5, 9.5]));
return $classifier;
self::assertEquals(0, $classifier->predict([0.5, 0.5]));
self::assertEquals(1, $classifier->predict([6.0, 5.0]));
self::assertEquals(2, $classifier->predict([3.5, 9.5]));
}
public function testSaveAndRestore(): void
@ -76,13 +74,13 @@ class DecisionStumpTest extends TestCase
$testSamples = [[0, 1], [1, 1], [0.2, 0.1]];
$predicted = $classifier->predict($testSamples);
$filename = 'dstump-test-'.random_int(100, 999).'-'.uniqid();
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filename = 'dstump-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
}

View File

@ -64,8 +64,8 @@ class LogisticRegressionTest extends TestCase
$targets = [0, 0, 0, 1, 0, 1];
$classifier = new LogisticRegression();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.1]));
$this->assertEquals(1, $classifier->predict([0.9, 0.9]));
self::assertEquals(0, $classifier->predict([0.1, 0.1]));
self::assertEquals(1, $classifier->predict([0.9, 0.9]));
}
public function testPredictSingleSampleWithBatchTraining(): void
@ -83,8 +83,8 @@ class LogisticRegressionTest extends TestCase
'L2'
);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.1]));
$this->assertEquals(1, $classifier->predict([0.9, 0.9]));
self::assertEquals(0, $classifier->predict([0.1, 0.1]));
self::assertEquals(1, $classifier->predict([0.9, 0.9]));
}
public function testPredictSingleSampleWithOnlineTraining(): void
@ -102,8 +102,8 @@ class LogisticRegressionTest extends TestCase
''
);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.1]));
$this->assertEquals(1, $classifier->predict([0.9, 0.9]));
self::assertEquals(0, $classifier->predict([0.1, 0.1]));
self::assertEquals(1, $classifier->predict([0.9, 0.9]));
}
public function testPredictSingleSampleWithSSECost(): void
@ -118,8 +118,8 @@ class LogisticRegressionTest extends TestCase
'L2'
);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.1]));
$this->assertEquals(1, $classifier->predict([0.9, 0.9]));
self::assertEquals(0, $classifier->predict([0.1, 0.1]));
self::assertEquals(1, $classifier->predict([0.9, 0.9]));
}
public function testPredictSingleSampleWithoutPenalty(): void
@ -134,8 +134,8 @@ class LogisticRegressionTest extends TestCase
''
);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.1]));
$this->assertEquals(1, $classifier->predict([0.9, 0.9]));
self::assertEquals(0, $classifier->predict([0.1, 0.1]));
self::assertEquals(1, $classifier->predict([0.9, 0.9]));
}
public function testPredictMultiClassSample(): void
@ -151,9 +151,9 @@ class LogisticRegressionTest extends TestCase
$classifier = new LogisticRegression();
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.5, 0.5]));
$this->assertEquals(1, $classifier->predict([6.0, 5.0]));
$this->assertEquals(2, $classifier->predict([3.0, 9.5]));
self::assertEquals(0, $classifier->predict([0.5, 0.5]));
self::assertEquals(1, $classifier->predict([6.0, 5.0]));
self::assertEquals(2, $classifier->predict([3.0, 9.5]));
}
public function testPredictProbabilitySingleSample(): void
@ -171,13 +171,13 @@ class LogisticRegressionTest extends TestCase
$zero = $method->invoke($predictor, [0.1, 0.1], 0);
$one = $method->invoke($predictor, [0.1, 0.1], 1);
$this->assertEquals(1, $zero + $one, '', 1e-6);
$this->assertTrue($zero > $one);
self::assertEquals(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);
$this->assertEquals(1, $zero + $one, '', 1e-6);
$this->assertTrue($zero < $one);
self::assertEquals(1, $zero + $one, '', 1e-6);
self::assertTrue($zero < $one);
}
public function testPredictProbabilityMultiClassSample(): void
@ -213,10 +213,10 @@ class LogisticRegressionTest extends TestCase
$two = $method->invoke($predictor, [3.0, 9.5], 2);
$not_two = $method->invoke($predictor, [3.0, 9.5], 'not_2');
$this->assertEquals(1, $zero + $not_zero, '', 1e-6);
$this->assertEquals(1, $one + $not_one, '', 1e-6);
$this->assertEquals(1, $two + $not_two, '', 1e-6);
$this->assertTrue($zero < $two);
$this->assertTrue($one < $two);
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::assertTrue($zero < $two);
self::assertTrue($one < $two);
}
}

View File

@ -33,9 +33,9 @@ class PerceptronTest extends TestCase
$classifier = new Perceptron(0.001, 5000);
$classifier->setEarlyStop(false);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.1, 0.2]));
$this->assertEquals(0, $classifier->predict([0, 1]));
$this->assertEquals(1, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0.1, 0.2]));
self::assertEquals(0, $classifier->predict([0, 1]));
self::assertEquals(1, $classifier->predict([1.1, 0.8]));
// OR problem
$samples = [[0.1, 0.1], [0.4, 0.], [0., 0.3], [1, 0], [0, 1], [1, 1]];
@ -43,9 +43,9 @@ class PerceptronTest extends TestCase
$classifier = new Perceptron(0.001, 5000, false);
$classifier->setEarlyStop(false);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0., 0.]));
$this->assertEquals(1, $classifier->predict([0.1, 0.99]));
$this->assertEquals(1, $classifier->predict([1.1, 0.8]));
self::assertEquals(0, $classifier->predict([0., 0.]));
self::assertEquals(1, $classifier->predict([0.1, 0.99]));
self::assertEquals(1, $classifier->predict([1.1, 0.8]));
// By use of One-v-Rest, Perceptron can perform multi-class classification
// The samples should be separable by lines perpendicular to the dimensions
@ -59,15 +59,15 @@ class PerceptronTest extends TestCase
$classifier = new Perceptron();
$classifier->setEarlyStop(false);
$classifier->train($samples, $targets);
$this->assertEquals(0, $classifier->predict([0.5, 0.5]));
$this->assertEquals(1, $classifier->predict([6.0, 5.0]));
$this->assertEquals(2, $classifier->predict([3.0, 9.5]));
self::assertEquals(0, $classifier->predict([0.5, 0.5]));
self::assertEquals(1, $classifier->predict([6.0, 5.0]));
self::assertEquals(2, $classifier->predict([3.0, 9.5]));
// Extra partial training should lead to the same results.
$classifier->partialTrain([[0, 1], [1, 0]], [0, 0], [0, 1, 2]);
$this->assertEquals(0, $classifier->predict([0.5, 0.5]));
$this->assertEquals(1, $classifier->predict([6.0, 5.0]));
$this->assertEquals(2, $classifier->predict([3.0, 9.5]));
self::assertEquals(0, $classifier->predict([0.5, 0.5]));
self::assertEquals(1, $classifier->predict([6.0, 5.0]));
self::assertEquals(2, $classifier->predict([3.0, 9.5]));
// Train should clear previous data.
$samples = [
@ -77,9 +77,9 @@ class PerceptronTest extends TestCase
];
$targets = [2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1];
$classifier->train($samples, $targets);
$this->assertEquals(2, $classifier->predict([0.5, 0.5]));
$this->assertEquals(0, $classifier->predict([6.0, 5.0]));
$this->assertEquals(1, $classifier->predict([3.0, 9.5]));
self::assertEquals(2, $classifier->predict([0.5, 0.5]));
self::assertEquals(0, $classifier->predict([6.0, 5.0]));
self::assertEquals(1, $classifier->predict([3.0, 9.5]));
}
public function testSaveAndRestore(): void
@ -93,12 +93,12 @@ class PerceptronTest extends TestCase
$predicted = $classifier->predict($testSamples);
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
}

View File

@ -21,21 +21,21 @@ class MLPClassifierTest extends TestCase
{
$mlp = new MLPClassifier(2, [2], [0, 1]);
$this->assertCount(3, $mlp->getLayers());
self::assertCount(3, $mlp->getLayers());
$layers = $mlp->getLayers();
// input layer
$this->assertCount(3, $layers[0]->getNodes());
$this->assertNotContainsOnly(Neuron::class, $layers[0]->getNodes());
self::assertCount(3, $layers[0]->getNodes());
self::assertNotContainsOnly(Neuron::class, $layers[0]->getNodes());
// hidden layer
$this->assertCount(3, $layers[1]->getNodes());
$this->assertNotContainsOnly(Neuron::class, $layers[1]->getNodes());
self::assertCount(3, $layers[1]->getNodes());
self::assertNotContainsOnly(Neuron::class, $layers[1]->getNodes());
// output layer
$this->assertCount(2, $layers[2]->getNodes());
$this->assertContainsOnly(Neuron::class, $layers[2]->getNodes());
self::assertCount(2, $layers[2]->getNodes());
self::assertContainsOnly(Neuron::class, $layers[2]->getNodes());
}
public function testSynapsesGeneration(): void
@ -46,11 +46,11 @@ class MLPClassifierTest extends TestCase
foreach ($layers[1]->getNodes() as $node) {
if ($node instanceof Neuron) {
$synapses = $node->getSynapses();
$this->assertCount(3, $synapses);
self::assertCount(3, $synapses);
$synapsesNodes = $this->getSynapsesNodes($synapses);
foreach ($layers[0]->getNodes() as $prevNode) {
$this->assertContains($prevNode, $synapsesNodes);
self::assertContains($prevNode, $synapsesNodes);
}
}
}
@ -65,10 +65,10 @@ class MLPClassifierTest extends TestCase
['a', 'b', 'a', 'b']
);
$this->assertEquals('a', $network->predict([1, 0]));
$this->assertEquals('b', $network->predict([0, 1]));
$this->assertEquals('a', $network->predict([1, 1]));
$this->assertEquals('b', $network->predict([0, 0]));
self::assertEquals('a', $network->predict([1, 0]));
self::assertEquals('b', $network->predict([0, 1]));
self::assertEquals('a', $network->predict([1, 1]));
self::assertEquals('b', $network->predict([0, 0]));
}
public function testBackpropagationTrainingReset(): void
@ -80,16 +80,16 @@ class MLPClassifierTest extends TestCase
['a', 'b']
);
$this->assertEquals('a', $network->predict([1, 0]));
$this->assertEquals('b', $network->predict([0, 1]));
self::assertEquals('a', $network->predict([1, 0]));
self::assertEquals('b', $network->predict([0, 1]));
$network->train(
[[1, 0], [0, 1]],
['b', 'a']
);
$this->assertEquals('b', $network->predict([1, 0]));
$this->assertEquals('a', $network->predict([0, 1]));
self::assertEquals('b', $network->predict([1, 0]));
self::assertEquals('a', $network->predict([0, 1]));
}
public function testBackpropagationPartialTraining(): void
@ -101,18 +101,18 @@ class MLPClassifierTest extends TestCase
['a', 'b']
);
$this->assertEquals('a', $network->predict([1, 0]));
$this->assertEquals('b', $network->predict([0, 1]));
self::assertEquals('a', $network->predict([1, 0]));
self::assertEquals('b', $network->predict([0, 1]));
$network->partialTrain(
[[1, 1], [0, 0]],
['a', 'b']
);
$this->assertEquals('a', $network->predict([1, 0]));
$this->assertEquals('b', $network->predict([0, 1]));
$this->assertEquals('a', $network->predict([1, 1]));
$this->assertEquals('b', $network->predict([0, 0]));
self::assertEquals('a', $network->predict([1, 0]));
self::assertEquals('b', $network->predict([0, 1]));
self::assertEquals('a', $network->predict([1, 1]));
self::assertEquals('b', $network->predict([0, 0]));
}
public function testBackpropagationLearningMultilayer(): void
@ -124,10 +124,10 @@ class MLPClassifierTest extends TestCase
['a', 'b', 'a', 'c']
);
$this->assertEquals('a', $network->predict([1, 0, 0, 0, 0]));
$this->assertEquals('b', $network->predict([0, 1, 1, 0, 0]));
$this->assertEquals('a', $network->predict([1, 1, 1, 1, 1]));
$this->assertEquals('c', $network->predict([0, 0, 0, 0, 0]));
self::assertEquals('a', $network->predict([1, 0, 0, 0, 0]));
self::assertEquals('b', $network->predict([0, 1, 1, 0, 0]));
self::assertEquals('a', $network->predict([1, 1, 1, 1, 1]));
self::assertEquals('c', $network->predict([0, 0, 0, 0, 0]));
}
public function testBackpropagationLearningMulticlass(): void
@ -139,11 +139,11 @@ class MLPClassifierTest extends TestCase
['a', 'b', 'a', 'a', 4]
);
$this->assertEquals('a', $network->predict([1, 0, 0, 0, 0]));
$this->assertEquals('b', $network->predict([0, 1, 0, 0, 0]));
$this->assertEquals('a', $network->predict([0, 0, 1, 1, 0]));
$this->assertEquals('a', $network->predict([1, 1, 1, 1, 1]));
$this->assertEquals(4, $network->predict([0, 0, 0, 0, 0]));
self::assertEquals('a', $network->predict([1, 0, 0, 0, 0]));
self::assertEquals('b', $network->predict([0, 1, 0, 0, 0]));
self::assertEquals('a', $network->predict([0, 0, 1, 1, 0]));
self::assertEquals('a', $network->predict([1, 1, 1, 1, 1]));
self::assertEquals(4, $network->predict([0, 0, 0, 0, 0]));
}
/**
@ -157,10 +157,10 @@ class MLPClassifierTest extends TestCase
['a', 'b', 'a', 'a']
);
$this->assertEquals('a', $network->predict([1, 0, 0, 0, 0]));
$this->assertEquals('b', $network->predict([0, 1, 0, 0, 0]));
$this->assertEquals('a', $network->predict([0, 0, 1, 1, 0]));
$this->assertEquals('a', $network->predict([1, 1, 1, 1, 1]));
self::assertEquals('a', $network->predict([1, 0, 0, 0, 0]));
self::assertEquals('b', $network->predict([0, 1, 0, 0, 0]));
self::assertEquals('a', $network->predict([0, 0, 1, 1, 0]));
self::assertEquals('a', $network->predict([1, 1, 1, 1, 1]));
}
public function activationFunctionsProvider(): array
@ -184,13 +184,13 @@ class MLPClassifierTest extends TestCase
$predicted = $classifier->predict($testSamples);
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
public function testSaveAndRestoreWithPartialTraining(): void
@ -201,11 +201,11 @@ class MLPClassifierTest extends TestCase
['a', 'b']
);
$this->assertEquals('a', $network->predict([1, 0]));
$this->assertEquals('b', $network->predict([0, 1]));
self::assertEquals('a', $network->predict([1, 0]));
self::assertEquals('b', $network->predict([0, 1]));
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($network, $filepath);
@ -216,10 +216,10 @@ class MLPClassifierTest extends TestCase
['a', 'b']
);
$this->assertEquals('a', $restoredNetwork->predict([1, 0]));
$this->assertEquals('b', $restoredNetwork->predict([0, 1]));
$this->assertEquals('a', $restoredNetwork->predict([1, 1]));
$this->assertEquals('b', $restoredNetwork->predict([0, 0]));
self::assertEquals('a', $restoredNetwork->predict([1, 0]));
self::assertEquals('b', $restoredNetwork->predict([0, 1]));
self::assertEquals('a', $restoredNetwork->predict([1, 1]));
self::assertEquals('b', $restoredNetwork->predict([0, 0]));
}
public function testThrowExceptionOnInvalidLayersNumber(): void
@ -249,7 +249,7 @@ class MLPClassifierTest extends TestCase
{
$output = (new MLPClassifier(2, [2, 2], ['T', 'F']))->getOutput();
$this->assertEquals(['T', 'F'], array_keys($output));
self::assertEquals(['T', 'F'], array_keys($output));
}
private function getSynapsesNodes(array $synapses): array

View File

@ -18,9 +18,9 @@ class NaiveBayesTest extends TestCase
$classifier = new NaiveBayes();
$classifier->train($samples, $labels);
$this->assertEquals('a', $classifier->predict([3, 1, 1]));
$this->assertEquals('b', $classifier->predict([1, 4, 1]));
$this->assertEquals('c', $classifier->predict([1, 1, 6]));
self::assertEquals('a', $classifier->predict([3, 1, 1]));
self::assertEquals('b', $classifier->predict([1, 4, 1]));
self::assertEquals('c', $classifier->predict([1, 1, 6]));
}
public function testPredictArrayOfSamples(): void
@ -35,7 +35,7 @@ class NaiveBayesTest extends TestCase
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$this->assertEquals($testLabels, $predicted);
self::assertEquals($testLabels, $predicted);
// Feed an extra set of training data.
$samples = [[1, 1, 6]];
@ -44,7 +44,7 @@ class NaiveBayesTest extends TestCase
$testSamples = [[1, 1, 6], [5, 1, 1]];
$testLabels = ['d', 'a'];
$this->assertEquals($testLabels, $classifier->predict($testSamples));
self::assertEquals($testLabels, $classifier->predict($testSamples));
}
public function testSaveAndRestore(): void
@ -59,13 +59,13 @@ class NaiveBayesTest extends TestCase
$predicted = $classifier->predict($testSamples);
$filename = 'naive-bayes-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
public function testPredictSimpleNumericLabels(): void
@ -76,9 +76,9 @@ class NaiveBayesTest extends TestCase
$classifier = new NaiveBayes();
$classifier->train($samples, $labels);
$this->assertEquals('1996', $classifier->predict([3, 1, 1]));
$this->assertEquals('1997', $classifier->predict([1, 4, 1]));
$this->assertEquals('1998', $classifier->predict([1, 1, 6]));
self::assertEquals('1996', $classifier->predict([3, 1, 1]));
self::assertEquals('1997', $classifier->predict([1, 4, 1]));
self::assertEquals('1998', $classifier->predict([1, 1, 6]));
}
public function testPredictArrayOfSamplesNumericalLabels(): void
@ -93,7 +93,7 @@ class NaiveBayesTest extends TestCase
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$this->assertEquals($testLabels, $predicted);
self::assertEquals($testLabels, $predicted);
// Feed an extra set of training data.
$samples = [[1, 1, 6]];
@ -102,7 +102,7 @@ class NaiveBayesTest extends TestCase
$testSamples = [[1, 1, 6], [5, 1, 1]];
$testLabels = ['1999', '1996'];
$this->assertEquals($testLabels, $classifier->predict($testSamples));
self::assertEquals($testLabels, $classifier->predict($testSamples));
}
public function testSaveAndRestoreNumericLabels(): void
@ -117,12 +117,12 @@ class NaiveBayesTest extends TestCase
$predicted = $classifier->predict($testSamples);
$filename = 'naive-bayes-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$filepath = (string) tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
}
}

View File

@ -19,15 +19,15 @@ class SVCTest extends TestCase
$classifier = new SVC(Kernel::LINEAR, $cost = 1000);
$classifier->train($samples, $labels);
$this->assertEquals('b', $classifier->predict([3, 2]));
$this->assertEquals('b', $classifier->predict([5, 1]));
$this->assertEquals('b', $classifier->predict([4, 3]));
$this->assertEquals('b', $classifier->predict([4, -5]));
self::assertEquals('b', $classifier->predict([3, 2]));
self::assertEquals('b', $classifier->predict([5, 1]));
self::assertEquals('b', $classifier->predict([4, 3]));
self::assertEquals('b', $classifier->predict([4, -5]));
$this->assertEquals('a', $classifier->predict([2, 3]));
$this->assertEquals('a', $classifier->predict([1, 2]));
$this->assertEquals('a', $classifier->predict([1, 5]));
$this->assertEquals('a', $classifier->predict([3, 10]));
self::assertEquals('a', $classifier->predict([2, 3]));
self::assertEquals('a', $classifier->predict([1, 2]));
self::assertEquals('a', $classifier->predict([1, 5]));
self::assertEquals('a', $classifier->predict([3, 10]));
}
public function testPredictArrayOfSamplesWithLinearKernel(): void
@ -42,7 +42,7 @@ class SVCTest extends TestCase
$classifier->train($trainSamples, $trainLabels);
$predictions = $classifier->predict($testSamples);
$this->assertEquals($testLabels, $predictions);
self::assertEquals($testLabels, $predictions);
}
public function testSaveAndRestore(): void
@ -57,14 +57,14 @@ class SVCTest extends TestCase
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$filepath = tempnam(sys_get_temp_dir(), uniqid('svc-test', true));
$filepath = (string) tempnam(sys_get_temp_dir(), uniqid('svc-test', true));
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
$restoredClassifier = $modelManager->restoreFromFile($filepath);
$this->assertEquals($classifier, $restoredClassifier);
$this->assertEquals($predicted, $restoredClassifier->predict($testSamples));
$this->assertEquals($predicted, $testLabels);
self::assertEquals($classifier, $restoredClassifier);
self::assertEquals($predicted, $restoredClassifier->predict($testSamples));
self::assertEquals($predicted, $testLabels);
}
public function testWithNonDotDecimalLocale(): void
@ -81,8 +81,8 @@ class SVCTest extends TestCase
$classifier = new SVC(Kernel::LINEAR, $cost = 1000);
$classifier->train($trainSamples, $trainLabels);
$this->assertEquals($classifier->predict($testSamples), $testLabels);
self::assertEquals($classifier->predict($testSamples), $testLabels);
setlocale(LC_NUMERIC, $currentLocale);
setlocale(LC_NUMERIC, (string) $currentLocale);
}
}

View File

@ -19,7 +19,7 @@ class DBSCANTest extends TestCase
$dbscan = new DBSCAN($epsilon = 2, $minSamples = 3);
$this->assertEquals($clustered, $dbscan->cluster($samples));
self::assertEquals($clustered, $dbscan->cluster($samples));
$samples = [[1, 1], [6, 6], [1, -1], [5, 6], [-1, -1], [7, 8], [-1, 1], [7, 7]];
$clustered = [
@ -29,7 +29,7 @@ class DBSCANTest extends TestCase
$dbscan = new DBSCAN($epsilon = 3, $minSamples = 4);
$this->assertEquals($clustered, $dbscan->cluster($samples));
self::assertEquals($clustered, $dbscan->cluster($samples));
}
public function testDBSCANSamplesClusteringAssociative(): void
@ -57,7 +57,7 @@ class DBSCANTest extends TestCase
$dbscan = new DBSCAN($epsilon = 3, $minSamples = 2);
$this->assertEquals($clustered, $dbscan->cluster($samples));
self::assertEquals($clustered, $dbscan->cluster($samples));
}
public function testClusterEpsilonSmall(): void
@ -68,7 +68,7 @@ class DBSCANTest extends TestCase
$dbscan = new DBSCAN($epsilon = 0.5, $minSamples = 2);
$this->assertEquals($clustered, $dbscan->cluster($samples));
self::assertEquals($clustered, $dbscan->cluster($samples));
}
public function testClusterEpsilonBoundary(): void
@ -79,7 +79,7 @@ class DBSCANTest extends TestCase
$dbscan = new DBSCAN($epsilon = 1.0, $minSamples = 2);
$this->assertEquals($clustered, $dbscan->cluster($samples));
self::assertEquals($clustered, $dbscan->cluster($samples));
}
public function testClusterEpsilonLarge(): void
@ -91,6 +91,6 @@ class DBSCANTest extends TestCase
$dbscan = new DBSCAN($epsilon = 1.5, $minSamples = 2);
$this->assertEquals($clustered, $dbscan->cluster($samples));
self::assertEquals($clustered, $dbscan->cluster($samples));
}
}

View File

@ -10,40 +10,40 @@ use PHPUnit\Framework\TestCase;
class FuzzyCMeansTest extends TestCase
{
public function testFCMSamplesClustering()
public function testFCMSamplesClustering(): void
{
$samples = [[1, 1], [8, 7], [1, 2], [7, 8], [2, 1], [8, 9]];
$fcm = new FuzzyCMeans(2);
$clusters = $fcm->cluster($samples);
$this->assertCount(2, $clusters);
self::assertCount(2, $clusters);
foreach ($samples as $index => $sample) {
if (in_array($sample, $clusters[0], true) || in_array($sample, $clusters[1], true)) {
unset($samples[$index]);
}
}
$this->assertCount(0, $samples);
return $fcm;
self::assertCount(0, $samples);
}
public function testMembershipMatrix(): void
{
$fcm = $this->testFCMSamplesClustering();
$fcm = new FuzzyCMeans(2);
$fcm->cluster([[1, 1], [8, 7], [1, 2], [7, 8], [2, 1], [8, 9]]);
$clusterCount = 2;
$sampleCount = 6;
$matrix = $fcm->getMembershipMatrix();
$this->assertCount($clusterCount, $matrix);
self::assertCount($clusterCount, $matrix);
foreach ($matrix as $row) {
$this->assertCount($sampleCount, $row);
self::assertCount($sampleCount, $row);
}
// Transpose of the matrix
array_unshift($matrix, null);
$matrix = call_user_func_array('array_map', $matrix);
$matrix = array_map(...$matrix);
// All column totals should be equal to 1 (100% membership)
foreach ($matrix as $col) {
$this->assertEquals(1, array_sum($col));
self::assertEquals(1, array_sum($col));
}
}

View File

@ -26,7 +26,7 @@ class ClusterTest extends TestCase
$cluster = new Cluster(new Space(2), [1, 2]);
$cluster->attach(new Point([1, 1]));
$this->assertSame([
self::assertSame([
'centroid' => [1, 2],
'points' => [
[1, 1],
@ -42,8 +42,8 @@ class ClusterTest extends TestCase
$detachedPoint = $cluster->detach($point);
$this->assertSame($detachedPoint, $point);
$this->assertNotContains($point, $cluster->getPoints());
$this->assertCount(1, $cluster);
self::assertSame($detachedPoint, $point);
self::assertNotContains($point, $cluster->getPoints());
self::assertCount(1, $cluster);
}
}

View File

@ -17,7 +17,7 @@ class KMeansTest extends TestCase
$kmeans = new KMeans(2);
$clusters = $kmeans->cluster($samples);
$this->assertCount(2, $clusters);
self::assertCount(2, $clusters);
foreach ($samples as $index => $sample) {
if (in_array($sample, $clusters[0], true) || in_array($sample, $clusters[1], true)) {
@ -25,7 +25,7 @@ class KMeansTest extends TestCase
}
}
$this->assertCount(0, $samples);
self::assertCount(0, $samples);
}
public function testKMeansSamplesLabeledClustering(): void
@ -42,16 +42,16 @@ class KMeansTest extends TestCase
$kmeans = new KMeans(2);
$clusters = $kmeans->cluster($samples);
$this->assertCount(2, $clusters);
self::assertCount(2, $clusters);
foreach ($samples as $index => $sample) {
if (in_array($sample, $clusters[0], true) || in_array($sample, $clusters[1], true)) {
$this->assertArrayHasKey($index, $clusters[0] + $clusters[1]);
self::assertArrayHasKey($index, $clusters[0] + $clusters[1]);
unset($samples[$index]);
}
}
$this->assertCount(0, $samples);
self::assertCount(0, $samples);
}
public function testKMeansInitializationMethods(): void
@ -71,11 +71,11 @@ class KMeansTest extends TestCase
$kmeans = new KMeans(4, KMeans::INIT_KMEANS_PLUS_PLUS);
$clusters = $kmeans->cluster($samples);
$this->assertCount(4, $clusters);
self::assertCount(4, $clusters);
$kmeans = new KMeans(4, KMeans::INIT_RANDOM);
$clusters = $kmeans->cluster($samples);
$this->assertCount(4, $clusters);
self::assertCount(4, $clusters);
}
public function testThrowExceptionOnInvalidClusterNumber(): void

View File

@ -32,13 +32,13 @@ class RandomSplitTest extends TestCase
$randomSplit = new RandomSplit($dataset, 0.5);
$this->assertCount(2, $randomSplit->getTestSamples());
$this->assertCount(2, $randomSplit->getTrainSamples());
self::assertCount(2, $randomSplit->getTestSamples());
self::assertCount(2, $randomSplit->getTrainSamples());
$randomSplit2 = new RandomSplit($dataset, 0.25);
$this->assertCount(1, $randomSplit2->getTestSamples());
$this->assertCount(3, $randomSplit2->getTrainSamples());
self::assertCount(1, $randomSplit2->getTestSamples());
self::assertCount(3, $randomSplit2->getTrainSamples());
}
public function testDatasetRandomSplitWithSameSeed(): void
@ -53,10 +53,10 @@ class RandomSplitTest extends TestCase
$randomSplit1 = new RandomSplit($dataset, 0.5, $seed);
$randomSplit2 = new RandomSplit($dataset, 0.5, $seed);
$this->assertEquals($randomSplit1->getTestLabels(), $randomSplit2->getTestLabels());
$this->assertEquals($randomSplit1->getTestSamples(), $randomSplit2->getTestSamples());
$this->assertEquals($randomSplit1->getTrainLabels(), $randomSplit2->getTrainLabels());
$this->assertEquals($randomSplit1->getTrainSamples(), $randomSplit2->getTrainSamples());
self::assertEquals($randomSplit1->getTestLabels(), $randomSplit2->getTestLabels());
self::assertEquals($randomSplit1->getTestSamples(), $randomSplit2->getTestSamples());
self::assertEquals($randomSplit1->getTrainLabels(), $randomSplit2->getTrainLabels());
self::assertEquals($randomSplit1->getTrainSamples(), $randomSplit2->getTrainSamples());
}
public function testDatasetRandomSplitWithDifferentSeed(): void
@ -69,10 +69,10 @@ class RandomSplitTest extends TestCase
$randomSplit1 = new RandomSplit($dataset, 0.5, 4321);
$randomSplit2 = new RandomSplit($dataset, 0.5, 1234);
$this->assertNotEquals($randomSplit1->getTestLabels(), $randomSplit2->getTestLabels());
$this->assertNotEquals($randomSplit1->getTestSamples(), $randomSplit2->getTestSamples());
$this->assertNotEquals($randomSplit1->getTrainLabels(), $randomSplit2->getTrainLabels());
$this->assertNotEquals($randomSplit1->getTrainSamples(), $randomSplit2->getTrainSamples());
self::assertNotEquals($randomSplit1->getTestLabels(), $randomSplit2->getTestLabels());
self::assertNotEquals($randomSplit1->getTestSamples(), $randomSplit2->getTestSamples());
self::assertNotEquals($randomSplit1->getTrainLabels(), $randomSplit2->getTrainLabels());
self::assertNotEquals($randomSplit1->getTrainSamples(), $randomSplit2->getTrainSamples());
}
public function testRandomSplitCorrectSampleAndLabelPosition(): void
@ -84,9 +84,9 @@ class RandomSplitTest extends TestCase
$randomSplit = new RandomSplit($dataset, 0.5);
$this->assertEquals($randomSplit->getTestSamples()[0][0], $randomSplit->getTestLabels()[0]);
$this->assertEquals($randomSplit->getTestSamples()[1][0], $randomSplit->getTestLabels()[1]);
$this->assertEquals($randomSplit->getTrainSamples()[0][0], $randomSplit->getTrainLabels()[0]);
$this->assertEquals($randomSplit->getTrainSamples()[1][0], $randomSplit->getTrainLabels()[1]);
self::assertEquals($randomSplit->getTestSamples()[0][0], $randomSplit->getTestLabels()[0]);
self::assertEquals($randomSplit->getTestSamples()[1][0], $randomSplit->getTestLabels()[1]);
self::assertEquals($randomSplit->getTrainSamples()[0][0], $randomSplit->getTrainLabels()[0]);
self::assertEquals($randomSplit->getTrainSamples()[1][0], $randomSplit->getTrainLabels()[1]);
}
}

View File

@ -19,13 +19,13 @@ class StratifiedRandomSplitTest extends TestCase
$split = new StratifiedRandomSplit($dataset, 0.5);
$this->assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 'a'));
$this->assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 'b'));
self::assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 'a'));
self::assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 'b'));
$split = new StratifiedRandomSplit($dataset, 0.25);
$this->assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 'a'));
$this->assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 'b'));
self::assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 'a'));
self::assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 'b'));
}
public function testDatasetStratifiedRandomSplitWithEvenDistributionAndNumericTargets(): void
@ -37,16 +37,19 @@ class StratifiedRandomSplitTest extends TestCase
$split = new StratifiedRandomSplit($dataset, 0.5);
$this->assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 1));
$this->assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 2));
self::assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 1));
self::assertEquals(2, $this->countSamplesByTarget($split->getTestLabels(), 2));
$split = new StratifiedRandomSplit($dataset, 0.25);
$this->assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 1));
$this->assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 2));
self::assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 1));
self::assertEquals(1, $this->countSamplesByTarget($split->getTestLabels(), 2));
}
private function countSamplesByTarget($splitTargets, $countTarget): int
/**
* @param string|int $countTarget
*/
private function countSamplesByTarget(array $splitTargets, $countTarget): int
{
$count = 0;
foreach ($splitTargets as $target) {

View File

@ -23,8 +23,8 @@ class ArrayDatasetTest extends TestCase
$labels = ['a', 'a', 'b', 'b']
);
$this->assertEquals($samples, $dataset->getSamples());
$this->assertEquals($labels, $dataset->getTargets());
self::assertEquals($samples, $dataset->getSamples());
self::assertEquals($labels, $dataset->getTargets());
}
public function testRemoveColumns(): void
@ -35,6 +35,6 @@ class ArrayDatasetTest extends TestCase
);
$dataset->removeColumns([0, 2]);
$this->assertEquals([[2, 4], [3, 5], [4, 6], [5, 7]], $dataset->getSamples());
self::assertEquals([[2, 4], [3, 5], [4, 6], [5, 7]], $dataset->getSamples());
}
}

View File

@ -22,8 +22,8 @@ class CsvDatasetTest extends TestCase
$dataset = new CsvDataset($filePath, 2, true);
$this->assertCount(10, $dataset->getSamples());
$this->assertCount(10, $dataset->getTargets());
self::assertCount(10, $dataset->getSamples());
self::assertCount(10, $dataset->getTargets());
}
public function testSampleCsvDatasetWithoutHeaderRow(): void
@ -32,8 +32,8 @@ class CsvDatasetTest extends TestCase
$dataset = new CsvDataset($filePath, 2, false);
$this->assertCount(11, $dataset->getSamples());
$this->assertCount(11, $dataset->getTargets());
self::assertCount(11, $dataset->getSamples());
self::assertCount(11, $dataset->getTargets());
}
public function testLongCsvDataset(): void
@ -42,7 +42,7 @@ class CsvDatasetTest extends TestCase
$dataset = new CsvDataset($filePath, 1000, false);
$this->assertCount(1000, $dataset->getSamples()[0]);
$this->assertEquals('label', $dataset->getTargets()[0]);
self::assertCount(1000, $dataset->getSamples()[0]);
self::assertEquals('label', $dataset->getTargets()[0]);
}
}

View File

@ -14,10 +14,10 @@ class GlassDatasetTest extends TestCase
$glass = new GlassDataset();
// whole dataset
$this->assertCount(214, $glass->getSamples());
$this->assertCount(214, $glass->getTargets());
self::assertCount(214, $glass->getSamples());
self::assertCount(214, $glass->getTargets());
// one sample features count
$this->assertCount(9, $glass->getSamples()[0]);
self::assertCount(9, $glass->getSamples()[0]);
}
}

View File

@ -14,10 +14,10 @@ class IrisDatasetTest extends TestCase
$iris = new IrisDataset();
// whole dataset
$this->assertCount(150, $iris->getSamples());
$this->assertCount(150, $iris->getTargets());
self::assertCount(150, $iris->getSamples());
self::assertCount(150, $iris->getTargets());
// one sample features count
$this->assertCount(4, $iris->getSamples()[0]);
self::assertCount(4, $iris->getSamples()[0]);
}
}

View File

@ -14,10 +14,10 @@ class WineDatasetTest extends TestCase
$wine = new WineDataset();
// whole dataset
$this->assertCount(178, $wine->getSamples());
$this->assertCount(178, $wine->getTargets());
self::assertCount(178, $wine->getSamples());
self::assertCount(178, $wine->getTargets());
// one sample features count
$this->assertCount(13, $wine->getSamples()[0]);
self::assertCount(13, $wine->getSamples()[0]);
}
}

View File

@ -22,22 +22,22 @@ class FilesDatasetTest extends TestCase
$dataset = new FilesDataset($rootPath);
$this->assertCount(50, $dataset->getSamples());
$this->assertCount(50, $dataset->getTargets());
self::assertCount(50, $dataset->getSamples());
self::assertCount(50, $dataset->getTargets());
$targets = ['business', 'entertainment', 'politics', 'sport', 'tech'];
$this->assertEquals($targets, array_values(array_unique($dataset->getTargets())));
self::assertEquals($targets, array_values(array_unique($dataset->getTargets())));
$firstSample = file_get_contents($rootPath.'/business/001.txt');
$this->assertEquals($firstSample, $dataset->getSamples()[0][0]);
self::assertEquals($firstSample, $dataset->getSamples()[0][0]);
$firstTarget = 'business';
$this->assertEquals($firstTarget, $dataset->getTargets()[0]);
self::assertEquals($firstTarget, $dataset->getTargets()[0]);
$lastSample = file_get_contents($rootPath.'/tech/010.txt');
$this->assertEquals($lastSample, $dataset->getSamples()[49][0]);
self::assertEquals($lastSample, $dataset->getSamples()[49][0]);
$lastTarget = 'tech';
$this->assertEquals($lastTarget, $dataset->getTargets()[49]);
self::assertEquals($lastTarget, $dataset->getTargets()[49]);
}
}

View File

@ -21,8 +21,8 @@ class SvmDatasetTest extends TestCase
$expectedTargets = [
];
$this->assertEquals($expectedSamples, $dataset->getSamples());
$this->assertEquals($expectedTargets, $dataset->getTargets());
self::assertEquals($expectedSamples, $dataset->getSamples());
self::assertEquals($expectedTargets, $dataset->getTargets());
}
public function testSvmDataset1x1(): void
@ -37,8 +37,8 @@ class SvmDatasetTest extends TestCase
0,
];
$this->assertEquals($expectedSamples, $dataset->getSamples());
$this->assertEquals($expectedTargets, $dataset->getTargets());
self::assertEquals($expectedSamples, $dataset->getSamples());
self::assertEquals($expectedTargets, $dataset->getTargets());
}
public function testSvmDataset3x1(): void
@ -57,8 +57,8 @@ class SvmDatasetTest extends TestCase
1,
];
$this->assertEquals($expectedSamples, $dataset->getSamples());
$this->assertEquals($expectedTargets, $dataset->getTargets());
self::assertEquals($expectedSamples, $dataset->getSamples());
self::assertEquals($expectedTargets, $dataset->getTargets());
}
public function testSvmDataset3x4(): void
@ -77,8 +77,8 @@ class SvmDatasetTest extends TestCase
0,
];
$this->assertEquals($expectedSamples, $dataset->getSamples());
$this->assertEquals($expectedTargets, $dataset->getTargets());
self::assertEquals($expectedSamples, $dataset->getSamples());
self::assertEquals($expectedTargets, $dataset->getTargets());
}
public function testSvmDatasetSparse(): void
@ -95,8 +95,8 @@ class SvmDatasetTest extends TestCase
1,
];
$this->assertEquals($expectedSamples, $dataset->getSamples());
$this->assertEquals($expectedTargets, $dataset->getTargets());
self::assertEquals($expectedSamples, $dataset->getSamples());
self::assertEquals($expectedTargets, $dataset->getTargets());
}
public function testSvmDatasetComments(): void
@ -113,8 +113,8 @@ class SvmDatasetTest extends TestCase
1,
];
$this->assertEquals($expectedSamples, $dataset->getSamples());
$this->assertEquals($expectedTargets, $dataset->getTargets());
self::assertEquals($expectedSamples, $dataset->getSamples());
self::assertEquals($expectedTargets, $dataset->getTargets());
}
public function testSvmDatasetTabs(): void
@ -129,8 +129,8 @@ class SvmDatasetTest extends TestCase
1,
];
$this->assertEquals($expectedSamples, $dataset->getSamples());
$this->assertEquals($expectedTargets, $dataset->getTargets());
self::assertEquals($expectedSamples, $dataset->getSamples());
self::assertEquals($expectedTargets, $dataset->getTargets());
}
public function testSvmDatasetMissingFile(): void

View File

@ -40,7 +40,7 @@ class KernelPCATest extends TestCase
// during the calculation of eigenValues, we have to compare
// absolute value of the values
array_map(function ($val1, $val2) use ($epsilon): void {
$this->assertEquals(abs($val1), abs($val2), '', $epsilon);
self::assertEquals(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);
$this->assertEquals(abs($newTransformed[0]), abs($newTransformed2[0]), '', $epsilon);
self::assertEquals(abs($newTransformed[0]), abs($newTransformed2[0]), '', $epsilon);
}
public function testKernelPCAThrowWhenKernelInvalid(): void

View File

@ -51,7 +51,7 @@ class LDATest extends TestCase
// absolute value of the values
$row1 = array_map('abs', $row1);
$row2 = array_map('abs', $row2);
$this->assertEquals($row1, $row2, '', $epsilon);
self::assertEquals($row1, $row2, '', $epsilon);
};
array_map($check, $control, $transformed2);

View File

@ -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 {
$this->assertEquals(abs($val1), abs($val2), '', $epsilon);
self::assertEquals(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 {
$this->assertEquals(abs($val1), abs($val2), '', $epsilon);
self::assertEquals(abs($val1), abs($val2), '', $epsilon);
}, $newRow, $newRow2);
}
}

View File

@ -14,13 +14,13 @@ class StopWordsTest extends TestCase
{
$stopWords = new StopWords(['lorem', 'ipsum', 'dolor']);
$this->assertTrue($stopWords->isStopWord('lorem'));
$this->assertTrue($stopWords->isStopWord('ipsum'));
$this->assertTrue($stopWords->isStopWord('dolor'));
self::assertTrue($stopWords->isStopWord('lorem'));
self::assertTrue($stopWords->isStopWord('ipsum'));
self::assertTrue($stopWords->isStopWord('dolor'));
$this->assertFalse($stopWords->isStopWord('consectetur'));
$this->assertFalse($stopWords->isStopWord('adipiscing'));
$this->assertFalse($stopWords->isStopWord('amet'));
self::assertFalse($stopWords->isStopWord('consectetur'));
self::assertFalse($stopWords->isStopWord('adipiscing'));
self::assertFalse($stopWords->isStopWord('amet'));
}
public function testThrowExceptionOnInvalidLanguage(): void
@ -33,23 +33,23 @@ class StopWordsTest extends TestCase
{
$stopWords = StopWords::factory('English');
$this->assertTrue($stopWords->isStopWord('again'));
$this->assertFalse($stopWords->isStopWord('strategy'));
self::assertTrue($stopWords->isStopWord('again'));
self::assertFalse($stopWords->isStopWord('strategy'));
}
public function testPolishStopWords(): void
{
$stopWords = StopWords::factory('Polish');
$this->assertTrue($stopWords->isStopWord('wam'));
$this->assertFalse($stopWords->isStopWord('transhumanizm'));
self::assertTrue($stopWords->isStopWord('wam'));
self::assertFalse($stopWords->isStopWord('transhumanizm'));
}
public function testFrenchStopWords(): void
{
$stopWords = StopWords::factory('French');
$this->assertTrue($stopWords->isStopWord('alors'));
$this->assertFalse($stopWords->isStopWord('carte'));
self::assertTrue($stopWords->isStopWord('alors'));
self::assertFalse($stopWords->isStopWord('carte'));
}
}

View File

@ -54,6 +54,6 @@ class TfIdfTransformerTest extends TestCase
$transformer = new TfIdfTransformer($samples);
$transformer->transform($samples);
$this->assertEquals($tfIdfSamples, $samples, '', 0.001);
self::assertEquals($tfIdfSamples, $samples, '', 0.001);
}
}

View File

@ -74,10 +74,10 @@ class TokenCountVectorizerTest extends TestCase
$vectorizer = new TokenCountVectorizer(new WhitespaceTokenizer());
$vectorizer->fit($samples);
$this->assertSame($vocabulary, $vectorizer->getVocabulary());
self::assertSame($vocabulary, $vectorizer->getVocabulary());
$vectorizer->transform($samples);
$this->assertSame($tokensCounts, $samples);
self::assertSame($tokensCounts, $samples);
}
public function testTransformationWithMinimumDocumentTokenCountFrequency(): void
@ -132,10 +132,10 @@ class TokenCountVectorizerTest extends TestCase
$vectorizer = new TokenCountVectorizer(new WhitespaceTokenizer(), null, 0.5);
$vectorizer->fit($samples);
$this->assertSame($vocabulary, $vectorizer->getVocabulary());
self::assertSame($vocabulary, $vectorizer->getVocabulary());
$vectorizer->transform($samples);
$this->assertSame($tokensCounts, $samples);
self::assertSame($tokensCounts, $samples);
// word at least once in all samples
$samples = [
@ -184,7 +184,7 @@ class TokenCountVectorizerTest extends TestCase
$vectorizer->fit($samples);
$vectorizer->transform($samples);
$this->assertSame($tokensCounts, $samples);
self::assertSame($tokensCounts, $samples);
}
public function testTransformationWithStopWords(): void
@ -246,9 +246,9 @@ class TokenCountVectorizerTest extends TestCase
$vectorizer = new TokenCountVectorizer(new WhitespaceTokenizer(), $stopWords);
$vectorizer->fit($samples);
$this->assertSame($vocabulary, $vectorizer->getVocabulary());
self::assertSame($vocabulary, $vectorizer->getVocabulary());
$vectorizer->transform($samples);
$this->assertSame($tokensCounts, $samples);
self::assertSame($tokensCounts, $samples);
}
}

View File

@ -33,7 +33,7 @@ class ConjugateGradientTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
$this->assertEquals([-1, 2], $theta, '', 0.1);
self::assertEquals([-1, 2], $theta, '', 0.1);
}
public function testRunOptimizationWithCustomInitialTheta(): void
@ -61,7 +61,7 @@ class ConjugateGradientTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
$this->assertEquals([-1.087708, 2.212034], $theta, '', 0.000001);
self::assertEquals([-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);
$this->assertEquals([-1, 2, -3], $theta, '', 0.1);
self::assertEquals([-1, 2, -3], $theta, '', 0.1);
}
public function testThrowExceptionOnInvalidTheta(): void

View File

@ -32,7 +32,7 @@ class GDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
$this->assertEquals([-1, 2], $theta, '', 0.1);
self::assertEquals([-1, 2], $theta, '', 0.1);
}
public function testRunOptimization2Dim(): void
@ -60,6 +60,6 @@ class GDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
$this->assertEquals([-1, 2, -3], $theta, '', 0.1);
self::assertEquals([-1, 2, -3], $theta, '', 0.1);
}
}

View File

@ -26,9 +26,9 @@ class OptimizerTest extends TestCase
$optimizer = $this->getMockForAbstractClass(Optimizer::class, [2]);
$object = $optimizer->setTheta([0.3, 1]);
$theta = $this->getObjectAttribute($optimizer, 'theta');
$theta = self::getObjectAttribute($optimizer, 'theta');
$this->assertSame($object, $optimizer);
$this->assertSame([0.3, 1], $theta);
self::assertSame($object, $optimizer);
self::assertSame([0.3, 1], $theta);
}
}

View File

@ -32,7 +32,7 @@ class StochasticGDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
$this->assertEquals([-1, 2], $theta, '', 0.1);
self::assertEquals([-1, 2], $theta, '', 0.1);
}
public function testRunOptimization2Dim(): void
@ -60,6 +60,6 @@ class StochasticGDTest extends TestCase
$theta = $optimizer->runOptimization($samples, $targets, $callback);
$this->assertEquals([-1, 2, -3], $theta, '', 0.1);
self::assertEquals([-1, 2, -3], $theta, '', 0.1);
}
}

View File

@ -20,7 +20,7 @@ class ComparisonTest extends TestCase
{
$result = Comparison::compare($a, $b, $operator);
$this->assertEquals($expected, $result);
self::assertEquals($expected, $result);
}
public function testThrowExceptionWhenOperatorIsInvalid(): void

View File

@ -36,7 +36,7 @@ class ChebyshevTest extends TestCase
$expectedDistance = 2;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
public function testCalculateDistanceForTwoDimensions(): void
@ -47,7 +47,7 @@ class ChebyshevTest extends TestCase
$expectedDistance = 2;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
public function testCalculateDistanceForThreeDimensions(): void
@ -58,6 +58,6 @@ class ChebyshevTest extends TestCase
$expectedDistance = 5;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
}

View File

@ -36,7 +36,7 @@ class EuclideanTest extends TestCase
$expectedDistance = 2;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
public function testCalculateDistanceForTwoDimensions(): void
@ -47,7 +47,7 @@ class EuclideanTest extends TestCase
$expectedDistance = 2.2360679774998;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
public function testCalculateDistanceForThreeDimensions(): void
@ -58,6 +58,6 @@ class EuclideanTest extends TestCase
$expectedDistance = 6.7082039324993694;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
}

View File

@ -36,7 +36,7 @@ class ManhattanTest extends TestCase
$expectedDistance = 2;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
public function testCalculateDistanceForTwoDimensions(): void
@ -47,7 +47,7 @@ class ManhattanTest extends TestCase
$expectedDistance = 3;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
public function testCalculateDistanceForThreeDimensions(): void
@ -58,6 +58,6 @@ class ManhattanTest extends TestCase
$expectedDistance = 11;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
}

View File

@ -36,7 +36,7 @@ class MinkowskiTest extends TestCase
$expectedDistance = 2;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance);
self::assertEquals($expectedDistance, $actualDistance);
}
public function testCalculateDistanceForTwoDimensions(): void
@ -47,7 +47,7 @@ class MinkowskiTest extends TestCase
$expectedDistance = 2.080;
$actualDistance = $this->distanceMetric->distance($a, $b);
$this->assertEquals($expectedDistance, $actualDistance, '', $delta = 0.001);
self::assertEquals($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);
$this->assertEquals($expectedDistance, $actualDistance, '', $delta = 0.001);
self::assertEquals($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);
$this->assertEquals($expectedDistance, $actualDistance, '', $delta = 0.001);
self::assertEquals($expectedDistance, $actualDistance, '', $delta = 0.001);
}
}

View File

@ -13,14 +13,14 @@ class RBFTest extends TestCase
{
$rbf = new RBF($gamma = 0.001);
$this->assertEquals(1, $rbf->compute([1, 2], [1, 2]));
$this->assertEquals(0.97336, $rbf->compute([1, 2, 3], [4, 5, 6]), '', $delta = 0.0001);
$this->assertEquals(0.00011, $rbf->compute([4, 5], [1, 100]), '', $delta = 0.0001);
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);
$rbf = new RBF($gamma = 0.2);
$this->assertEquals(1, $rbf->compute([1, 2], [1, 2]));
$this->assertEquals(0.00451, $rbf->compute([1, 2, 3], [4, 5, 6]), '', $delta = 0.0001);
$this->assertEquals(0, $rbf->compute([4, 5], [1, 100]));
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::assertEquals(0, $rbf->compute([4, 5], [1, 100]));
}
}

View File

@ -34,8 +34,7 @@ final class LUDecompositionTest extends TestCase
$lu = new LUDecomposition(new Matrix([[1, 2], [3, 4]]));
$L = $lu->getL();
$this->assertInstanceOf(Matrix::class, $L);
$this->assertSame([[1.0, 0.0], [0.3333333333333333, 1.0]], $L->toArray());
self::assertSame([[1.0, 0.0], [0.3333333333333333, 1.0]], $L->toArray());
}
public function testUpperTriangularFactor(): void
@ -43,7 +42,6 @@ final class LUDecompositionTest extends TestCase
$lu = new LUDecomposition(new Matrix([[1, 2], [3, 4]]));
$U = $lu->getU();
$this->assertInstanceOf(Matrix::class, $U);
$this->assertSame([[3.0, 4.0], [0.0, 0.6666666666666667]], $U->toArray());
self::assertSame([[3.0, 4.0], [0.0, 0.6666666666666667]], $U->toArray());
}
}

View File

@ -22,11 +22,10 @@ class MatrixTest extends TestCase
$flatArray = [1, 2, 3, 4];
$matrix = Matrix::fromFlatArray($flatArray);
$this->assertInstanceOf(Matrix::class, $matrix);
$this->assertEquals([[1], [2], [3], [4]], $matrix->toArray());
$this->assertEquals(4, $matrix->getRows());
$this->assertEquals(1, $matrix->getColumns());
$this->assertEquals($flatArray, $matrix->getColumnValues(0));
self::assertEquals([[1], [2], [3], [4]], $matrix->toArray());
self::assertEquals(4, $matrix->getRows());
self::assertEquals(1, $matrix->getColumns());
self::assertEquals($flatArray, $matrix->getColumnValues(0));
}
public function testThrowExceptionOnInvalidColumnNumber(): void
@ -51,7 +50,7 @@ class MatrixTest extends TestCase
[4, 2, 1],
[5, 6, 7],
]);
$this->assertEquals(-3, $matrix->getDeterminant());
self::assertEquals(-3, $matrix->getDeterminant());
$matrix = new Matrix([
[1, 2, 3, 3, 2, 1],
@ -61,7 +60,7 @@ class MatrixTest extends TestCase
[1 / 4, 4, 1, 0, 2, 3 / 7],
[1, 8, 7, 5, 4, 4 / 5],
]);
$this->assertEquals(1116.5035, $matrix->getDeterminant(), '', $delta = 0.0001);
self::assertEquals(1116.5035, $matrix->getDeterminant(), '', $delta = 0.0001);
}
public function testMatrixTranspose(): void
@ -78,7 +77,7 @@ class MatrixTest extends TestCase
[3, 1, 7],
];
$this->assertEquals($transposedMatrix, $matrix->transpose()->toArray());
self::assertEquals($transposedMatrix, $matrix->transpose()->toArray());
}
public function testThrowExceptionOnMultiplyWhenInconsistentMatrixSupplied(): void
@ -107,7 +106,7 @@ class MatrixTest extends TestCase
[139, 154],
];
$this->assertEquals($product, $matrix1->multiply($matrix2)->toArray());
self::assertEquals($product, $matrix1->multiply($matrix2)->toArray());
}
public function testDivideByScalar(): void
@ -122,7 +121,7 @@ class MatrixTest extends TestCase
[1, 5, 10],
];
$this->assertEquals($quotient, $matrix->divideByScalar(2)->toArray());
self::assertEquals($quotient, $matrix->divideByScalar(2)->toArray());
}
public function testThrowExceptionWhenInverseIfArrayIsNotSquare(): void
@ -158,7 +157,7 @@ class MatrixTest extends TestCase
[-1 / 2, 1 / 2, -1 / 2],
];
$this->assertEquals($inverseMatrix, $matrix->inverse()->toArray(), '', $delta = 0.0001);
self::assertEquals($inverseMatrix, $matrix->inverse()->toArray(), '', $delta = 0.0001);
}
public function testCrossOutMatrix(): void
@ -174,14 +173,14 @@ class MatrixTest extends TestCase
[1, 1],
];
$this->assertEquals($crossOuted, $matrix->crossOut(1, 1)->toArray());
self::assertEquals($crossOuted, $matrix->crossOut(1, 1)->toArray());
}
public function testToScalar(): void
{
$matrix = new Matrix([[1, 2, 3], [3, 2, 3]]);
$this->assertEquals($matrix->toScalar(), 1);
self::assertEquals($matrix->toScalar(), 1);
}
public function testMultiplyByScalar(): void
@ -196,7 +195,7 @@ class MatrixTest extends TestCase
[-4, -20, -40],
];
$this->assertEquals($result, $matrix->multiplyByScalar(-2)->toArray());
self::assertEquals($result, $matrix->multiplyByScalar(-2)->toArray());
}
public function testAdd(): void
@ -208,7 +207,7 @@ class MatrixTest extends TestCase
$m1 = new Matrix($array1);
$m2 = new Matrix($array2);
$this->assertEquals($result, $m1->add($m2)->toArray()[0]);
self::assertEquals($result, $m1->add($m2)->toArray()[0]);
}
public function testSubtract(): void
@ -220,7 +219,7 @@ class MatrixTest extends TestCase
$m1 = new Matrix($array1);
$m2 = new Matrix($array2);
$this->assertEquals($result, $m1->subtract($m2)->toArray()[0]);
self::assertEquals($result, $m1->subtract($m2)->toArray()[0]);
}
public function testTransposeArray(): void
@ -235,7 +234,7 @@ class MatrixTest extends TestCase
[1, 2],
];
$this->assertEquals($transposed, Matrix::transposeArray($array));
self::assertEquals($transposed, Matrix::transposeArray($array));
}
public function testDot(): void
@ -244,12 +243,12 @@ class MatrixTest extends TestCase
$vect2 = [3, 3, 3];
$dot = [18];
$this->assertEquals($dot, Matrix::dot($vect1, $vect2));
self::assertEquals($dot, Matrix::dot($vect1, $vect2));
$matrix1 = [[1, 1], [2, 2]];
$matrix2 = [[3, 3], [3, 3], [3, 3]];
$dot = [6, 12];
$this->assertEquals($dot, Matrix::dot($matrix2, $matrix1));
self::assertEquals($dot, Matrix::dot($matrix2, $matrix1));
}
/**
@ -257,12 +256,10 @@ class MatrixTest extends TestCase
*/
public function testFrobeniusNorm(array $matrix, float $norm): void
{
$matrix = new Matrix($matrix);
$this->assertEquals($norm, $matrix->frobeniusNorm(), '', 0.0001);
self::assertEquals($norm, (new Matrix($matrix))->frobeniusNorm(), '', 0.0001);
}
public function dataProviderForFrobeniusNorm()
public function dataProviderForFrobeniusNorm(): array
{
return [
[

View File

@ -12,11 +12,11 @@ class ProductTest extends TestCase
{
public function testScalarProduct(): void
{
$this->assertEquals(10, Product::scalar([2, 3], [-1, 4]));
$this->assertEquals(-0.1, Product::scalar([1, 4, 1], [-2, 0.5, -0.1]));
$this->assertEquals(8, Product::scalar([2], [4]));
self::assertEquals(10, Product::scalar([2, 3], [-1, 4]));
self::assertEquals(-0.1, Product::scalar([1, 4, 1], [-2, 0.5, -0.1]));
self::assertEquals(8, Product::scalar([2], [4]));
//test for non numeric values
$this->assertEquals(0, Product::scalar(['', null, [], new stdClass()], [null]));
self::assertEquals(0, Product::scalar(['', null, [], new stdClass()], [null]));
}
}

View File

@ -13,84 +13,79 @@ class SetTest extends TestCase
{
$union = Set::union(new Set([3, 1]), new Set([3, 2, 2]));
$this->assertInstanceOf(Set::class, $union);
$this->assertEquals(new Set([1, 2, 3]), $union);
$this->assertEquals(3, $union->cardinality());
self::assertEquals(new Set([1, 2, 3]), $union);
self::assertEquals(3, $union->cardinality());
}
public function testIntersection(): void
{
$intersection = Set::intersection(new Set(['C', 'A']), new Set(['B', 'C']));
$this->assertInstanceOf(Set::class, $intersection);
$this->assertEquals(new Set(['C']), $intersection);
$this->assertEquals(1, $intersection->cardinality());
self::assertEquals(new Set(['C']), $intersection);
self::assertEquals(1, $intersection->cardinality());
}
public function testDifference(): void
{
$difference = Set::difference(new Set(['C', 'A', 'B']), new Set(['A']));
$this->assertInstanceOf(Set::class, $difference);
$this->assertEquals(new Set(['B', 'C']), $difference);
$this->assertEquals(2, $difference->cardinality());
self::assertEquals(new Set(['B', 'C']), $difference);
self::assertEquals(2, $difference->cardinality());
}
public function testPower(): void
{
$power = Set::power(new Set(['A', 'B']));
$this->assertInternalType('array', $power);
$this->assertEquals([new Set(), new Set(['A']), new Set(['B']), new Set(['A', 'B'])], $power);
$this->assertCount(4, $power);
self::assertEquals([new Set(), new Set(['A']), new Set(['B']), new Set(['A', 'B'])], $power);
self::assertCount(4, $power);
}
public function testCartesian(): void
{
$cartesian = Set::cartesian(new Set(['A']), new Set([1, 2]));
$this->assertInternalType('array', $cartesian);
$this->assertEquals([new Set(['A', 1]), new Set(['A', 2])], $cartesian);
$this->assertCount(2, $cartesian);
self::assertEquals([new Set(['A', 1]), new Set(['A', 2])], $cartesian);
self::assertCount(2, $cartesian);
}
public function testContains(): void
{
$set = new Set(['B', 'A', 2, 1]);
$this->assertTrue($set->contains('B'));
$this->assertTrue($set->containsAll(['A', 'B']));
self::assertTrue($set->contains('B'));
self::assertTrue($set->containsAll(['A', 'B']));
$this->assertFalse($set->contains('C'));
$this->assertFalse($set->containsAll(['A', 'B', 'C']));
self::assertFalse($set->contains('C'));
self::assertFalse($set->containsAll(['A', 'B', 'C']));
}
public function testRemove(): void
{
$set = new Set(['B', 'A', 2, 1]);
$this->assertEquals((new Set([1, 2, 2, 2, 'B']))->toArray(), $set->remove('A')->toArray());
self::assertEquals((new Set([1, 2, 2, 2, 'B']))->toArray(), $set->remove('A')->toArray());
}
public function testAdd(): void
{
$set = new Set(['B', 'A', 2, 1]);
$set->addAll(['foo', 'bar']);
$this->assertEquals(6, $set->cardinality());
self::assertEquals(6, $set->cardinality());
}
public function testEmpty(): void
{
$set = new Set([1, 2]);
$set->removeAll([2, 1]);
$this->assertEquals(new Set(), $set);
$this->assertTrue($set->isEmpty());
self::assertEquals(new Set(), $set);
self::assertTrue($set->isEmpty());
}
public function testToArray(): void
{
$set = new Set([1, 2, 2, 3, 'A', false, '', 1.1, -1, -10, 'B']);
$this->assertEquals([-10, '', -1, 'A', 'B', 1, 1.1, 2, 3], $set->toArray());
self::assertEquals([-10, '', -1, 'A', 'B', 1, 1.1, 2, 3], $set->toArray());
}
}

View File

@ -16,18 +16,18 @@ class CorrelationTest extends TestCase
$delta = 0.001;
$x = [9300, 10565, 15000, 15000, 17764, 57000, 65940, 73676, 77006, 93739, 146088, 153260];
$y = [7100, 15500, 4400, 4400, 5900, 4600, 8800, 2000, 2750, 2550, 960, 1025];
$this->assertEquals(-0.641, Correlation::pearson($x, $y), '', $delta);
self::assertEquals(-0.641, Correlation::pearson($x, $y), '', $delta);
//http://www.statisticshowto.com/how-to-compute-pearsons-correlation-coefficients/
$delta = 0.001;
$x = [43, 21, 25, 42, 57, 59];
$y = [99, 65, 79, 75, 87, 82];
$this->assertEquals(0.549, Correlation::pearson($x, $y), '', $delta);
self::assertEquals(0.549, Correlation::pearson($x, $y), '', $delta);
$delta = 0.001;
$x = [60, 61, 62, 63, 65];
$y = [3.1, 3.6, 3.8, 4, 4.1];
$this->assertEquals(0.911, Correlation::pearson($x, $y), '', $delta);
self::assertEquals(0.911, Correlation::pearson($x, $y), '', $delta);
}
public function testThrowExceptionOnInvalidArgumentsForPearsonCorrelation(): void

Some files were not shown because too many files have changed in this diff Show More