diff --git a/.travis.yml b/.travis.yml index 92c643b3..30ee8232 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,9 @@ matrix: - os: linux php: '7.3' + - os: linux + php: '7.4' + cache: directories: - $HOME/.composer/cache diff --git a/CHANGELOG.md b/CHANGELOG.md index 662a086a..b403887f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.9.0] - Unreleased ### Added - [Preprocessing] Implement LabelEncoder +- [Preprocessing] Implement ColumnFilter +- [Preprocessing] Implement LambdaTransformer +- [Preprocessing] Implement NumberConverter +- [Preprocessing] Implement OneHotEncoder +- [Workflow] Implement FeatureUnion +- [Metric] Add Regression metrics: meanSquaredError, meanSquaredLogarithmicError, meanAbsoluteError, medianAbsoluteError, r2Score, maxError +- [Regression] Implement DecisionTreeRegressor ## [0.8.0] - 2019-03-20 ### Added diff --git a/LICENSE b/LICENSE index c90077cb..bcb78954 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ The MIT License (MIT) -Copyright (c) 2016-2018 Arkadiusz Kondas +Copyright (c) 2016-2019 Arkadiusz Kondas +Copyright (c) 2018 Andrew DalPino Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3449ee0d..f34a49ab 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Public datasets are available in a separate repository [php-ai/php-ml-datasets]( * Regression * [Least Squares](http://php-ml.readthedocs.io/en/latest/machine-learning/regression/least-squares/) * [SVR](http://php-ml.readthedocs.io/en/latest/machine-learning/regression/svr/) + * DecisionTreeRegressor * Clustering * [k-Means](http://php-ml.readthedocs.io/en/latest/machine-learning/clustering/k-means/) * [DBSCAN](http://php-ml.readthedocs.io/en/latest/machine-learning/clustering/dbscan/) @@ -87,8 +88,10 @@ Public datasets are available in a separate repository [php-ai/php-ml-datasets]( * [Accuracy](http://php-ml.readthedocs.io/en/latest/machine-learning/metric/accuracy/) * [Confusion Matrix](http://php-ml.readthedocs.io/en/latest/machine-learning/metric/confusion-matrix/) * [Classification Report](http://php-ml.readthedocs.io/en/latest/machine-learning/metric/classification-report/) + * Regression * Workflow * [Pipeline](http://php-ml.readthedocs.io/en/latest/machine-learning/workflow/pipeline) + * FeatureUnion * Neural Network * [Multilayer Perceptron Classifier](http://php-ml.readthedocs.io/en/latest/machine-learning/neural-network/multilayer-perceptron-classifier/) * Cross Validation @@ -101,6 +104,10 @@ Public datasets are available in a separate repository [php-ai/php-ml-datasets]( * [Normalization](http://php-ml.readthedocs.io/en/latest/machine-learning/preprocessing/normalization/) * [Imputation missing values](http://php-ml.readthedocs.io/en/latest/machine-learning/preprocessing/imputation-missing-values/) * LabelEncoder + * LambdaTransformer + * NumberConverter + * ColumnFilter + * OneHotEncoder * Feature Extraction * [Token Count Vectorizer](http://php-ml.readthedocs.io/en/latest/machine-learning/feature-extraction/token-count-vectorizer/) * NGramTokenizer diff --git a/composer.json b/composer.json index 52e783c3..d3cbc2b1 100644 --- a/composer.json +++ b/composer.json @@ -20,16 +20,15 @@ } ], "require": { - "php": "^7.2" + "php": ">=7.2" }, "require-dev": { - "phpbench/phpbench": "^0.14.0", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpstan/phpstan-strict-rules": "^0.11", + "phpbench/phpbench": "^0.16.0", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", "phpunit/phpunit": "^8.0", - "symplify/coding-standard": "^5.1", - "symplify/easy-coding-standard": "^5.1" + "symplify/easy-coding-standard": "^6.0" }, "config": { "preferred-install": "dist", diff --git a/composer.lock b/composer.lock index e270c978..3a8a25fb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,37 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b329ea9fc7b690ad2d498e85a445d214", + "content-hash": "914a4eb72418c2cf0d2321cafd474ac2", "packages": [], "packages-dev": [ { "name": "beberlei/assert", - "version": "v2.9.6", + "version": "v3.2.7", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "ec9e4cf0b63890edce844ee3922e2b95a526e936" + "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/ec9e4cf0b63890edce844ee3922e2b95a526e936", - "reference": "ec9e4cf0b63890edce844ee3922e2b95a526e936", + "url": "https://api.github.com/repos/beberlei/assert/zipball/d63a6943fc4fd1a2aedb65994e3548715105abcf", + "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-mbstring": "*", - "php": ">=5.3" + "ext-simplexml": "*", + "php": "^7" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.1.1", - "phpunit/phpunit": "^4.8.35|^5.7" + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan-shim": "*", + "phpunit/phpunit": ">=6.0.0 <8" + }, + "suggest": { + "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" }, "type": "library", "autoload": { @@ -60,28 +67,27 @@ "assertion", "validation" ], - "time": "2018-06-11T17:15:25+00:00" + "time": "2019-12-19T17:51:41+00:00" }, { "name": "composer/semver", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e" + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/46d9139568ccb8d9e7cdd4539cab7347568a5e2e", - "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "^4.5 || ^5.0.5" }, "type": "library", "extra": { @@ -122,28 +128,28 @@ "validation", "versioning" ], - "time": "2019-03-19T17:25:45+00:00" + "time": "2020-01-13T12:06:48+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.3.2", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "d17708133b6c276d6e42ef887a877866b909d892" + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/d17708133b6c276d6e42ef887a877866b909d892", - "reference": "d17708133b6c276d6e42ef887a877866b909d892", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7", + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0", + "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" }, "type": "library", "autoload": { @@ -161,25 +167,25 @@ "email": "john-stevenson@blueyonder.co.uk" } ], - "description": "Restarts a process without xdebug.", + "description": "Restarts a process without Xdebug.", "keywords": [ "Xdebug", "performance" ], - "time": "2019-01-28T20:25:53+00:00" + "time": "2020-03-01T12:26:26+00:00" }, { "name": "doctrine/annotations", - "version": "v1.6.0", + "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", "shasum": "" }, "require": { @@ -188,12 +194,12 @@ }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -206,72 +212,10 @@ "MIT" ], "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org/", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "time": "2017-12-06T07:11:42+00:00" - }, - { - "name": "doctrine/inflector", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/inflector.git", - "reference": "5527a48b7313d15261292c149e55e26eae771b0a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a", - "reference": "5527a48b7313d15261292c149e55e26eae771b0a", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^6.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -280,10 +224,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -293,28 +233,27 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "description": "Docblock Annotations Parser", "homepage": "http://www.doctrine-project.org/", "keywords": [ - "inflection", - "pluralize", - "singularize", - "string" + "annotations", + "docblock", + "parser" ], - "time": "2018-01-09T20:05:19+00:00" + "time": "2019-10-01T18:55:10+00:00" }, { "name": "doctrine/instantiator", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "a2c590166b2133a4633738648b6b064edae0814a" + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", - "reference": "a2c590166b2133a4633738648b6b064edae0814a", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", "shasum": "" }, "require": { @@ -357,34 +296,39 @@ "constructor", "instantiate" ], - "time": "2019-03-17T17:37:11+00:00" + "time": "2019-10-21T16:45:58+00:00" }, { "name": "doctrine/lexer", - "version": "v1.0.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.2" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } }, "notification-url": "https://packagist.org/downloads/", @@ -392,39 +336,42 @@ "MIT" ], "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" } ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org/", + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", "keywords": [ + "annotations", + "docblock", "lexer", - "parser" + "parser", + "php" ], - "time": "2014-09-09T13:34:57+00:00" + "time": "2019-10-30T14:39:59+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v2.14.2", + "version": "v2.16.1", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "ff401e58261ffc5934a58f795b3f95b355e276cb" + "reference": "c8afb599858876e95e8ebfcd97812d383fa23f02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/ff401e58261ffc5934a58f795b3f95b355e276cb", - "reference": "ff401e58261ffc5934a58f795b3f95b355e276cb", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/c8afb599858876e95e8ebfcd97812d383fa23f02", + "reference": "c8afb599858876e95e8ebfcd97812d383fa23f02", "shasum": "" }, "require": { @@ -435,15 +382,15 @@ "ext-tokenizer": "*", "php": "^5.6 || ^7.0", "php-cs-fixer/diff": "^1.3", - "symfony/console": "^3.4.17 || ^4.1.6", - "symfony/event-dispatcher": "^3.0 || ^4.0", - "symfony/filesystem": "^3.0 || ^4.0", - "symfony/finder": "^3.0 || ^4.0", - "symfony/options-resolver": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "symfony/event-dispatcher": "^3.0 || ^4.0 || ^5.0", + "symfony/filesystem": "^3.0 || ^4.0 || ^5.0", + "symfony/finder": "^3.0 || ^4.0 || ^5.0", + "symfony/options-resolver": "^3.0 || ^4.0 || ^5.0", "symfony/polyfill-php70": "^1.0", "symfony/polyfill-php72": "^1.4", - "symfony/process": "^3.0 || ^4.0", - "symfony/stopwatch": "^3.0 || ^4.0" + "symfony/process": "^3.0 || ^4.0 || ^5.0", + "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0" }, "require-dev": { "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0", @@ -452,11 +399,12 @@ "mikey179/vfsstream": "^1.6", "php-coveralls/php-coveralls": "^2.1", "php-cs-fixer/accessible-object": "^1.0", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.0.1", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.0.1", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1", - "phpunitgoodpractices/traits": "^1.5.1", - "symfony/phpunit-bridge": "^4.0" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.1", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.1", + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.1", + "phpunitgoodpractices/traits": "^1.8", + "symfony/phpunit-bridge": "^4.3 || ^5.0", + "symfony/yaml": "^3.0 || ^4.0 || ^5.0" }, "suggest": { "ext-mbstring": "For handling non-UTF8 characters in cache signature.", @@ -489,122 +437,17 @@ "MIT" ], "authors": [ - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" - } - ], - "description": "A tool to automatically fix PHP code style", - "time": "2019-02-17T17:44:13+00:00" - }, - { - "name": "illuminate/contracts", - "version": "v5.8.4", - "source": { - "type": "git", - "url": "https://github.com/illuminate/contracts.git", - "reference": "3e3a9a654adbf798e05491a5dbf90112df1effde" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/3e3a9a654adbf798e05491a5dbf90112df1effde", - "reference": "3e3a9a654adbf798e05491a5dbf90112df1effde", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "psr/container": "^1.0", - "psr/simple-cache": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.8-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Contracts\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Contracts package.", - "homepage": "https://laravel.com/", - "time": "2019-02-18T18:37:54+00:00" - }, - { - "name": "illuminate/support", - "version": "v5.8.4", - "source": { - "type": "git", - "url": "https://github.com/illuminate/support.git", - "reference": "07062f5750872a31e086ff37a7c50ac18b8c417c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/07062f5750872a31e086ff37a7c50ac18b8c417c", - "reference": "07062f5750872a31e086ff37a7c50ac18b8c417c", - "shasum": "" - }, - "require": { - "doctrine/inflector": "^1.1", - "ext-json": "*", - "ext-mbstring": "*", - "illuminate/contracts": "5.8.*", - "nesbot/carbon": "^1.26.3 || ^2.0", - "php": "^7.1.3" - }, - "conflict": { - "tightenco/collect": "<5.5.33" - }, - "suggest": { - "illuminate/filesystem": "Required to use the composer class (5.8.*).", - "moontoast/math": "Required to use ordered UUIDs (^1.1).", - "ramsey/uuid": "Required to use Str::uuid() (^3.7).", - "symfony/process": "Required to use the composer class (^4.2).", - "symfony/var-dumper": "Required to use the dd function (^4.2).", - "vlucas/phpdotenv": "Required to use the env helper (^3.3)." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.8-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" }, - "files": [ - "helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" } ], - "description": "The Illuminate Support package.", - "homepage": "https://laravel.com/", - "time": "2019-03-12T13:17:00+00:00" + "description": "A tool to automatically fix PHP code style", + "time": "2019-11-25T22:10:32+00:00" }, { "name": "jean85/pretty-package-versions", @@ -659,30 +502,27 @@ }, { "name": "lstrojny/functional-php", - "version": "1.9.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/lstrojny/functional-php.git", - "reference": "f5b3b4424dcddb406d3dcfcae0d1bc0060099a78" + "reference": "df0e516eb44cd0579eeaff57023ef41ffa11947f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lstrojny/functional-php/zipball/f5b3b4424dcddb406d3dcfcae0d1bc0060099a78", - "reference": "f5b3b4424dcddb406d3dcfcae0d1bc0060099a78", + "url": "https://api.github.com/repos/lstrojny/functional-php/zipball/df0e516eb44cd0579eeaff57023ef41ffa11947f", + "reference": "df0e516eb44cd0579eeaff57023ef41ffa11947f", "shasum": "" }, "require": { "php": "~7" }, "require-dev": { - "phpunit/phpunit": "~6" + "friendsofphp/php-cs-fixer": "^2.14", + "phpunit/phpunit": "~7", + "squizlabs/php_codesniffer": "~3.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, "autoload": { "psr-4": { "Functional\\": "src/Functional" @@ -697,6 +537,7 @@ "src/Functional/Compose.php", "src/Functional/Concat.php", "src/Functional/Contains.php", + "src/Functional/Converge.php", "src/Functional/Curry.php", "src/Functional/CurryN.php", "src/Functional/Difference.php", @@ -739,7 +580,9 @@ "src/Functional/Memoize.php", "src/Functional/Minimum.php", "src/Functional/None.php", + "src/Functional/Noop.php", "src/Functional/Not.php", + "src/Functional/OmitKeys.php", "src/Functional/PartialAny.php", "src/Functional/PartialLeft.php", "src/Functional/PartialMethod.php", @@ -754,6 +597,7 @@ "src/Functional/ReduceRight.php", "src/Functional/Reindex.php", "src/Functional/Reject.php", + "src/Functional/Repeat.php", "src/Functional/Retry.php", "src/Functional/Select.php", "src/Functional/SelectKeys.php", @@ -767,6 +611,8 @@ "src/Functional/Tap.php", "src/Functional/Tail.php", "src/Functional/TailRecursion.php", + "src/Functional/TakeLeft.php", + "src/Functional/TakeRight.php", "src/Functional/True.php", "src/Functional/Truthy.php", "src/Functional/Unique.php", @@ -794,20 +640,20 @@ "keywords": [ "functional" ], - "time": "2018-12-03T16:47:05+00:00" + "time": "2019-12-19T16:01:40+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.8.1", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", "shasum": "" }, "require": { @@ -842,84 +688,24 @@ "object", "object graph" ], - "time": "2018-06-11T23:09:50+00:00" - }, - { - "name": "nesbot/carbon", - "version": "2.16.0", - "source": { - "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "dd16fedc022180ea4292a03aabe95e9895677911" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/dd16fedc022180ea4292a03aabe95e9895677911", - "reference": "dd16fedc022180ea4292a03aabe95e9895677911", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": "^7.1.8 || ^8.0", - "symfony/translation": "^3.4 || ^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", - "kylekatarnls/multi-tester": "^0.1", - "phpmd/phpmd": "^2.6", - "phpstan/phpstan": "^0.10.8", - "phpunit/phpunit": "^7.5 || ^8.0", - "squizlabs/php_codesniffer": "^3.4" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Carbon\\Laravel\\ServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Carbon\\": "src/Carbon/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Brian Nesbitt", - "email": "brian@nesbot.com", - "homepage": "http://nesbot.com/" - } - ], - "description": "A simple API extension for DateTime.", - "homepage": "http://carbon.nesbot.com/", - "keywords": [ - "date", - "datetime", - "time" - ], - "time": "2019-03-12T09:31:40+00:00" + "time": "2020-01-17T21:11:47+00:00" }, { "name": "nette/finder", - "version": "v2.5.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/nette/finder.git", - "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2" + "reference": "4ad2c298eb8c687dd0e74ae84206a4186eeaed50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/finder/zipball/6be1b83ea68ac558aff189d640abe242e0306fe2", - "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2", + "url": "https://api.github.com/repos/nette/finder/zipball/4ad2c298eb8c687dd0e74ae84206a4186eeaed50", + "reference": "4ad2c298eb8c687dd0e74ae84206a4186eeaed50", "shasum": "" }, "require": { - "nette/utils": "^2.4 || ~3.0.0", + "nette/utils": "^2.4 || ^3.0", "php": ">=7.1" }, "conflict": { @@ -927,6 +713,7 @@ }, "require-dev": { "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", "tracy/tracy": "^2.3" }, "type": "library", @@ -964,39 +751,37 @@ "iterator", "nette" ], - "time": "2019-02-28T18:13:25+00:00" + "time": "2020-01-03T20:35:40+00:00" }, { "name": "nette/robot-loader", - "version": "v3.1.1", + "version": "v3.2.2", "source": { "type": "git", "url": "https://github.com/nette/robot-loader.git", - "reference": "3e8d75d6d976e191bdf46752ca40a286671219d2" + "reference": "38e8a270567a4ad9fe716b40fcda5a6580afa3c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/robot-loader/zipball/3e8d75d6d976e191bdf46752ca40a286671219d2", - "reference": "3e8d75d6d976e191bdf46752ca40a286671219d2", + "url": "https://api.github.com/repos/nette/robot-loader/zipball/38e8a270567a4ad9fe716b40fcda5a6580afa3c0", + "reference": "38e8a270567a4ad9fe716b40fcda5a6580afa3c0", "shasum": "" }, "require": { "ext-tokenizer": "*", - "nette/finder": "^2.3 || ^3.0", - "nette/utils": "^2.4 || ^3.0", - "php": ">=5.6.0" - }, - "conflict": { - "nette/nette": "<2.2" + "nette/finder": "^2.5 || ^3.0", + "nette/utils": "^3.0", + "php": ">=7.1" }, "require-dev": { "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", "tracy/tracy": "^2.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -1007,8 +792,8 @@ "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" + "GPL-2.0-only", + "GPL-3.0-only" ], "authors": [ { @@ -1029,59 +814,55 @@ "nette", "trait" ], - "time": "2019-03-01T20:23:02+00:00" + "time": "2020-02-20T22:17:50+00:00" }, { "name": "nette/utils", - "version": "v2.5.3", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce" + "reference": "2c17d16d8887579ae1c0898ff94a3668997fd3eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/17b9f76f2abd0c943adfb556e56f2165460b15ce", - "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce", + "url": "https://api.github.com/repos/nette/utils/zipball/2c17d16d8887579ae1c0898ff94a3668997fd3eb", + "reference": "2c17d16d8887579ae1c0898ff94a3668997fd3eb", "shasum": "" }, "require": { - "php": ">=5.6.0" - }, - "conflict": { - "nette/nette": "<2.2" + "php": ">=7.1" }, "require-dev": { "nette/tester": "~2.0", + "phpstan/phpstan": "^0.12", "tracy/tracy": "^2.3" }, "suggest": { "ext-gd": "to use Image", "ext-iconv": "to use Strings::webalize() and toAscii()", - "ext-intl": "for script transliteration in Strings::webalize() and toAscii()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", "ext-json": "to use Nette\\Utils\\Json", "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", "ext-xml": "to use Strings::length() etc. when mbstring is not available" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "3.1-dev" } }, "autoload": { "classmap": [ "src/" - ], - "files": [ - "src/loader.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" + "GPL-2.0-only", + "GPL-3.0-only" ], "authors": [ { @@ -1111,38 +892,39 @@ "utility", "validation" ], - "time": "2018-09-18T10:22:16+00:00" + "time": "2020-02-09T14:10:55+00:00" }, { "name": "ocramius/package-versions", - "version": "1.4.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c", "shasum": "" }, "require": { "composer-plugin-api": "^1.0.0", - "php": "^7.1.0" + "php": "^7.3.0" }, "require-dev": { - "composer/composer": "^1.6.3", - "doctrine/coding-standard": "^5.0.1", + "composer/composer": "^1.8.6", + "doctrine/coding-standard": "^6.0.0", "ext-zip": "*", - "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.0.0" + "infection/infection": "^0.13.4", + "phpunit/phpunit": "^8.2.5", + "vimeo/psalm": "^3.4.9" }, "type": "composer-plugin", "extra": { "class": "PackageVersions\\Installer", "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -1161,7 +943,7 @@ } ], "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-02-21T12:16:21+00:00" + "time": "2019-07-17T15:49:50+00:00" }, { "name": "paragonie/random_compat", @@ -1452,47 +1234,49 @@ }, { "name": "phpbench/phpbench", - "version": "0.14.0", + "version": "0.16.10", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "ea2c7ca1cdbfa952b8d50c4f36fc233dbfabe3c9" + "reference": "00c18b1ab87dbda66e8972c8602a14dd08c69914" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/ea2c7ca1cdbfa952b8d50c4f36fc233dbfabe3c9", - "reference": "ea2c7ca1cdbfa952b8d50c4f36fc233dbfabe3c9", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/00c18b1ab87dbda66e8972c8602a14dd08c69914", + "reference": "00c18b1ab87dbda66e8972c8602a14dd08c69914", "shasum": "" }, "require": { - "beberlei/assert": "^2.4", + "beberlei/assert": "^2.4 || ^3.0", "doctrine/annotations": "^1.2.7", "ext-dom": "*", "ext-json": "*", "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", - "lstrojny/functional-php": "1.0|^1.2.3", - "php": "^7.0", - "phpbench/container": "~1.0", + "lstrojny/functional-php": "1.0 || ^1.2.3", + "php": "^7.1", + "phpbench/container": "~1.2", "phpbench/dom": "~0.2.0", - "seld/jsonlint": "^1.0", - "symfony/console": "^2.6|^3.0|^4.0", - "symfony/debug": "^2.4|^3.0|^4.0", - "symfony/filesystem": "^2.4|^3.0|^4.0", - "symfony/finder": "^2.4|^3.0|^4.0", - "symfony/options-resolver": "^2.6|^3.0|^4.0", - "symfony/process": "^2.1|^3.0|^4.0" + "seld/jsonlint": "^1.1", + "symfony/console": "^3.2 || ^4.0", + "symfony/debug": "^2.4 || ^3.0 || ^4.0", + "symfony/filesystem": "^2.4 || ^3.0 || ^4.0", + "symfony/finder": "^2.4 || ^3.0 || ^4.0", + "symfony/options-resolver": "^2.6 || ^3.0 || ^4.0", + "symfony/process": "^2.1 || ^3.0 || ^4.0", + "webmozart/path-util": "^2.3" }, "require-dev": { "doctrine/dbal": "^2.4", - "liip/rmt": "^1.2", + "friendsofphp/php-cs-fixer": "^2.13.1", "padraic/phar-updater": "^1.0", - "phpstan/phpstan": "^0.8.5", - "phpunit/phpunit": "^6.0" + "phpstan/phpstan": "^0.10.7", + "phpunit/phpunit": "^6.5 || ^7.0" }, "suggest": { - "ext-xdebug": "For XDebug profiling extension." + "ext-curl": "For (web) reports extension", + "ext-xdebug": "For Xdebug profiling extension." }, "bin": [ "bin/phpbench" @@ -1507,7 +1291,8 @@ "psr-4": { "PhpBench\\": "lib/", "PhpBench\\Extensions\\Dbal\\": "extensions/dbal/lib/", - "PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/" + "PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/", + "PhpBench\\Extensions\\Reports\\": "extensions/reports/lib/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1521,39 +1306,37 @@ } ], "description": "PHP Benchmarking Framework", - "time": "2017-12-05T15:55:57+00:00" + "time": "2019-09-01T08:08:02+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1575,44 +1358,42 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", - "webmozart/assert": "^1.0" + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1623,44 +1404,46 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2020-02-22T12:28:44+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-tokenizer": "^7.2", + "mockery/mockery": "~1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1673,42 +1456,43 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2020-02-18T18:59:58+00:00" }, { "name": "phpspec/prophecy", - "version": "1.8.0", + "version": "v1.10.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", + "phpspec/phpspec": "^2.5 || ^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -1736,80 +1520,71 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2020-01-20T15:57:02+00:00" }, { - "name": "phpstan/phpstan-phpunit", - "version": "0.11", + "name": "phpstan/phpdoc-parser", + "version": "0.3.5", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "70c22d44b96a21a4952fc13021a5a63cc83f5c81" + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/70c22d44b96a21a4952fc13021a5a63cc83f5c81", - "reference": "70c22d44b96a21a4952fc13021a5a63cc83f5c81", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/8c4ef2aefd9788238897b678a985e1d5c8df6db4", + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4", "shasum": "" }, "require": { - "nikic/php-parser": "^4.0", - "php": "~7.1", - "phpstan/phpdoc-parser": "^0.3", - "phpstan/phpstan": "^0.11" - }, - "conflict": { - "phpunit/phpunit": "<7.0" + "php": "~7.1" }, "require-dev": { - "consistence/coding-standard": "^3.0.1", - "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", - "jakub-onderka/php-parallel-lint": "^1.0", + "consistence/coding-standard": "^3.5", + "jakub-onderka/php-parallel-lint": "^0.9.2", "phing/phing": "^2.16.0", - "phpstan/phpstan-strict-rules": "^0.11", - "phpunit/phpunit": "^7.0", - "satooshi/php-coveralls": "^1.0", - "slevomat/coding-standard": "^4.5.2" + "phpstan/phpstan": "^0.10", + "phpunit/phpunit": "^6.3", + "slevomat/coding-standard": "^4.7.2", + "squizlabs/php_codesniffer": "^3.3.2", + "symfony/process": "^3.4 || ^4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.11-dev" + "dev-master": "0.3-dev" } }, "autoload": { "psr-4": { - "PHPStan\\": "src/" + "PHPStan\\PhpDocParser\\": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "PHPUnit extensions and rules for PHPStan", - "time": "2018-12-22T14:05:04+00:00" + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "time": "2019-06-07T19:13:52+00:00" }, { - "name": "phpstan/phpstan-shim", - "version": "0.11.4", + "name": "phpstan/phpstan", + "version": "0.12.13", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan-shim.git", - "reference": "70e1a346907142449ac085745f158aa715b4e0b8" + "url": "https://github.com/phpstan/phpstan.git", + "reference": "d74fb5ce1ab9f24a7128db90e99dec82440975c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-shim/zipball/70e1a346907142449ac085745f158aa715b4e0b8", - "reference": "70e1a346907142449ac085745f158aa715b4e0b8", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d74fb5ce1ab9f24a7128db90e99dec82440975c3", + "reference": "d74fb5ce1ab9f24a7128db90e99dec82440975c3", "shasum": "" }, "require": { - "php": "~7.1" - }, - "replace": { - "nikic/php-parser": "^4.0.2", - "phpstan/phpdoc-parser": "^0.3", - "phpstan/phpstan": "self.version" + "php": "^7.1" }, "bin": [ "phpstan", @@ -1818,7 +1593,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "0.11-dev" + "dev-master": "0.12-dev" } }, "autoload": { @@ -1830,41 +1605,102 @@ "license": [ "MIT" ], - "description": "PHPStan Phar distribution", - "time": "2019-03-14T15:24:47+00:00" + "description": "PHPStan - PHP Static Analysis Tool", + "time": "2020-03-02T13:08:55+00:00" + }, + { + "name": "phpstan/phpstan-phpunit", + "version": "0.12.6", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "26394996368b6d033d012547d3197f4e07e23021" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/26394996368b6d033d012547d3197f4e07e23021", + "reference": "26394996368b6d033d012547d3197f4e07e23021", + "shasum": "" + }, + "require": { + "php": "~7.1", + "phpstan/phpstan": "^0.12.4" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "consistence/coding-standard": "^3.5", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "ergebnis/composer-normalize": "^2.0.2", + "jakub-onderka/php-parallel-lint": "^1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0", + "satooshi/php-coveralls": "^1.0", + "slevomat/coding-standard": "^4.7.2" + }, + "type": "phpstan-extension", + "extra": { + "branch-alias": { + "dev-master": "0.12-dev" + }, + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "time": "2020-01-10T12:07:21+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "0.11", + "version": "0.12.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "747a742b26a35ef4e4ebef5ec4490ad74eebcbc0" + "reference": "a670a59aff7cf96f75d21b974860ada10e25b2ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/747a742b26a35ef4e4ebef5ec4490ad74eebcbc0", - "reference": "747a742b26a35ef4e4ebef5ec4490ad74eebcbc0", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/a670a59aff7cf96f75d21b974860ada10e25b2ee", + "reference": "a670a59aff7cf96f75d21b974860ada10e25b2ee", "shasum": "" }, "require": { - "nikic/php-parser": "^4.0", "php": "~7.1", - "phpstan/phpstan": "^0.11" + "phpstan/phpstan": "^0.12.6" }, "require-dev": { "consistence/coding-standard": "^3.0.1", "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "ergebnis/composer-normalize": "^2.0.2", "jakub-onderka/php-parallel-lint": "^1.0", "phing/phing": "^2.16.0", - "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-phpunit": "^0.12", "phpunit/phpunit": "^7.0", "slevomat/coding-standard": "^4.5.2" }, - "type": "library", + "type": "phpstan-extension", "extra": { "branch-alias": { - "dev-master": "0.11-dev" + "dev-master": "0.12-dev" + }, + "phpstan": { + "includes": [ + "rules.neon" + ] } }, "autoload": { @@ -1877,20 +1713,20 @@ "MIT" ], "description": "Extra strict and opinionated rules for PHPStan", - "time": "2019-01-14T09:56:55+00:00" + "time": "2020-01-20T13:08:52+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "7.0.3", + "version": "7.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "0317a769a81845c390e19684d9ba25d7f6aa4707" + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0317a769a81845c390e19684d9ba25d7f6aa4707", - "reference": "0317a769a81845c390e19684d9ba25d7f6aa4707", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", "shasum": "" }, "require": { @@ -1899,17 +1735,17 @@ "php": "^7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0.1", + "phpunit/php-token-stream": "^3.1.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.1", + "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^8.0" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-xdebug": "^2.6.1" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { @@ -1940,7 +1776,7 @@ "testing", "xunit" ], - "time": "2019-02-26T07:38:26+00:00" + "time": "2019-11-20T13:55:58+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2035,16 +1871,16 @@ }, { "name": "phpunit/php-timer", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b389aebe1b8b0578430bda0c7c95a829608e059", - "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { @@ -2080,20 +1916,20 @@ "keywords": [ "timer" ], - "time": "2019-02-20T10:12:59+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "3.0.1", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { @@ -2106,7 +1942,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -2129,46 +1965,47 @@ "keywords": [ "tokenizer" ], - "time": "2018-10-30T05:52:18+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "8.0.5", + "version": "8.5.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "19cbed2120839772c4a00e8b28456b0c77d1a7b4" + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/19cbed2120839772c4a00e8b28456b0c77d1a7b4", - "reference": "19cbed2120839772c4a00e8b28456b0c77d1a7b4", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0", + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.1", + "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.7", - "phar-io/manifest": "^1.0.2", - "phar-io/version": "^2.0", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", "php": "^7.2", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^7.0", - "phpunit/php-file-iterator": "^2.0.1", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^7.0.7", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^4.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^3.0", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.2", + "sebastian/exporter": "^3.1.1", + "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, "require-dev": { @@ -2177,7 +2014,7 @@ "suggest": { "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -2185,7 +2022,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.0-dev" + "dev-master": "8.5-dev" } }, "autoload": { @@ -2211,7 +2048,7 @@ "testing", "xunit" ], - "time": "2019-03-16T07:33:46+00:00" + "time": "2020-01-08T08:49:49+00:00" }, { "name": "psr/cache", @@ -2310,16 +2147,16 @@ }, { "name": "psr/log", - "version": "1.1.0", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", "shasum": "" }, "require": { @@ -2328,7 +2165,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -2353,7 +2190,7 @@ "psr", "psr-3" ], - "time": "2018-11-20T15:27:04+00:00" + "time": "2019-11-01T11:05:21+00:00" }, { "name": "psr/simple-cache", @@ -2570,16 +2407,16 @@ }, { "name": "sebastian/environment", - "version": "4.1.0", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6fda8ce1974b62b14935adc02a9ed38252eca656", - "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { @@ -2594,7 +2431,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -2619,20 +2456,20 @@ "environment", "hhvm" ], - "time": "2019-02-01T05:27:49+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { @@ -2659,6 +2496,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -2667,17 +2508,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -2686,7 +2523,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", @@ -2929,6 +2766,52 @@ "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "time": "2018-10-04T04:07:39+00:00" }, + { + "name": "sebastian/type", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2019-07-02T08:10:15+00:00" + }, { "name": "sebastian/version", "version": "2.0.1", @@ -2974,16 +2857,16 @@ }, { "name": "seld/jsonlint", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38" + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", "shasum": "" }, "require": { @@ -3019,54 +2902,7 @@ "parser", "validator" ], - "time": "2018-01-24T12:46:19+00:00" - }, - { - "name": "slam/php-cs-fixer-extensions", - "version": "v1.18.0", - "source": { - "type": "git", - "url": "https://github.com/Slamdunk/php-cs-fixer-extensions.git", - "reference": "da18f089d1c559915d3c25d5e8783c7b7d272d1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Slamdunk/php-cs-fixer-extensions/zipball/da18f089d1c559915d3c25d5e8783c7b7d272d1d", - "reference": "da18f089d1c559915d3c25d5e8783c7b7d272d1d", - "shasum": "" - }, - "require": { - "friendsofphp/php-cs-fixer": "^2.14", - "php": "^7.1" - }, - "require-dev": { - "phpstan/phpstan": "^0.10", - "phpstan/phpstan-phpunit": "^0.10", - "phpunit/phpunit": "^7.5", - "roave/security-advisories": "dev-master", - "slam/php-debug-r": "^1.4", - "slam/phpstan-extensions": "^2.0", - "thecodingmachine/phpstan-strict-rules": "^0.10" - }, - "type": "library", - "autoload": { - "psr-4": { - "SlamCsFixer\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Filippo Tessarotto", - "email": "zoeslam@gmail.com", - "role": "Developer" - } - ], - "description": "Slam extension of friendsofphp/php-cs-fixer", - "time": "2019-01-07T15:02:12+00:00" + "time": "2019-10-24T14:27:39+00:00" }, { "name": "slevomat/coding-standard", @@ -3110,16 +2946,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.4.1", + "version": "3.5.4", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "5b4333b4010625d29580eb4a41f1e53251be6baa" + "reference": "dceec07328401de6211037abbb18bda423677e26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5b4333b4010625d29580eb4a41f1e53251be6baa", - "reference": "5b4333b4010625d29580eb4a41f1e53251be6baa", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26", + "reference": "dceec07328401de6211037abbb18bda423677e26", "shasum": "" }, "require": { @@ -3157,53 +2993,55 @@ "phpcs", "standards" ], - "time": "2019-03-19T03:22:27+00:00" + "time": "2020-01-30T22:20:29+00:00" }, { "name": "symfony/cache", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "b5c650406953f2f44a37c4f3ac66152fafc22c66" + "reference": "28511cbd8c760a19f4b4b70961d2cd957733b3d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/b5c650406953f2f44a37c4f3ac66152fafc22c66", - "reference": "b5c650406953f2f44a37c4f3ac66152fafc22c66", + "url": "https://api.github.com/repos/symfony/cache/zipball/28511cbd8c760a19f4b4b70961d2cd957733b3d9", + "reference": "28511cbd8c760a19f4b4b70961d2cd957733b3d9", "shasum": "" }, "require": { "php": "^7.1.3", "psr/cache": "~1.0", "psr/log": "~1.0", - "psr/simple-cache": "^1.0", - "symfony/contracts": "^1.0", - "symfony/var-exporter": "^4.2" + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" }, "conflict": { "doctrine/dbal": "<2.5", "symfony/dependency-injection": "<3.4", - "symfony/var-dumper": "<3.4" + "symfony/http-kernel": "<4.4", + "symfony/var-dumper": "<4.4" }, "provide": { "psr/cache-implementation": "1.0", "psr/simple-cache-implementation": "1.0", - "symfony/cache-contracts-implementation": "1.0" + "symfony/cache-implementation": "1.0" }, "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "~1.6", "doctrine/dbal": "~2.5", "predis/predis": "~1.1", - "symfony/config": "~4.2", - "symfony/dependency-injection": "~3.4|~4.1", - "symfony/var-dumper": "^4.1.1" + "psr/simple-cache": "^1.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/var-dumper": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3234,52 +3072,39 @@ "caching", "psr6" ], - "time": "2019-02-23T15:17:42+00:00" + "time": "2020-02-20T16:31:44+00:00" }, { - "name": "symfony/config", - "version": "v4.2.4", + "name": "symfony/cache-contracts", + "version": "v2.0.1", "source": { "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "7f70d79c7a24a94f8e98abb988049403a53d7b31" + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/7f70d79c7a24a94f8e98abb988049403a53d7b31", - "reference": "7f70d79c7a24a94f8e98abb988049403a53d7b31", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16", + "reference": "23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/filesystem": "~3.4|~4.0", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/finder": "<3.4" - }, - "require-dev": { - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~3.4|~4.0", - "symfony/finder": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "php": "^7.2.5", + "psr/cache": "^1.0" }, "suggest": { - "symfony/yaml": "To use the yaml reference dumper" + "symfony/cache-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "2.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\Cache\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3287,67 +3112,67 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Config Component", + "description": "Generic abstractions related to caching", "homepage": "https://symfony.com/", - "time": "2019-02-23T15:17:42+00:00" + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" }, { - "name": "symfony/console", - "version": "v4.2.4", + "name": "symfony/config", + "version": "v4.4.5", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "9dc2299a016497f9ee620be94524e6c0af0280a9" + "url": "https://github.com/symfony/config.git", + "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/9dc2299a016497f9ee620be94524e6c0af0280a9", - "reference": "9dc2299a016497f9ee620be94524e6c0af0280a9", + "url": "https://api.github.com/repos/symfony/config/zipball/cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", + "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0", - "symfony/polyfill-mbstring": "~1.0" + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/process": "<3.3" - }, - "provide": { - "psr/log-implementation": "1.0" + "symfony/finder": "<3.4" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~3.4|~4.0", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0" + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "symfony/yaml": "To use the yaml reference dumper" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Console\\": "" + "Symfony\\Component\\Config\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3367,50 +3192,66 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Console Component", + "description": "Symfony Config Component", "homepage": "https://symfony.com/", - "time": "2019-02-23T15:17:42+00:00" + "time": "2020-02-04T09:32:40+00:00" }, { - "name": "symfony/contracts", - "version": "v1.0.2", + "name": "symfony/console", + "version": "v4.4.5", "source": { "type": "git", - "url": "https://github.com/symfony/contracts.git", - "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf" + "url": "https://github.com/symfony/console.git", + "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf", - "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf", + "url": "https://api.github.com/repos/symfony/console/zipball/4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", + "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" }, "require-dev": { - "psr/cache": "^1.0", - "psr/container": "^1.0" + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" }, "suggest": { - "psr/cache": "When using the Cache contracts", - "psr/container": "When using the Service contracts", - "symfony/cache-contracts-implementation": "", - "symfony/service-contracts-implementation": "", - "symfony/translation-contracts-implementation": "" + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Contracts\\": "" + "Symfony\\Component\\Console\\": "" }, "exclude-from-classmap": [ - "**/Tests/" + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3419,38 +3260,30 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "A set of abstractions extracted out of the Symfony components", + "description": "Symfony Console Component", "homepage": "https://symfony.com/", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "time": "2018-12-05T08:06:11+00:00" + "time": "2020-02-24T13:10:00+00:00" }, { "name": "symfony/debug", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "de73f48977b8eaf7ce22814d66e43a1662cc864f" + "reference": "a980d87a659648980d89193fd8b7a7ca89d97d21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/de73f48977b8eaf7ce22814d66e43a1662cc864f", - "reference": "de73f48977b8eaf7ce22814d66e43a1662cc864f", + "url": "https://api.github.com/repos/symfony/debug/zipball/a980d87a659648980d89193fd8b7a7ca89d97d21", + "reference": "a980d87a659648980d89193fd8b7a7ca89d97d21", "shasum": "" }, "require": { @@ -3461,12 +3294,12 @@ "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~3.4|~4.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3493,41 +3326,41 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com/", - "time": "2019-03-03T18:11:24+00:00" + "time": "2020-02-23T14:41:43+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "cdadb3765df7c89ac93628743913b92bb91f1704" + "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/cdadb3765df7c89ac93628743913b92bb91f1704", - "reference": "cdadb3765df7c89ac93628743913b92bb91f1704", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ebb2e882e8c9e2eb990aa61ddcd389848466e342", + "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342", "shasum": "" }, "require": { "php": "^7.1.3", "psr/container": "^1.0", - "symfony/contracts": "^1.0" + "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<4.2", + "symfony/config": "<4.3|>=5.0", "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { "psr/container-implementation": "1.0", - "symfony/service-contracts-implementation": "1.0" + "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/config": "~4.2", - "symfony/expression-language": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/config": "", @@ -3539,7 +3372,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3566,49 +3399,41 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com/", - "time": "2019-02-23T15:17:42+00:00" + "time": "2020-02-29T09:50:10+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v4.2.4", + "name": "symfony/error-handler", + "version": "v4.4.5", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "3354d2e6af986dd71f68b4e5cf4a933ab58697fb" + "url": "https://github.com/symfony/error-handler.git", + "reference": "89aa4b9ac6f1f35171b8621b24f60477312085be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3354d2e6af986dd71f68b4e5cf4a933ab58697fb", - "reference": "3354d2e6af986dd71f68b4e5cf4a933ab58697fb", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/89aa4b9ac6f1f35171b8621b24f60477312085be", + "reference": "89aa4b9ac6f1f35171b8621b24f60477312085be", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0" - }, - "conflict": { - "symfony/dependency-injection": "<3.4" - }, - "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/stopwatch": "~3.4|~4.0" + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" + "Symfony\\Component\\ErrorHandler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3628,22 +3453,150 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Symfony ErrorHandler Component", "homepage": "https://symfony.com/", - "time": "2019-02-23T15:17:42+00:00" + "time": "2020-02-26T11:45:31+00:00" }, { - "name": "symfony/filesystem", - "version": "v4.2.4", + "name": "symfony/event-dispatcher", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4ad8e149799d3128621a3a1f70e92b9897a8930d", + "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com/", + "time": "2020-02-04T09:32:40+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com/", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T09:54:03+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "e16b9e471703b2c60b95f14d31c1239f68f11601" + "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/e16b9e471703b2c60b95f14d31c1239f68f11601", - "reference": "e16b9e471703b2c60b95f14d31c1239f68f11601", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/266c9540b475f26122b61ef8b23dd9198f5d1cfd", + "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd", "shasum": "" }, "require": { @@ -3653,7 +3606,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3680,20 +3633,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com/", - "time": "2019-02-07T11:40:08+00:00" + "time": "2020-01-21T08:20:44+00:00" }, { "name": "symfony/finder", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a" + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/267b7002c1b70ea80db0833c3afe05f0fbde580a", - "reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a", + "url": "https://api.github.com/repos/symfony/finder/zipball/ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357", "shasum": "" }, "require": { @@ -3702,7 +3655,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3729,34 +3682,35 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com/", - "time": "2019-02-23T15:42:05+00:00" + "time": "2020-02-14T07:42:58+00:00" }, { "name": "symfony/http-foundation", - "version": "v4.2.4", + "version": "v5.0.5", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "850a667d6254ccf6c61d853407b16f21c4579c77" + "reference": "6f9c2ba72f4295d7ce6cf9f79dbb18036291d335" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/850a667d6254ccf6c61d853407b16f21c4579c77", - "reference": "850a667d6254ccf6c61d853407b16f21c4579c77", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6f9c2ba72f4295d7ce6cf9f79dbb18036291d335", + "reference": "6f9c2ba72f4295d7ce6cf9f79dbb18036291d335", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": "^7.2.5", + "symfony/mime": "^4.4|^5.0", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { "predis/predis": "~1.0", - "symfony/expression-language": "~3.4|~4.0" + "symfony/expression-language": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -3783,36 +3737,37 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com/", - "time": "2019-02-26T08:03:39+00:00" + "time": "2020-02-14T07:43:07+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "895ceccaa8149f9343e6134e607c21da42d73b7a" + "reference": "8c8734486dada83a6041ab744709bdc1651a8462" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/895ceccaa8149f9343e6134e607c21da42d73b7a", - "reference": "895ceccaa8149f9343e6134e607c21da42d73b7a", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8c8734486dada83a6041ab744709bdc1651a8462", + "reference": "8c8734486dada83a6041ab744709bdc1651a8462", "shasum": "" }, "require": { "php": "^7.1.3", "psr/log": "~1.0", - "symfony/contracts": "^1.0.2", - "symfony/debug": "~3.4|~4.0", - "symfony/event-dispatcher": "~4.1", - "symfony/http-foundation": "^4.1.1", - "symfony/polyfill-ctype": "~1.8" + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9" }, "conflict": { + "symfony/browser-kit": "<4.3", "symfony/config": "<3.4", - "symfony/dependency-injection": "<4.2", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", - "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" }, "provide": { @@ -3820,32 +3775,32 @@ }, "require-dev": { "psr/cache": "~1.0", - "symfony/browser-kit": "~3.4|~4.0", - "symfony/config": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/css-selector": "~3.4|~4.0", - "symfony/dependency-injection": "^4.2", - "symfony/dom-crawler": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/finder": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~3.4|~4.0", - "symfony/templating": "~3.4|~4.0", - "symfony/translation": "~4.2", - "symfony/var-dumper": "^4.1.1" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/var-dumper": "" + "symfony/dependency-injection": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3872,20 +3827,82 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com/", - "time": "2019-03-03T19:38:09+00:00" + "time": "2020-02-29T10:31:38+00:00" + }, + { + "name": "symfony/mime", + "version": "v5.0.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/9b3e5b5e58c56bbd76628c952d2b78556d305f3c", + "reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A library to manipulate MIME messages", + "homepage": "https://symfony.com/", + "keywords": [ + "mime", + "mime-type" + ], + "time": "2020-02-04T09:41:09+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "3896e5a7d06fd15fa4947694c8dcdd371ff147d1" + "reference": "9a02d6662660fe7bfadad63b5f0b0718d4c8b6b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/3896e5a7d06fd15fa4947694c8dcdd371ff147d1", - "reference": "3896e5a7d06fd15fa4947694c8dcdd371ff147d1", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/9a02d6662660fe7bfadad63b5f0b0718d4c8b6b0", + "reference": "9a02d6662660fe7bfadad63b5f0b0718d4c8b6b0", "shasum": "" }, "require": { @@ -3894,7 +3911,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3926,20 +3943,20 @@ "configuration", "options" ], - "time": "2019-02-23T15:17:42+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.11.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "82ebae02209c21113908c229e9883c419720738a" + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", - "reference": "82ebae02209c21113908c229e9883c419720738a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", "shasum": "" }, "require": { @@ -3951,7 +3968,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.14-dev" } }, "autoload": { @@ -3967,13 +3984,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -3984,20 +4001,82 @@ "polyfill", "portable" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6842f1a39cf7d580655688069a03dd7cd83d244a", + "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2020-01-17T12:01:36+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.11.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609" + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2", + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2", "shasum": "" }, "require": { @@ -4009,7 +4088,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.14-dev" } }, "autoload": { @@ -4043,20 +4122,20 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-01-13T11:15:53+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.11.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "bc4858fb611bda58719124ca079baff854149c89" + "reference": "419c4940024c30ccc033650373a1fe13890d3255" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/bc4858fb611bda58719124ca079baff854149c89", - "reference": "bc4858fb611bda58719124ca079baff854149c89", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/419c4940024c30ccc033650373a1fe13890d3255", + "reference": "419c4940024c30ccc033650373a1fe13890d3255", "shasum": "" }, "require": { @@ -4066,7 +4145,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.14-dev" } }, "autoload": { @@ -4102,20 +4181,20 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-01-13T11:15:53+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.11.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c" + "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", + "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", "shasum": "" }, "require": { @@ -4124,7 +4203,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.14-dev" } }, "autoload": { @@ -4157,20 +4236,78 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-01-13T11:15:53+00:00" }, { "name": "symfony/process", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "6c05edb11fbeff9e2b324b4270ecb17911a8b7ad" + "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/6c05edb11fbeff9e2b324b4270ecb17911a8b7ad", - "reference": "6c05edb11fbeff9e2b324b4270ecb17911a8b7ad", + "url": "https://api.github.com/repos/symfony/process/zipball/bf9166bac906c9e69fb7a11d94875e7ced97bcd7", + "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7", "shasum": "" }, "require": { @@ -4179,7 +4316,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4206,30 +4343,88 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com/", - "time": "2019-01-24T22:05:03+00:00" + "time": "2020-02-07T20:06:44+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "144c5e51266b281231e947b51223ba14acf1a749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", + "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com/", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" }, { "name": "symfony/stopwatch", - "version": "v4.2.4", + "version": "v5.0.5", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "b1a5f646d56a3290230dbc8edf2a0d62cda23f67" + "reference": "5d9add8034135b9a5f7b101d1e42c797e7f053e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b1a5f646d56a3290230dbc8edf2a0d62cda23f67", - "reference": "b1a5f646d56a3290230dbc8edf2a0d62cda23f67", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5d9add8034135b9a5f7b101d1e42c797e7f053e4", + "reference": "5d9add8034135b9a5f7b101d1e42c797e7f053e4", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0" + "php": "^7.2.5", + "symfony/service-contracts": "^1.0|^2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -4256,58 +4451,56 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com/", - "time": "2019-01-16T20:31:39+00:00" + "time": "2020-01-04T14:08:26+00:00" }, { - "name": "symfony/translation", - "version": "v4.2.4", + "name": "symfony/var-dumper", + "version": "v5.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "748464177a77011f8f4cdd076773862ce4915f8f" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "3a37aeb1132d1035536d3d6aa9cb06c2ff9355e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/748464177a77011f8f4cdd076773862ce4915f8f", - "reference": "748464177a77011f8f4cdd076773862ce4915f8f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3a37aeb1132d1035536d3d6aa9cb06c2ff9355e9", + "reference": "3a37aeb1132d1035536d3d6aa9cb06c2ff9355e9", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0.2", + "php": "^7.2.5", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/config": "<3.4", - "symfony/dependency-injection": "<3.4", - "symfony/yaml": "<3.4" - }, - "provide": { - "symfony/translation-contracts-implementation": "1.0" + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/intl": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^2.4|^3.0" }, "suggest": { - "psr/log-implementation": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" }, + "bin": [ + "Resources/bin/var-dump-server" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.0-dev" } }, "autoload": { + "files": [ + "Resources/functions/dump.php" + ], "psr-4": { - "Symfony\\Component\\Translation\\": "" + "Symfony\\Component\\VarDumper\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4319,42 +4512,46 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Translation Component", + "description": "Symfony mechanism for exploring and dumping PHP variables", "homepage": "https://symfony.com/", - "time": "2019-02-27T03:31:50+00:00" + "keywords": [ + "debug", + "dump" + ], + "time": "2020-02-26T22:30:10+00:00" }, { "name": "symfony/var-exporter", - "version": "v4.2.4", + "version": "v5.0.5", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "d8bf4424c232b55f4c1816037d3077a89258557e" + "reference": "30779a25c736b4290449eaedefe4196c1d060378" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/d8bf4424c232b55f4c1816037d3077a89258557e", - "reference": "d8bf4424c232b55f4c1816037d3077a89258557e", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/30779a25c736b4290449eaedefe4196c1d060378", + "reference": "30779a25c736b4290449eaedefe4196c1d060378", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.2.5" }, "require-dev": { - "symfony/var-dumper": "^4.1.1" + "symfony/var-dumper": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -4389,20 +4586,20 @@ "instantiate", "serialize" ], - "time": "2019-01-16T20:35:37+00:00" + "time": "2020-02-04T09:47:34+00:00" }, { "name": "symfony/yaml", - "version": "v4.2.4", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "761fa560a937fd7686e5274ff89dcfa87a5047df" + "reference": "94d005c176db2080e98825d98e01e8b311a97a88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/761fa560a937fd7686e5274ff89dcfa87a5047df", - "reference": "761fa560a937fd7686e5274ff89dcfa87a5047df", + "url": "https://api.github.com/repos/symfony/yaml/zipball/94d005c176db2080e98825d98e01e8b311a97a88", + "reference": "94d005c176db2080e98825d98e01e8b311a97a88", "shasum": "" }, "require": { @@ -4413,7 +4610,7 @@ "symfony/console": "<3.4" }, "require-dev": { - "symfony/console": "~3.4|~4.0" + "symfony/console": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -4421,7 +4618,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4448,84 +4645,41 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com/", - "time": "2019-02-23T15:17:42+00:00" - }, - { - "name": "symplify/better-phpdoc-parser", - "version": "v5.4.16", - "source": { - "type": "git", - "url": "https://github.com/Symplify/BetterPhpDocParser.git", - "reference": "a730f69c4b19c741f13b4d05116da7bb64e3db26" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Symplify/BetterPhpDocParser/zipball/a730f69c4b19c741f13b4d05116da7bb64e3db26", - "reference": "a730f69c4b19c741f13b4d05116da7bb64e3db26", - "shasum": "" - }, - "require": { - "nette/utils": "^2.5", - "php": "^7.1", - "phpstan/phpdoc-parser": "^0.3.1", - "symplify/package-builder": "^5.4.16" - }, - "require-dev": { - "phpunit/phpunit": "^7.5|^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.5-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\BetterPhpDocParser\\": "src", - "Symplify\\BetterPhpDocParser\\Attributes\\": "packages/Attributes/src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Slim wrapper around phpstan/phpdoc-parser with format preserving printer", - "time": "2019-03-05T23:15:04+00:00" + "time": "2020-02-03T10:46:43+00:00" }, { "name": "symplify/coding-standard", - "version": "v5.4.16", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/Symplify/CodingStandard.git", - "reference": "72a3b03f21be6c978a90ad567a29bd9261df0dfa" + "reference": "d692701e2c74edd8c0cc7c35f47b8421b8b4885c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Symplify/CodingStandard/zipball/72a3b03f21be6c978a90ad567a29bd9261df0dfa", - "reference": "72a3b03f21be6c978a90ad567a29bd9261df0dfa", + "url": "https://api.github.com/repos/Symplify/CodingStandard/zipball/d692701e2c74edd8c0cc7c35f47b8421b8b4885c", + "reference": "d692701e2c74edd8c0cc7c35f47b8421b8b4885c", "shasum": "" }, "require": { - "friendsofphp/php-cs-fixer": "^2.14", + "friendsofphp/php-cs-fixer": "^2.15", "nette/finder": "^2.4", - "nette/utils": "^2.5", + "nette/utils": "^2.5|^3.0", "php": "^7.1", - "slam/php-cs-fixer-extensions": "^1.17", + "phpstan/phpdoc-parser": "^0.3.4", "squizlabs/php_codesniffer": "^3.4", - "symplify/better-phpdoc-parser": "^5.4.16", - "symplify/package-builder": "^5.4.16" + "symplify/package-builder": "^6.1" }, "require-dev": { - "nette/application": "^2.4", + "nette/application": "^3.0", "phpunit/phpunit": "^7.5|^8.0", - "symplify/easy-coding-standard-tester": "^5.4.16", - "symplify/package-builder": "^5.4.16" + "symplify/easy-coding-standard-tester": "^6.1", + "symplify/package-builder": "^6.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -4539,45 +4693,46 @@ "MIT" ], "description": "Set of Symplify rules for PHP_CodeSniffer and PHP CS Fixer.", - "time": "2019-03-05T23:15:04+00:00" + "time": "2019-09-18T08:01:34+00:00" }, { "name": "symplify/easy-coding-standard", - "version": "v5.4.16", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/Symplify/EasyCodingStandard.git", - "reference": "66ed360e0b81881336c7339989dce3b0c14509e9" + "reference": "94b8cf03af132d007d8a33c8dad5655cff6a74e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Symplify/EasyCodingStandard/zipball/66ed360e0b81881336c7339989dce3b0c14509e9", - "reference": "66ed360e0b81881336c7339989dce3b0c14509e9", + "url": "https://api.github.com/repos/Symplify/EasyCodingStandard/zipball/94b8cf03af132d007d8a33c8dad5655cff6a74e8", + "reference": "94b8cf03af132d007d8a33c8dad5655cff6a74e8", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.3", - "friendsofphp/php-cs-fixer": "^2.14", + "friendsofphp/php-cs-fixer": "^2.15", "jean85/pretty-package-versions": "^1.2", "nette/robot-loader": "^3.1.0", - "nette/utils": "^2.5", + "nette/utils": "^2.5|^3.0", "ocramius/package-versions": "^1.3", "php": "^7.1", + "psr/simple-cache": "^1.0", "slevomat/coding-standard": "^5.0.1", "squizlabs/php_codesniffer": "^3.4", - "symfony/cache": "^3.4|^4.1", - "symfony/config": "^3.4|^4.1", - "symfony/console": "^3.4|^4.1", - "symfony/dependency-injection": "^3.4|^4.1", - "symfony/finder": "^3.4|^4.1", - "symfony/http-kernel": "^3.4|^4.1", - "symfony/yaml": "^3.4|^4.1", - "symplify/coding-standard": "^5.4.16", - "symplify/package-builder": "^5.4.16" + "symfony/cache": "^3.4|^4.3", + "symfony/config": "^3.4|^4.3", + "symfony/console": "^3.4|^4.3", + "symfony/dependency-injection": "^3.4.10|^4.2", + "symfony/finder": "^3.4|^4.3", + "symfony/http-kernel": "^3.4|^4.3", + "symfony/yaml": "^3.4|^4.3", + "symplify/coding-standard": "^6.1", + "symplify/package-builder": "^6.1" }, "require-dev": { "phpunit/phpunit": "^7.5|^8.0", - "symplify/easy-coding-standard-tester": "^5.4.16" + "symplify/easy-coding-standard-tester": "^6.1" }, "bin": [ "bin/ecs" @@ -4585,7 +4740,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -4602,34 +4757,33 @@ "MIT" ], "description": "Use Coding Standard with 0-knowledge of PHP-CS-Fixer and PHP_CodeSniffer.", - "time": "2019-03-05T23:15:04+00:00" + "time": "2019-09-14T22:46:23+00:00" }, { "name": "symplify/package-builder", - "version": "v5.4.16", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/Symplify/PackageBuilder.git", - "reference": "20e04ad9cd15a53527807a62c8b244d8a114f779" + "reference": "fbdfe363a27070cfdfbc47d5f59e711ed08bb060" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Symplify/PackageBuilder/zipball/20e04ad9cd15a53527807a62c8b244d8a114f779", - "reference": "20e04ad9cd15a53527807a62c8b244d8a114f779", + "url": "https://api.github.com/repos/Symplify/PackageBuilder/zipball/fbdfe363a27070cfdfbc47d5f59e711ed08bb060", + "reference": "fbdfe363a27070cfdfbc47d5f59e711ed08bb060", "shasum": "" }, "require": { - "illuminate/support": "^5.7", "nette/finder": "^2.4", - "nette/utils": "^2.5", + "nette/utils": "^2.5|^3.0", "php": "^7.1", - "symfony/config": "^3.4|^4.1", - "symfony/console": "^3.4|^4.1", - "symfony/debug": "^3.4|^4.1", - "symfony/dependency-injection": "^3.4|^4.1", - "symfony/finder": "^3.4|^4.1", - "symfony/http-kernel": "^3.4|^4.1", - "symfony/yaml": "^3.4|^4.1" + "symfony/config": "^3.4|^4.3", + "symfony/console": "^3.4|^4.3", + "symfony/debug": "^3.4|^4.3", + "symfony/dependency-injection": "^3.4.10|^4.2", + "symfony/finder": "^3.4|^4.3", + "symfony/http-kernel": "^3.4|^4.3", + "symfony/yaml": "^3.4|^4.3" }, "require-dev": { "phpunit/phpunit": "^7.5|^8.0" @@ -4637,7 +4791,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -4650,20 +4804,20 @@ "MIT" ], "description": "Dependency Injection, Console and Kernel toolkit for Symplify packages.", - "time": "2019-03-03T15:32:34+00:00" + "time": "2019-09-17T20:48:03+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -4690,36 +4844,33 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", - "version": "1.4.0", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -4741,7 +4892,53 @@ "check", "validate" ], - "time": "2018-12-25T11:19:39+00:00" + "time": "2020-02-14T12:15:55+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "time": "2015-12-17T08:42:14+00:00" } ], "aliases": [], diff --git a/docs/index.md b/docs/index.md index 8ce2751b..bff00f2d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -44,7 +44,7 @@ To find out how to use PHP-ML follow [Documentation](http://php-ml.readthedocs.o ## Installation -Currently this library is in the process of developing, but You can install it with Composer: +This library is still in beta. However, it can be installed with Composer: ``` composer require php-ai/php-ml @@ -56,7 +56,7 @@ Example scripts are available in a separate repository [php-ai/php-ml-examples]( ## Features -* Association rule Lerning +* Association rule Learning * [Apriori](machine-learning/association/apriori.md) * Classification * [SVC](machine-learning/classification/svc.md) @@ -108,18 +108,5 @@ Example scripts are available in a separate repository [php-ai/php-ml-examples]( * [Statistic](math/statistic.md) -## Contribute - -- Guide: [CONTRIBUTING.md](https://github.com/php-ai/php-ml/blob/master/CONTRIBUTING.md) -- Issue Tracker: [github.com/php-ai/php-ml/issues](https://github.com/php-ai/php-ml/issues) -- Source Code: [github.com/php-ai/php-ml](https://github.com/php-ai/php-ml) - -You can find more about contributing in [CONTRIBUTING.md](../CONTRIBUTING.md). - -## License - -PHP-ML is released under the MIT Licence. See the bundled LICENSE file for details. - -## Author - +## Arkadiusz Kondas (@ArkadiuszKondas) diff --git a/docs/machine-learning/association/apriori.md b/docs/machine-learning/association/apriori.md index bbf829ba..779ef289 100644 --- a/docs/machine-learning/association/apriori.md +++ b/docs/machine-learning/association/apriori.md @@ -15,7 +15,7 @@ $associator = new Apriori($support = 0.5, $confidence = 0.5); ### Train -To train a associator simply provide train samples and labels (as `array`). Example: +To train an associator, simply provide train samples and labels (as `array`). Example: ``` $samples = [['alpha', 'beta', 'epsilon'], ['alpha', 'beta', 'theta'], ['alpha', 'beta', 'epsilon'], ['alpha', 'beta', 'theta']]; @@ -31,7 +31,7 @@ You can train the associator using multiple data sets, predictions will be based ### Predict -To predict sample label use `predict` method. You can provide one sample or array of samples: +To predict sample label use the `predict` method. You can provide one sample or array of samples: ``` $associator->predict(['alpha','theta']); @@ -43,7 +43,7 @@ $associator->predict([['alpha','epsilon'],['beta','theta']]); ### Associating -Get generated association rules simply use `rules` method. +To get generated association rules, simply use the `rules` method. ``` $associator->getRules(); @@ -52,7 +52,7 @@ $associator->getRules(); ### Frequent item sets -Generating k-length frequent item sets simply use `apriori` method. +To generate k-length frequent item sets, simply use the `apriori` method. ``` $associator->apriori(); diff --git a/docs/machine-learning/classification/k-nearest-neighbors.md b/docs/machine-learning/classification/k-nearest-neighbors.md index a4eb96ca..a4ba53b0 100644 --- a/docs/machine-learning/classification/k-nearest-neighbors.md +++ b/docs/machine-learning/classification/k-nearest-neighbors.md @@ -14,7 +14,7 @@ $classifier = new KNearestNeighbors($k=3, new Minkowski($lambda=4)); ## Train -To train a classifier simply provide train samples and labels (as `array`). Example: +To train a classifier, simply provide train samples and labels (as `array`). Example: ``` $samples = [[1, 3], [1, 4], [2, 4], [3, 1], [4, 1], [4, 2]]; @@ -28,7 +28,7 @@ You can train the classifier using multiple data sets, predictions will be based ## Predict -To predict sample label use `predict` method. You can provide one sample or array of samples: +To predict sample label use the `predict` method. You can provide one sample or array of samples: ``` $classifier->predict([3, 2]); diff --git a/docs/machine-learning/classification/naive-bayes.md b/docs/machine-learning/classification/naive-bayes.md index af3b3577..57fcdcf6 100644 --- a/docs/machine-learning/classification/naive-bayes.md +++ b/docs/machine-learning/classification/naive-bayes.md @@ -4,7 +4,7 @@ Classifier based on applying Bayes' theorem with strong (naive) independence ass ### Train -To train a classifier simply provide train samples and labels (as `array`). Example: +To train a classifier, simply provide train samples and labels (as `array`). Example: ``` $samples = [[5, 1, 1], [1, 5, 1], [1, 1, 5]]; @@ -18,7 +18,7 @@ You can train the classifier using multiple data sets, predictions will be based ### Predict -To predict sample label use `predict` method. You can provide one sample or array of samples: +To predict sample label use the `predict` method. You can provide one sample or array of samples: ``` $classifier->predict([3, 1, 1]); diff --git a/docs/machine-learning/classification/svc.md b/docs/machine-learning/classification/svc.md index 99b4da01..3d87b62c 100644 --- a/docs/machine-learning/classification/svc.md +++ b/docs/machine-learning/classification/svc.md @@ -21,7 +21,7 @@ $classifier = new SVC(Kernel::RBF, $cost = 1000, $degree = 3, $gamma = 6); ### Train -To train a classifier simply provide train samples and labels (as `array`). Example: +To train a classifier, simply provide train samples and labels (as `array`). Example: ``` use Phpml\Classification\SVC; @@ -38,7 +38,7 @@ You can train the classifier using multiple data sets, predictions will be based ### Predict -To predict sample label use `predict` method. You can provide one sample or array of samples: +To predict sample label use the `predict` method. You can provide one sample or array of samples: ``` $classifier->predict([3, 2]); @@ -74,7 +74,7 @@ $classifier = new SVC( $classifier->train($samples, $labels); ``` -Then use `predictProbability` method instead of `predict`: +Then use the `predictProbability` method instead of `predict`: ``` $classifier->predictProbability([3, 2]); diff --git a/docs/machine-learning/clustering/dbscan.md b/docs/machine-learning/clustering/dbscan.md index c82a195e..ce011986 100644 --- a/docs/machine-learning/clustering/dbscan.md +++ b/docs/machine-learning/clustering/dbscan.md @@ -16,12 +16,12 @@ $dbscan = new DBSCAN($epsilon = 2, $minSamples = 3, new Minkowski($lambda=4)); ### Clustering -To divide the samples into clusters simply use `cluster` method. It's return the `array` of clusters with samples inside. +To divide the samples into clusters, simply use the `cluster` method. It returns the `array` of clusters with samples inside. ``` $samples = [[1, 1], [8, 7], [1, 2], [7, 8], [2, 1], [8, 9]]; $dbscan = new DBSCAN($epsilon = 2, $minSamples = 3); $dbscan->cluster($samples); -// return [0=>[[1, 1], ...], 1=>[[8, 7], ...]] +// return [0=>[[1, 1], ...], 1=>[[8, 7], ...]] ``` diff --git a/docs/machine-learning/clustering/k-means.md b/docs/machine-learning/clustering/k-means.md index 661f7172..132c2dc6 100644 --- a/docs/machine-learning/clustering/k-means.md +++ b/docs/machine-learning/clustering/k-means.md @@ -1,6 +1,6 @@ # K-means clustering -The K-Means algorithm clusters data by trying to separate samples in n groups of equal variance, minimizing a criterion known as the inertia or within-cluster sum-of-squares. +The K-Means algorithm clusters data by trying to separate samples in n groups of equal variance, minimizing a criterion known as the inertia or within-cluster sum-of-squares. This algorithm requires the number of clusters to be specified. ### Constructor Parameters @@ -15,11 +15,11 @@ $kmeans = new KMeans(4, KMeans::INIT_RANDOM); ### Clustering -To divide the samples into clusters simply use `cluster` method. It's return the `array` of clusters with samples inside. +To divide the samples into clusters, simply use the `cluster` method. It returns the `array` of clusters with samples inside. ``` $samples = [[1, 1], [8, 7], [1, 2], [7, 8], [2, 1], [8, 9]]; -Or if you need to keep your indentifiers along with yours samples you can use array keys as labels. +Or if you need to keep your identifiers along with yours samples you can use array keys as labels. $samples = [ 'Label1' => [1, 1], 'Label2' => [8, 7], 'Label3' => [1, 2]]; $kmeans = new KMeans(2); @@ -32,8 +32,8 @@ $kmeans->cluster($samples); #### kmeans++ (default) K-means++ method selects initial cluster centers for k-mean clustering in a smart way to speed up convergence. -It use the DASV seeding method consists of finding good initial centroids for the clusters. +It uses the DASV seeding method consists of finding good initial centroids for the clusters. #### random -Random initialization method chooses completely random centroid. It get the space boundaries to avoid placing clusters centroid too far from samples data. +Random initialization method chooses completely random centroid. It gets the space boundaries to avoid placing cluster centroids too far from samples data. diff --git a/docs/machine-learning/cross-validation/random-split.md b/docs/machine-learning/cross-validation/random-split.md index edfdded5..a5bf4022 100644 --- a/docs/machine-learning/cross-validation/random-split.md +++ b/docs/machine-learning/cross-validation/random-split.md @@ -1,20 +1,20 @@ # Random Split -One of the simplest methods from Cross-validation is implemented as `RandomSpilt` class. Samples are split to two groups: train group and test group. You can adjust number of samples in each group. +One of the simplest methods from Cross-validation is implemented as `RandomSpilt` class. Samples are split to two groups: train group and test group. You can adjust the number of samples in each group. ### Constructor Parameters * $dataset - object that implements `Dataset` interface * $testSize - a fraction of test split (float, from 0 to 1, default: 0.3) * $seed - seed for random generator (e.g. for tests) - + ``` $randomSplit = new RandomSplit($dataset, 0.2); ``` ### Samples and labels groups -To get samples or labels from test and train group you can use getters: +To get samples or labels from test and train group, you can use getters: ``` $dataset = new RandomSplit($dataset, 0.3, 1234); diff --git a/docs/machine-learning/cross-validation/stratified-random-split.md b/docs/machine-learning/cross-validation/stratified-random-split.md index d3f53be0..1a6caa19 100644 --- a/docs/machine-learning/cross-validation/stratified-random-split.md +++ b/docs/machine-learning/cross-validation/stratified-random-split.md @@ -1,22 +1,22 @@ # Stratified Random Split -Analogously to `RandomSpilt` class samples are split to two groups: train group and test group. +Analogously to `RandomSpilt` class, samples are split to two groups: train group and test group. Distribution of samples takes into account their targets and trying to divide them equally. -You can adjust number of samples in each group. +You can adjust the number of samples in each group. ### Constructor Parameters * $dataset - object that implements `Dataset` interface * $testSize - a fraction of test split (float, from 0 to 1, default: 0.3) * $seed - seed for random generator (e.g. for tests) - + ``` $split = new StratifiedRandomSplit($dataset, 0.2); ``` ### Samples and labels groups -To get samples or labels from test and train group you can use getters: +To get samples or labels from test and train group, you can use getters: ``` $dataset = new StratifiedRandomSplit($dataset, 0.3, 1234); @@ -41,4 +41,4 @@ $dataset = new ArrayDataset( $split = new StratifiedRandomSplit($dataset, 0.5); ``` -Split will have equals amount of each target. Two of the target `a` and two of `b`. +Split will have equal amounts of each target. Two of the target `a` and two of `b`. diff --git a/docs/machine-learning/datasets/array-dataset.md b/docs/machine-learning/datasets/array-dataset.md index 8bbcc37a..87bae48c 100644 --- a/docs/machine-learning/datasets/array-dataset.md +++ b/docs/machine-learning/datasets/array-dataset.md @@ -2,7 +2,7 @@ Helper class that holds data as PHP `array` type. Implements the `Dataset` interface which is used heavily in other classes. -### Constructors Parameters +### Constructor Parameters * $samples - (array) of samples * $labels - (array) of labels @@ -15,7 +15,7 @@ $dataset = new ArrayDataset([[1, 1], [2, 1], [3, 2], [4, 1]], ['a', 'a', 'b', 'b ### Samples and labels -To get samples or labels you can use getters: +To get samples or labels, you can use getters: ``` $dataset->getSamples(); @@ -24,7 +24,7 @@ $dataset->getTargets(); ### Remove columns -You can remove columns by index numbers, for example: +You can remove columns by their index numbers, for example: ``` use Phpml\Dataset\ArrayDataset; diff --git a/docs/machine-learning/datasets/csv-dataset.md b/docs/machine-learning/datasets/csv-dataset.md index d2efaaaf..557b7fce 100644 --- a/docs/machine-learning/datasets/csv-dataset.md +++ b/docs/machine-learning/datasets/csv-dataset.md @@ -2,11 +2,11 @@ Helper class that loads data from CSV file. It extends the `ArrayDataset`. -### Constructors Parameters +### Constructor Parameters * $filepath - (string) path to `.csv` file * $features - (int) number of columns that are features (starts from first column), last column must be a label -* $headingRow - (bool) define is file have a heading row (if `true` then first row will be ignored) +* $headingRow - (bool) define if the file has a heading row (if `true` then first row will be ignored) ``` $dataset = new CsvDataset('dataset.csv', 2, true); diff --git a/docs/machine-learning/datasets/files-dataset.md b/docs/machine-learning/datasets/files-dataset.md index f050cfda..6d55b3f5 100644 --- a/docs/machine-learning/datasets/files-dataset.md +++ b/docs/machine-learning/datasets/files-dataset.md @@ -2,7 +2,7 @@ Helper class that loads dataset from files. Use folder names as targets. It extends the `ArrayDataset`. -### Constructors Parameters +### Constructor Parameters * $rootPath - (string) path to root folder that contains files dataset @@ -42,7 +42,7 @@ data ... ``` -Load files data with `FilesDataset`: +Load files data with `FilesDataset`: ``` use Phpml\Dataset\FilesDataset; diff --git a/docs/machine-learning/datasets/mnist-dataset.md b/docs/machine-learning/datasets/mnist-dataset.md index 1ed50816..5c7a76e4 100644 --- a/docs/machine-learning/datasets/mnist-dataset.md +++ b/docs/machine-learning/datasets/mnist-dataset.md @@ -1,6 +1,6 @@ # MnistDataset -Helper class that load data from MNIST dataset: [http://yann.lecun.com/exdb/mnist/](http://yann.lecun.com/exdb/mnist/) +Helper class that loads data from MNIST dataset: [http://yann.lecun.com/exdb/mnist/](http://yann.lecun.com/exdb/mnist/) > The MNIST database of handwritten digits, available from this page, has a training set of 60,000 examples, and a test set of 10,000 examples. It is a subset of a larger set available from NIST. The digits have been size-normalized and centered in a fixed-size image. It is a good database for people who want to try learning techniques and pattern recognition methods on real-world data while spending minimal efforts on preprocessing and formatting. @@ -18,7 +18,7 @@ $trainDataset = new MnistDataset('train-images-idx3-ubyte', 'train-labels-idx1-u ### Samples and labels -To get samples or labels you can use getters: +To get samples or labels, you can use getters: ``` $dataset->getSamples(); diff --git a/docs/machine-learning/datasets/svm-dataset.md b/docs/machine-learning/datasets/svm-dataset.md index 8ac1c268..93a8cfb4 100644 --- a/docs/machine-learning/datasets/svm-dataset.md +++ b/docs/machine-learning/datasets/svm-dataset.md @@ -2,7 +2,7 @@ Helper class that loads data from SVM-Light format file. It extends the `ArrayDataset`. -### Constructors Parameters +### Constructor Parameters * $filepath - (string) path to the file diff --git a/docs/machine-learning/feature-extraction/tf-idf-transformer.md b/docs/machine-learning/feature-extraction/tf-idf-transformer.md index c592b8d6..4ac2e5dd 100644 --- a/docs/machine-learning/feature-extraction/tf-idf-transformer.md +++ b/docs/machine-learning/feature-extraction/tf-idf-transformer.md @@ -19,7 +19,7 @@ $transformer = new TfIdfTransformer($samples); ### Transformation -To transform a collection of text samples use `transform` method. Example: +To transform a collection of text samples, use the `transform` method. Example: ``` use Phpml\FeatureExtraction\TfIdfTransformer; @@ -28,7 +28,7 @@ $samples = [ [0 => 1, 1 => 1, 2 => 2, 3 => 1, 4 => 0, 5 => 0], [0 => 1, 1 => 1, 2 => 0, 3 => 0, 4 => 2, 5 => 3], ]; - + $transformer = new TfIdfTransformer($samples); $transformer->transform($samples); @@ -38,5 +38,5 @@ $samples = [ [0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0.602, 5 => 0.903], ]; */ - + ``` diff --git a/docs/machine-learning/feature-extraction/token-count-vectorizer.md b/docs/machine-learning/feature-extraction/token-count-vectorizer.md index 4dc52604..7d9405ef 100644 --- a/docs/machine-learning/feature-extraction/token-count-vectorizer.md +++ b/docs/machine-learning/feature-extraction/token-count-vectorizer.md @@ -16,7 +16,7 @@ $vectorizer = new TokenCountVectorizer(new WhitespaceTokenizer()); ### Transformation -To transform a collection of text samples use `transform` method. Example: +To transform a collection of text samples, use the `transform` method. Example: ``` $samples = [ @@ -42,7 +42,7 @@ $vectorizer->transform($samples); ### Vocabulary -You can extract vocabulary using `getVocabulary()` method. Example: +You can extract vocabulary using the `getVocabulary()` method. Example: ``` $vectorizer->getVocabulary(); diff --git a/docs/machine-learning/feature-selection/selectkbest.md b/docs/machine-learning/feature-selection/selectkbest.md index 2d8024cd..71d1ff92 100644 --- a/docs/machine-learning/feature-selection/selectkbest.md +++ b/docs/machine-learning/feature-selection/selectkbest.md @@ -5,7 +5,7 @@ ## Constructor Parameters * $k (int) - number of top features to select, rest will be removed (default: 10) -* $scoringFunction (ScoringFunction) - function that take samples and targets and return array with scores (default: ANOVAFValue) +* $scoringFunction (ScoringFunction) - function that takes samples and targets and returns an array with scores (default: ANOVAFValue) ```php use Phpml\FeatureSelection\SelectKBest; @@ -27,13 +27,13 @@ $selector->fit($samples = $dataset->getSamples(), $dataset->getTargets()); $selector->transform($samples); /* -$samples[0] = [1.4, 0.2]; +$samples[0] = [1.4, 0.2]; */ ``` ## Scores -You can get a array with the calculated score for each feature. +You can get an array with the calculated score for each feature. A higher value means that a given feature is better suited for learning. Of course, the rating depends on the scoring function used. @@ -56,7 +56,7 @@ $selector->scores(); float(1179.0343277002) [3]=> float(959.32440572573) -} +} */ ``` @@ -70,11 +70,11 @@ For classification: The test is applied to samples from two or more groups, possibly with differing sizes. For regression: - - **UnivariateLinearRegression** + - **UnivariateLinearRegression** Quick linear model for testing the effect of a single regressor, sequentially for many regressors. This is done in 2 steps: - 1. The cross correlation between each regressor and the target is computed, that is, ((X[:, i] - mean(X[:, i])) * (y - mean_y)) / (std(X[:, i]) *std(y)). - - 2. It is converted to an F score + - 2. It is converted to an F score ## Pipeline diff --git a/docs/machine-learning/feature-selection/variance-threshold.md b/docs/machine-learning/feature-selection/variance-threshold.md index 9c942e79..40218951 100644 --- a/docs/machine-learning/feature-selection/variance-threshold.md +++ b/docs/machine-learning/feature-selection/variance-threshold.md @@ -1,7 +1,7 @@ # Variance Threshold -`VarianceThreshold` is a simple baseline approach to feature selection. -It removes all features whose variance doesn’t meet some threshold. +`VarianceThreshold` is a simple baseline approach to feature selection. +It removes all features whose variance doesn’t meet some threshold. By default, it removes all zero-variance features, i.e. features that have the same value in all samples. ## Constructor Parameters @@ -16,10 +16,10 @@ $transformer = new VarianceThreshold(0.15); ## Example of use -As an example, suppose that we have a dataset with boolean features and +As an example, suppose that we have a dataset with boolean features and we want to remove all features that are either one or zero (on or off) -in more than 80% of the samples. -Boolean features are Bernoulli random variables, and the variance of such +in more than 80% of the samples. +Boolean features are Bernoulli random variables, and the variance of such variables is given by ``` Var[X] = p(1 - p) diff --git a/docs/machine-learning/metric/accuracy.md b/docs/machine-learning/metric/accuracy.md index 50459737..efdab23a 100644 --- a/docs/machine-learning/metric/accuracy.md +++ b/docs/machine-learning/metric/accuracy.md @@ -1,10 +1,10 @@ # Accuracy -Class for calculate classifier accuracy. +Class for calculating classifier accuracy. ### Score -To calculate classifier accuracy score use `score` static method. Parameters: +To calculate classifier accuracy score, use the `score` static method. Parameters: * $actualLabels - (array) true sample labels * $predictedLabels - (array) predicted labels (e.x. from test group) diff --git a/docs/machine-learning/metric/classification-report.md b/docs/machine-learning/metric/classification-report.md index 53f125b8..f5591a83 100644 --- a/docs/machine-learning/metric/classification-report.md +++ b/docs/machine-learning/metric/classification-report.md @@ -1,6 +1,6 @@ # Classification Report -Class for calculate main classifier metrics: precision, recall, F1 score and support. +Class for calculating main classifier metrics: precision, recall, F1 score and support. ### Report diff --git a/docs/machine-learning/metric/confusion-matrix.md b/docs/machine-learning/metric/confusion-matrix.md index b07443ac..4ff08c9c 100644 --- a/docs/machine-learning/metric/confusion-matrix.md +++ b/docs/machine-learning/metric/confusion-matrix.md @@ -1,6 +1,6 @@ # Confusion Matrix -Class for compute confusion matrix to evaluate the accuracy of a classification. +Class for computing confusion matrix to evaluate the accuracy of a classification. ### Example (all targets) diff --git a/docs/machine-learning/neural-network/multilayer-perceptron-classifier.md b/docs/machine-learning/neural-network/multilayer-perceptron-classifier.md index 7365a715..976d475f 100644 --- a/docs/machine-learning/neural-network/multilayer-perceptron-classifier.md +++ b/docs/machine-learning/neural-network/multilayer-perceptron-classifier.md @@ -39,8 +39,7 @@ $mlp = new MLPClassifier(4, [$layer1, $layer2], ['a', 'b', 'c']); ## Train -To train a MLP simply provide train samples and labels (as array). Example: - +To train a MLP, simply provide train samples and labels (as array). Example: ``` $mlp->train( @@ -71,7 +70,7 @@ $mlp->setLearningRate(0.1); ## Predict -To predict sample label use predict method. You can provide one sample or array of samples: +To predict sample label use the `predict` method. You can provide one sample or array of samples: ``` $mlp->predict([[1, 1, 1, 1], [0, 0, 0, 0]]); diff --git a/docs/machine-learning/preprocessing/imputation-missing-values.md b/docs/machine-learning/preprocessing/imputation-missing-values.md index 219db22c..302d89d8 100644 --- a/docs/machine-learning/preprocessing/imputation-missing-values.md +++ b/docs/machine-learning/preprocessing/imputation-missing-values.md @@ -49,7 +49,7 @@ $data = [ ``` -You can also use `$samples` constructer parameter instead of `fit` method: +You can also use the `$samples` constructor parameter instead of the `fit` method: ``` use Phpml\Preprocessing\Imputer; diff --git a/docs/machine-learning/regression/least-squares.md b/docs/machine-learning/regression/least-squares.md index 84a32791..5505f13e 100644 --- a/docs/machine-learning/regression/least-squares.md +++ b/docs/machine-learning/regression/least-squares.md @@ -1,10 +1,10 @@ # LeastSquares Linear Regression -Linear model that use least squares method to approximate solution. +Linear model that uses least squares method to approximate solution. ### Train -To train a model simply provide train samples and targets values (as `array`). Example: +To train a model, simply provide train samples and targets values (as `array`). Example: ``` $samples = [[60], [61], [62], [63], [65]]; @@ -18,7 +18,7 @@ You can train the model using multiple data sets, predictions will be based on a ### Predict -To predict sample target value use `predict` method with sample to check (as `array`). Example: +To predict sample target value, use the `predict` method with sample to check (as `array`). Example: ``` $regression->predict([64]); @@ -27,8 +27,8 @@ $regression->predict([64]); ### Multiple Linear Regression -The term multiple attached to linear regression means that there are two or more sample parameters used to predict target. -For example you can use: mileage and production year to predict price of a car. +The term multiple attached to linear regression means that there are two or more sample parameters used to predict target. +For example you can use: mileage and production year to predict the price of a car. ``` $samples = [[73676, 1996], [77006, 1998], [10565, 2000], [146088, 1995], [15000, 2001], [65940, 2000], [9300, 2000], [93739, 1996], [153260, 1994], [17764, 2002], [57000, 1998], [15000, 2000]]; @@ -42,7 +42,7 @@ $regression->predict([60000, 1996]) ### Intercept and Coefficients -After you train your model you can get the intercept and coefficients array. +After you train your model, you can get the intercept and coefficients array. ``` $regression->getIntercept(); diff --git a/docs/machine-learning/regression/svr.md b/docs/machine-learning/regression/svr.md index 1678f5fc..14f9e6ab 100644 --- a/docs/machine-learning/regression/svr.md +++ b/docs/machine-learning/regression/svr.md @@ -21,7 +21,7 @@ $regression = new SVR(Kernel::LINEAR, $degree = 3, $epsilon=10.0); ### Train -To train a model simply provide train samples and targets values (as `array`). Example: +To train a model, simply provide train samples and targets values (as `array`). Example: ``` use Phpml\Regression\SVR; @@ -38,7 +38,7 @@ You can train the model using multiple data sets, predictions will be based on a ### Predict -To predict sample target value use `predict` method. You can provide one sample or array of samples: +To predict sample target value, use the `predict` method. You can provide one sample or array of samples: ``` $regression->predict([64]) diff --git a/docs/machine-learning/workflow/pipeline.md b/docs/machine-learning/workflow/pipeline.md index 34465eb5..b89b88ed 100644 --- a/docs/machine-learning/workflow/pipeline.md +++ b/docs/machine-learning/workflow/pipeline.md @@ -5,13 +5,12 @@ In machine learning, it is common to run a sequence of algorithms to process and * Split each document’s text into tokens. * Convert each document’s words into a numerical feature vector ([Token Count Vectorizer](machine-learning/feature-extraction/token-count-vectorizer/)). * Learn a prediction model using the feature vectors and labels. - -PHP-ML represents such a workflow as a Pipeline, which consists sequence of transformers and a estimator. +PHP-ML represents such a workflow as a Pipeline, which consists of a sequence of transformers and an estimator. ### Constructor Parameters -* $transformers (array|Transformer[]) - sequence of objects that implements Transformer interface +* $transformers (array|Transformer[]) - sequence of objects that implements the Transformer interface * $estimator (Estimator) - estimator that can train and predict ``` @@ -29,7 +28,8 @@ $pipeline = new Pipeline($transformers, $estimator); ### Example -First our pipeline replace missing value, then normalize samples and finally train SVC estimator. Thus prepared pipeline repeats each transformation step for predicted sample. +First, our pipeline replaces the missing value, then normalizes samples and finally trains the SVC estimator. +Thus prepared pipeline repeats each transformation step for predicted sample. ``` use Phpml\Classification\SVC; diff --git a/docs/math/distance.md b/docs/math/distance.md index 69707425..c7c3a989 100644 --- a/docs/math/distance.md +++ b/docs/math/distance.md @@ -4,7 +4,7 @@ Selected algorithms require the use of a function for calculating the distance. ### Euclidean -Class for calculation Euclidean distance. +Class for calculating Euclidean distance. ![euclidean](https://upload.wikimedia.org/math/8/4/9/849f040fd10bb86f7c85eb0bbe3566a4.png "Euclidean Distance") @@ -13,7 +13,7 @@ To calculate Euclidean distance: ``` $a = [4, 6]; $b = [2, 5]; - + $euclidean = new Euclidean(); $euclidean->distance($a, $b); // return 2.2360679774998 @@ -21,7 +21,7 @@ $euclidean->distance($a, $b); ### Manhattan -Class for calculation Manhattan distance. +Class for calculating Manhattan distance. ![manhattan](https://upload.wikimedia.org/math/4/c/5/4c568bd1d76a6b15e19cb2ac3ad75350.png "Manhattan Distance") @@ -30,7 +30,7 @@ To calculate Manhattan distance: ``` $a = [4, 6]; $b = [2, 5]; - + $manhattan = new Manhattan(); $manhattan->distance($a, $b); // return 3 @@ -38,7 +38,7 @@ $manhattan->distance($a, $b); ### Chebyshev -Class for calculation Chebyshev distance. +Class for calculating Chebyshev distance. ![chebyshev](https://upload.wikimedia.org/math/7/1/2/71200f7dbb43b3bcfbcbdb9e02ab0a0c.png "Chebyshev Distance") @@ -47,7 +47,7 @@ To calculate Chebyshev distance: ``` $a = [4, 6]; $b = [2, 5]; - + $chebyshev = new Chebyshev(); $chebyshev->distance($a, $b); // return 2 @@ -55,7 +55,7 @@ $chebyshev->distance($a, $b); ### Minkowski -Class for calculation Minkowski distance. +Class for calculating Minkowski distance. ![minkowski](https://upload.wikimedia.org/math/a/a/0/aa0c62083c12390cb15ac3217de88e66.png "Minkowski Distance") @@ -64,7 +64,7 @@ To calculate Minkowski distance: ``` $a = [4, 6]; $b = [2, 5]; - + $minkowski = new Minkowski(); $minkowski->distance($a, $b); // return 2.080 @@ -83,7 +83,7 @@ $minkowski->distance($a, $b); ### Custom distance -To apply your own function of distance use `Distance` interface. Example +To apply your own function of distance use the `Distance` interface. Example: ``` class CustomDistance implements Distance @@ -103,7 +103,7 @@ class CustomDistance implements Distance $distance[] = $a[$i] * $b[$i]; } - return min($distance); + return min($distance); } } ``` diff --git a/docs/math/statistic.md b/docs/math/statistic.md deleted file mode 100644 index 626828e9..00000000 --- a/docs/math/statistic.md +++ /dev/null @@ -1,80 +0,0 @@ -# Statistic - -Selected statistical methods. - -## Correlation - -Correlation coefficients are used in statistics to measure how strong a relationship is between two variables. There are several types of correlation coefficient. - -### Pearson correlation - -Pearson’s correlation or Pearson correlation is a correlation coefficient commonly used in linear regression. - -Example: - -``` -use Phpml\Math\Statistic\Correlation; - -$x = [43, 21, 25, 42, 57, 59]; -$y = [99, 65, 79, 75, 87, 82]; - -Correlation::pearson($x, $y); -// return 0.549 -``` - -## Mean - -### Arithmetic - -Example: - -``` -use Phpml\Math\Statistic\Mean; - -Mean::arithmetic([2, 5]; -// return 3.5 - -Mean::arithmetic([0.5, 0.5, 1.5, 2.5, 3.5]; -// return 1.7 -``` - -## Median - -Example: - -``` -use Phpml\Math\Statistic\Mean; - -Mean::median([5, 2, 6, 1, 3, 4]); -// return 3.5 - -Mean::median([5, 2, 6, 1, 3]); -// return 3 -``` - -## Mode - -Example: - -``` -use Phpml\Math\Statistic\Mean; - -Mean::mode([5, 2, 6, 1, 3, 4, 6, 6, 5]); -// return 6 -``` - -## Standard Deviation - -Example: - -``` -use Phpml\Math\Statistic\StandardDeviation; - -$population = [5, 6, 8, 9]; -StandardDeviation::population($population) -// return 1.825 - -$population = [7100, 15500, 4400, 4400, 5900, 4600, 8800, 2000, 2750, 2550, 960, 1025]; -StandardDeviation::population($population) -// return 4079 -``` diff --git a/ecs.yml b/ecs.yml index 21b30e9b..a6026959 100644 --- a/ecs.yml +++ b/ecs.yml @@ -1,8 +1,8 @@ imports: - - { resource: 'vendor/symplify/easy-coding-standard/config/psr2.yml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/php71.yml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/clean-code.yml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/common.yml' } + - { resource: 'vendor/symplify/easy-coding-standard/config/set/psr2.yaml' } + - { resource: 'vendor/symplify/easy-coding-standard/config/set/php71.yaml' } + - { resource: 'vendor/symplify/easy-coding-standard/config/set/clean-code.yaml' } + - { resource: 'vendor/symplify/easy-coding-standard/config/set/common.yaml' } services: # spacing diff --git a/phpstan.neon b/phpstan.neon index c2abfaf9..7af78fae 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,12 +4,18 @@ includes: - vendor/phpstan/phpstan-phpunit/rules.neon parameters: + checkGenericClassInNonGenericObjectType: false + checkMissingIterableValueType: false + ignoreErrors: - '#Property Phpml\\Clustering\\KMeans\\Cluster\:\:\$points \(iterable\\&SplObjectStorage\) does not accept SplObjectStorage#' - '#Phpml\\Dataset\\(.*)Dataset::__construct\(\) does not call parent constructor from Phpml\\Dataset\\ArrayDataset#' - '#Variable property access on .+#' - '#Variable method call on .+#' - + - message: '#ReflectionClass#' + paths: + - src/Classification/Ensemble/AdaBoost.php + - src/Classification/Ensemble/Bagging.php # probably known value - '#Method Phpml\\Classification\\DecisionTree::getBestSplit\(\) should return Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf but returns Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf\|null#' - '#Call to an undefined method Phpml\\Helper\\Optimizer\\Optimizer::getCostValues\(\)#' diff --git a/src/Association/Apriori.php b/src/Association/Apriori.php index 201bfbf0..1f736790 100644 --- a/src/Association/Apriori.php +++ b/src/Association/Apriori.php @@ -104,11 +104,11 @@ public function apriori(): array */ protected function predictSample(array $sample): array { - $predicts = array_values(array_filter($this->getRules(), function ($rule) use ($sample) { + $predicts = array_values(array_filter($this->getRules(), function ($rule) use ($sample): bool { return $this->equals($rule[self::ARRAY_KEY_ANTECEDENT], $sample); })); - return array_map(function ($rule) { + return array_map(static function ($rule) { return $rule[self::ARRAY_KEY_CONSEQUENT]; }, $predicts); } @@ -177,7 +177,7 @@ private function antecedents(array $sample): array $cardinality = count($sample); $antecedents = $this->powerSet($sample); - return array_filter($antecedents, function ($antecedent) use ($cardinality) { + return array_filter($antecedents, static function ($antecedent) use ($cardinality): bool { return (count($antecedent) != $cardinality) && ($antecedent != []); }); } @@ -199,7 +199,7 @@ private function items(): array } } - return array_map(function ($entry) { + return array_map(static function ($entry): array { return [$entry]; }, $items); } @@ -213,7 +213,7 @@ private function items(): array */ private function frequent(array $samples): array { - return array_values(array_filter($samples, function ($entry) { + return array_values(array_filter($samples, function ($entry): bool { return $this->support($entry) >= $this->support; })); } @@ -288,7 +288,7 @@ private function support(array $sample): float */ private function frequency(array $sample): int { - return count(array_filter($this->samples, function ($entry) use ($sample) { + return count(array_filter($this->samples, function ($entry) use ($sample): bool { return $this->subset($entry, $sample); })); } @@ -303,7 +303,7 @@ private function frequency(array $sample): int */ private function contains(array $system, array $set): bool { - return (bool) array_filter($system, function ($entry) use ($set) { + return (bool) array_filter($system, function ($entry) use ($set): bool { return $this->equals($entry, $set); }); } diff --git a/src/Classification/DecisionTree.php b/src/Classification/DecisionTree.php index 04cde562..b187796e 100644 --- a/src/Classification/DecisionTree.php +++ b/src/Classification/DecisionTree.php @@ -386,9 +386,9 @@ protected function preprocess(array $samples): array $median = Mean::median($values); foreach ($values as &$value) { if ($value <= $median) { - $value = "<= ${median}"; + $value = "<= {$median}"; } else { - $value = "> ${median}"; + $value = "> {$median}"; } } } diff --git a/src/Classification/DecisionTree/DecisionTreeLeaf.php b/src/Classification/DecisionTree/DecisionTreeLeaf.php index 04af3d62..3f8bd2c5 100644 --- a/src/Classification/DecisionTree/DecisionTreeLeaf.php +++ b/src/Classification/DecisionTree/DecisionTreeLeaf.php @@ -122,7 +122,7 @@ public function getNodeImpurityDecrease(int $parentRecordCount): float public function getHTML(?array $columnNames = null): string { if ($this->isTerminal) { - $value = "${this}->classValue"; + $value = "{$this}->classValue"; } else { $value = $this->value; if ($columnNames !== null) { @@ -132,13 +132,13 @@ public function getHTML(?array $columnNames = null): string } if ((bool) preg_match('/^[<>=]{1,2}/', (string) $value) === false) { - $value = "=${value}"; + $value = "={$value}"; } - $value = "${col} ${value}
Gini: ".number_format($this->giniIndex, 2); + $value = "{$col} {$value}
Gini: ".number_format($this->giniIndex, 2); } - $str = ""; + $str = "
${value}
"; if ($this->leftLeaf !== null || $this->rightLeaf !== null) { $str .= ''; diff --git a/src/Classification/Linear/Adaline.php b/src/Classification/Linear/Adaline.php index 797cdc9c..e5bc9d9a 100644 --- a/src/Classification/Linear/Adaline.php +++ b/src/Classification/Linear/Adaline.php @@ -58,7 +58,7 @@ public function __construct( protected function runTraining(array $samples, array $targets): void { // The cost function is the sum of squares - $callback = function ($weights, $sample, $target) { + $callback = function ($weights, $sample, $target): array { $this->weights = $weights; $output = $this->output($sample); diff --git a/src/Classification/Linear/DecisionStump.php b/src/Classification/Linear/DecisionStump.php index 258939e3..ae81d563 100644 --- a/src/Classification/Linear/DecisionStump.php +++ b/src/Classification/Linear/DecisionStump.php @@ -87,7 +87,7 @@ public function __construct(int $columnIndex = self::AUTO_SELECT) public function __toString(): string { - return "IF ${this}->column ${this}->operator ${this}->value ". + return "IF {$this->column} {$this->operator} {$this->value} ". 'THEN '.$this->binaryLabels[0].' '. 'ELSE '.$this->binaryLabels[1]; } diff --git a/src/Classification/Linear/LogisticRegression.php b/src/Classification/Linear/LogisticRegression.php index 889ea981..4014fb07 100644 --- a/src/Classification/Linear/LogisticRegression.php +++ b/src/Classification/Linear/LogisticRegression.php @@ -188,7 +188,7 @@ protected function getCostFunction(): Closure * The gradient of the cost function to be used with gradient descent: * ∇J(x) = -(y - h(x)) = (h(x) - y) */ - return function ($weights, $sample, $y) use ($penalty) { + return function ($weights, $sample, $y) use ($penalty): array { $this->weights = $weights; $hX = $this->output($sample); @@ -220,7 +220,7 @@ protected function getCostFunction(): Closure * The gradient of the cost function: * ∇J(x) = -(h(x) - y) . h(x) . (1 - h(x)) */ - return function ($weights, $sample, $y) use ($penalty) { + return function ($weights, $sample, $y) use ($penalty): array { $this->weights = $weights; $hX = $this->output($sample); diff --git a/src/Classification/Linear/Perceptron.php b/src/Classification/Linear/Perceptron.php index 36cd4d1f..44220a60 100644 --- a/src/Classification/Linear/Perceptron.php +++ b/src/Classification/Linear/Perceptron.php @@ -154,7 +154,7 @@ protected function resetBinary(): void protected function runTraining(array $samples, array $targets): void { // The cost function is the sum of squares - $callback = function ($weights, $sample, $target) { + $callback = function ($weights, $sample, $target): array { $this->weights = $weights; $prediction = $this->outputClass($sample); diff --git a/src/Clustering/FuzzyCMeans.php b/src/Clustering/FuzzyCMeans.php index abc53f17..ce86f5f9 100644 --- a/src/Clustering/FuzzyCMeans.php +++ b/src/Clustering/FuzzyCMeans.php @@ -139,7 +139,7 @@ protected function generateRandomMembership(int $rows, int $cols): void $total += $val; } - $this->membership[] = array_map(function ($val) use ($total) { + $this->membership[] = array_map(static function ($val) use ($total): float { return $val / $total; }, $row); } diff --git a/src/Clustering/KMeans/Space.php b/src/Clustering/KMeans/Space.php index f9f57f5f..e4207cca 100644 --- a/src/Clustering/KMeans/Space.php +++ b/src/Clustering/KMeans/Space.php @@ -88,7 +88,7 @@ public function getBoundaries() $min = $this->newPoint(array_fill(0, $this->dimension, null)); $max = $this->newPoint(array_fill(0, $this->dimension, null)); - /** @var self $point */ + /** @var Point $point */ foreach ($this as $point) { for ($n = 0; $n < $this->dimension; ++$n) { if ($min[$n] === null || $min[$n] > $point[$n]) { @@ -167,6 +167,10 @@ protected function iterate(array $clusters): bool foreach ($cluster as $point) { $closest = $point->getClosest($clusters); + if ($closest === null) { + continue; + } + if ($closest !== $cluster) { $attach[$closest] ?? $attach[$closest] = new SplObjectStorage(); $detach[$cluster] ?? $detach[$cluster] = new SplObjectStorage(); diff --git a/src/Dataset/CsvDataset.php b/src/Dataset/CsvDataset.php index cdd387fb..483664d8 100644 --- a/src/Dataset/CsvDataset.php +++ b/src/Dataset/CsvDataset.php @@ -35,8 +35,8 @@ public function __construct(string $filepath, int $features, bool $headingRow = } $samples = $targets = []; - while (($data = fgetcsv($handle, $maxLineLength, $delimiter)) !== false) { - $samples[] = array_slice((array) $data, 0, $features); + while ($data = fgetcsv($handle, $maxLineLength, $delimiter)) { + $samples[] = array_slice($data, 0, $features); $targets[] = $data[$features]; } diff --git a/src/Dataset/FilesDataset.php b/src/Dataset/FilesDataset.php index daa7192c..e24d908a 100644 --- a/src/Dataset/FilesDataset.php +++ b/src/Dataset/FilesDataset.php @@ -19,7 +19,13 @@ public function __construct(string $rootPath) private function scanRootPath(string $rootPath): void { - foreach (glob($rootPath.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR) as $dir) { + $dirs = glob($rootPath.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR); + + if ($dirs === false) { + throw new DatasetException(sprintf('An error occurred during directory "%s" scan', $rootPath)); + } + + foreach ($dirs as $dir) { $this->scanDir($dir); } } @@ -28,7 +34,12 @@ private function scanDir(string $dir): void { $target = basename($dir); - foreach (array_filter(glob($dir.DIRECTORY_SEPARATOR.'*'), 'is_file') as $file) { + $files = glob($dir.DIRECTORY_SEPARATOR.'*'); + if ($files === false) { + return; + } + + foreach (array_filter($files, 'is_file') as $file) { $this->samples[] = file_get_contents($file); $this->targets[] = $target; } diff --git a/src/DimensionReduction/KernelPCA.php b/src/DimensionReduction/KernelPCA.php index 41c7340f..beeaba41 100644 --- a/src/DimensionReduction/KernelPCA.php +++ b/src/DimensionReduction/KernelPCA.php @@ -179,13 +179,13 @@ protected function getKernel(): Closure // k(x,y)=exp(-γ.|x-y|) where |..| is Euclidean distance $dist = new Euclidean(); - return function ($x, $y) use ($dist) { + return function ($x, $y) use ($dist): float { return exp(-$this->gamma * $dist->sqDistance($x, $y)); }; case self::KERNEL_SIGMOID: // k(x,y)=tanh(γ.xT.y+c0) where c0=1 - return function ($x, $y) { + return function ($x, $y): float { $res = Matrix::dot($x, $y)[0] + 1.0; return tanh((float) $this->gamma * $res); @@ -195,7 +195,7 @@ protected function getKernel(): Closure // k(x,y)=exp(-γ.|x-y|) where |..| is Manhattan distance $dist = new Manhattan(); - return function ($x, $y) use ($dist) { + return function ($x, $y) use ($dist): float { return exp(-$this->gamma * $dist->distance($x, $y)); }; diff --git a/src/FeatureExtraction/StopWords.php b/src/FeatureExtraction/StopWords.php index f5622fd6..1b074105 100644 --- a/src/FeatureExtraction/StopWords.php +++ b/src/FeatureExtraction/StopWords.php @@ -25,7 +25,7 @@ public function isStopWord(string $token): bool public static function factory(string $language = 'English'): self { - $className = __NAMESPACE__."\\StopWords\\${language}"; + $className = __NAMESPACE__."\\StopWords\\{$language}"; if (!class_exists($className)) { throw new InvalidArgumentException(sprintf('Can\'t find "%s" language for StopWords', $language)); diff --git a/src/FeatureExtraction/StopWords/German.php b/src/FeatureExtraction/StopWords/German.php new file mode 100644 index 00000000..93f4cd67 --- /dev/null +++ b/src/FeatureExtraction/StopWords/German.php @@ -0,0 +1,22 @@ +stopWords); + } +} diff --git a/src/FeatureExtraction/StopWords/Russian.php b/src/FeatureExtraction/StopWords/Russian.php new file mode 100644 index 00000000..d26902da --- /dev/null +++ b/src/FeatureExtraction/StopWords/Russian.php @@ -0,0 +1,30 @@ +stopWords); + } +} diff --git a/src/FeatureExtraction/TfIdfTransformer.php b/src/FeatureExtraction/TfIdfTransformer.php index d1ac35db..34f75330 100644 --- a/src/FeatureExtraction/TfIdfTransformer.php +++ b/src/FeatureExtraction/TfIdfTransformer.php @@ -30,7 +30,7 @@ public function fit(array $samples, ?array $targets = null): void } } - public function transform(array &$samples): void + public function transform(array &$samples, ?array &$targets = null): void { foreach ($samples as &$sample) { foreach ($sample as $index => &$feature) { diff --git a/src/FeatureExtraction/TokenCountVectorizer.php b/src/FeatureExtraction/TokenCountVectorizer.php index afd5f339..5cc5e8d3 100644 --- a/src/FeatureExtraction/TokenCountVectorizer.php +++ b/src/FeatureExtraction/TokenCountVectorizer.php @@ -46,7 +46,7 @@ public function fit(array $samples, ?array $targets = null): void $this->buildVocabulary($samples); } - public function transform(array &$samples): void + public function transform(array &$samples, ?array &$targets = null): void { array_walk($samples, function (string &$sample): void { $this->transformSample($sample); diff --git a/src/FeatureSelection/SelectKBest.php b/src/FeatureSelection/SelectKBest.php index 36b4245a..16e52782 100644 --- a/src/FeatureSelection/SelectKBest.php +++ b/src/FeatureSelection/SelectKBest.php @@ -56,7 +56,7 @@ public function fit(array $samples, ?array $targets = null): void $this->keepColumns = array_slice($sorted, 0, $this->k, true); } - public function transform(array &$samples): void + public function transform(array &$samples, ?array &$targets = null): void { if ($this->keepColumns === null) { return; diff --git a/src/FeatureSelection/VarianceThreshold.php b/src/FeatureSelection/VarianceThreshold.php index 5ca23323..0c3154e0 100644 --- a/src/FeatureSelection/VarianceThreshold.php +++ b/src/FeatureSelection/VarianceThreshold.php @@ -37,7 +37,7 @@ public function __construct(float $threshold = 0.0) public function fit(array $samples, ?array $targets = null): void { - $this->variances = array_map(function (array $column) { + $this->variances = array_map(static function (array $column): float { return Variance::population($column); }, Matrix::transposeArray($samples)); @@ -48,7 +48,7 @@ public function fit(array $samples, ?array $targets = null): void } } - public function transform(array &$samples): void + public function transform(array &$samples, ?array &$targets = null): void { foreach ($samples as &$sample) { $sample = array_values(array_intersect_key($sample, $this->keepColumns)); diff --git a/src/FeatureUnion.php b/src/FeatureUnion.php new file mode 100644 index 00000000..645a4219 --- /dev/null +++ b/src/FeatureUnion.php @@ -0,0 +1,72 @@ +pipelines = array_map(static function (Pipeline $pipeline): Pipeline { + return $pipeline; + }, $pipelines); + } + + public function fit(array $samples, ?array $targets = null): void + { + $originSamples = $samples; + foreach ($this->pipelines as $pipeline) { + foreach ($pipeline->getTransformers() as $transformer) { + $transformer->fit($samples, $targets); + $transformer->transform($samples, $targets); + } + $samples = $originSamples; + } + } + + public function transform(array &$samples, ?array &$targets = null): void + { + $this->transformSamples($samples, $targets); + } + + public function fitAndTransform(array &$samples, ?array &$targets = null): void + { + $this->transformSamples($samples, $targets, true); + } + + private function transformSamples(array &$samples, ?array &$targets = null, bool $fit = false): void + { + $union = []; + $originSamples = $samples; + foreach ($this->pipelines as $pipeline) { + foreach ($pipeline->getTransformers() as $transformer) { + if ($fit) { + $transformer->fit($samples, $targets); + } + $transformer->transform($samples, $targets); + } + + foreach ($samples as $index => $sample) { + $union[$index] = array_merge($union[$index] ?? [], is_array($sample) ? $sample : [$sample]); + } + $samples = $originSamples; + } + + $samples = $union; + } +} diff --git a/src/Helper/OneVsRest.php b/src/Helper/OneVsRest.php index 691fb643..b17fc025 100644 --- a/src/Helper/OneVsRest.php +++ b/src/Helper/OneVsRest.php @@ -157,7 +157,7 @@ abstract protected function predictSampleBinary(array $sample); */ private function binarizeTargets(array $targets, $label): array { - $notLabel = "not_${label}"; + $notLabel = "not_{$label}"; foreach ($targets as $key => $target) { $targets[$key] = $target == $label ? $label : $notLabel; } diff --git a/src/Helper/Optimizer/GD.php b/src/Helper/Optimizer/GD.php index 28320329..40c65c70 100644 --- a/src/Helper/Optimizer/GD.php +++ b/src/Helper/Optimizer/GD.php @@ -38,7 +38,7 @@ public function runOptimization(array $samples, array $targets, Closure $gradien $this->updateWeightsWithUpdates($updates, $totalPenalty); - $this->costValues[] = array_sum($errors) / $this->sampleCount; + $this->costValues[] = array_sum($errors) / (int) $this->sampleCount; if ($this->earlyStop($theta)) { break; diff --git a/src/Math/Matrix.php b/src/Math/Matrix.php index db6be42b..6f07d5d5 100644 --- a/src/Math/Matrix.php +++ b/src/Math/Matrix.php @@ -126,7 +126,7 @@ public function isSquare(): bool public function transpose(): self { if ($this->rows === 1) { - $matrix = array_map(function ($el) { + $matrix = array_map(static function ($el): array { return [$el]; }, $this->matrix[0]); } else { @@ -201,7 +201,7 @@ public function multiplyByScalar($value): self */ public function add(self $other): self { - return $this->_add($other); + return $this->sum($other); } /** @@ -209,7 +209,7 @@ public function add(self $other): self */ public function subtract(self $other): self { - return $this->_add($other, -1); + return $this->sum($other, -1); } public function inverse(): self @@ -297,7 +297,7 @@ public static function dot(array $array1, array $array2): array /** * Element-wise addition or substraction depending on the given sign parameter */ - private function _add(self $other, int $sign = 1): self + private function sum(self $other, int $sign = 1): self { $a1 = $this->toArray(); $a2 = $other->toArray(); diff --git a/src/Math/Statistic/ANOVA.php b/src/Math/Statistic/ANOVA.php index d233f84b..16291819 100644 --- a/src/Math/Statistic/ANOVA.php +++ b/src/Math/Statistic/ANOVA.php @@ -28,7 +28,7 @@ public static function oneWayF(array $samples): array throw new InvalidArgumentException('The array must have at least 2 elements'); } - $samplesPerClass = array_map(function (array $class): int { + $samplesPerClass = array_map(static function (array $class): int { return count($class); }, $samples); $allSamples = (int) array_sum($samplesPerClass); @@ -41,10 +41,14 @@ public static function oneWayF(array $samples): array $dfbn = $classes - 1; $dfwn = $allSamples - $classes; - $msb = array_map(function ($s) use ($dfbn) { + $msb = array_map(static function ($s) use ($dfbn) { return $s / $dfbn; }, $ssbn); - $msw = array_map(function ($s) use ($dfwn) { + $msw = array_map(static function ($s) use ($dfwn) { + if ($dfwn === 0) { + return 1; + } + return $s / $dfwn; }, $sswn); @@ -72,7 +76,7 @@ private static function sumOfSquaresPerFeature(array $samples): array private static function sumOfFeaturesPerClass(array $samples): array { - return array_map(function (array $class) { + return array_map(static function (array $class): array { $sum = array_fill(0, count($class[0]), 0); foreach ($class as $sample) { foreach ($sample as $index => $feature) { @@ -93,7 +97,7 @@ private static function sumOfSquares(array $sums): array } } - return array_map(function ($sum) { + return array_map(static function ($sum) { return $sum ** 2; }, $squares); } diff --git a/src/Math/Statistic/StandardDeviation.php b/src/Math/Statistic/StandardDeviation.php index 50effab7..48d93021 100644 --- a/src/Math/Statistic/StandardDeviation.php +++ b/src/Math/Statistic/StandardDeviation.php @@ -50,7 +50,7 @@ public static function sumOfSquares(array $numbers): float $mean = Mean::arithmetic($numbers); return array_sum(array_map( - function ($val) use ($mean) { + static function ($val) use ($mean): float { return ($val - $mean) ** 2; }, $numbers diff --git a/src/Metric/ClassificationReport.php b/src/Metric/ClassificationReport.php index 6263a525..0abac769 100644 --- a/src/Metric/ClassificationReport.php +++ b/src/Metric/ClassificationReport.php @@ -148,7 +148,7 @@ private function computeMicroAverage(): void $precision = $this->computePrecision($truePositive, $falsePositive); $recall = $this->computeRecall($truePositive, $falseNegative); - $f1score = $this->computeF1Score((float) $precision, (float) $recall); + $f1score = $this->computeF1Score($precision, $recall); $this->average = compact('precision', 'recall', 'f1score'); } @@ -186,10 +186,7 @@ private function computeWeightedAverage(): void } } - /** - * @return float|string - */ - private function computePrecision(int $truePositive, int $falsePositive) + private function computePrecision(int $truePositive, int $falsePositive): float { $divider = $truePositive + $falsePositive; if ($divider == 0) { @@ -199,10 +196,7 @@ private function computePrecision(int $truePositive, int $falsePositive) return $truePositive / $divider; } - /** - * @return float|string - */ - private function computeRecall(int $truePositive, int $falseNegative) + private function computeRecall(int $truePositive, int $falseNegative): float { $divider = $truePositive + $falseNegative; if ($divider == 0) { diff --git a/src/Metric/Regression.php b/src/Metric/Regression.php new file mode 100644 index 00000000..c833f6aa --- /dev/null +++ b/src/Metric/Regression.php @@ -0,0 +1,86 @@ + $target) { + $errors[] = (($target - $predictions[$index]) ** 2); + } + + return Mean::arithmetic($errors); + } + + public static function meanSquaredLogarithmicError(array $targets, array $predictions): float + { + self::assertCountEquals($targets, $predictions); + + $errors = []; + foreach ($targets as $index => $target) { + $errors[] = log((1 + $target) / (1 + $predictions[$index])) ** 2; + } + + return Mean::arithmetic($errors); + } + + public static function meanAbsoluteError(array $targets, array $predictions): float + { + self::assertCountEquals($targets, $predictions); + + $errors = []; + foreach ($targets as $index => $target) { + $errors[] = abs($target - $predictions[$index]); + } + + return Mean::arithmetic($errors); + } + + public static function medianAbsoluteError(array $targets, array $predictions): float + { + self::assertCountEquals($targets, $predictions); + + $errors = []; + foreach ($targets as $index => $target) { + $errors[] = abs($target - $predictions[$index]); + } + + return (float) Mean::median($errors); + } + + public static function r2Score(array $targets, array $predictions): float + { + self::assertCountEquals($targets, $predictions); + + return Correlation::pearson($targets, $predictions) ** 2; + } + + public static function maxError(array $targets, array $predictions): float + { + self::assertCountEquals($targets, $predictions); + + $errors = []; + foreach ($targets as $index => $target) { + $errors[] = abs($target - $predictions[$index]); + } + + return (float) max($errors); + } + + private static function assertCountEquals(array &$targets, array &$predictions): void + { + if (count($targets) !== count($predictions)) { + throw new InvalidArgumentException('Targets count must be equal with predictions count'); + } + } +} diff --git a/src/ModelManager.php b/src/ModelManager.php index 057e0ead..e0f5be57 100644 --- a/src/ModelManager.php +++ b/src/ModelManager.php @@ -12,29 +12,29 @@ class ModelManager public function saveToFile(Estimator $estimator, string $filepath): void { if (!is_writable(dirname($filepath))) { - throw new FileException(sprintf('File "%s" can\'t be saved.', basename($filepath))); + throw new FileException(sprintf('File "%s" cannot be saved.', basename($filepath))); } $serialized = serialize($estimator); if (!isset($serialized[0])) { - throw new SerializeException(sprintf('Class "%s" can not be serialized.', gettype($estimator))); + throw new SerializeException(sprintf('Class "%s" cannot be serialized.', gettype($estimator))); } $result = file_put_contents($filepath, $serialized, LOCK_EX); if ($result === false) { - throw new FileException(sprintf('File "%s" can\'t be saved.', basename($filepath))); + throw new FileException(sprintf('File "%s" cannot be saved.', basename($filepath))); } } public function restoreFromFile(string $filepath): Estimator { if (!file_exists($filepath) || !is_readable($filepath)) { - throw new FileException(sprintf('File "%s" can\'t be open.', basename($filepath))); + throw new FileException(sprintf('File "%s" cannot be opened.', basename($filepath))); } - $object = unserialize((string) file_get_contents($filepath), [Estimator::class]); - if ($object === false) { - throw new SerializeException(sprintf('"%s" can not be unserialized.', basename($filepath))); + $object = unserialize((string) file_get_contents($filepath)); + if ($object === false || !$object instanceof Estimator) { + throw new SerializeException(sprintf('"%s" cannot be unserialized.', basename($filepath))); } return $object; diff --git a/src/NeuralNetwork/Node/Neuron.php b/src/NeuralNetwork/Node/Neuron.php index c5376069..6681e66b 100644 --- a/src/NeuralNetwork/Node/Neuron.php +++ b/src/NeuralNetwork/Node/Neuron.php @@ -33,7 +33,7 @@ class Neuron implements Node public function __construct(?ActivationFunction $activationFunction = null) { - $this->activationFunction = $activationFunction ?: new Sigmoid(); + $this->activationFunction = $activationFunction ?? new Sigmoid(); } public function addSynapse(Synapse $synapse): void diff --git a/src/NeuralNetwork/Node/Neuron/Synapse.php b/src/NeuralNetwork/Node/Neuron/Synapse.php index 0a6e0f8c..d749937f 100644 --- a/src/NeuralNetwork/Node/Neuron/Synapse.php +++ b/src/NeuralNetwork/Node/Neuron/Synapse.php @@ -24,7 +24,7 @@ class Synapse public function __construct(Node $node, ?float $weight = null) { $this->node = $node; - $this->weight = $weight ?: $this->generateRandomWeight(); + $this->weight = $weight ?? $this->generateRandomWeight(); } public function getOutput(): float diff --git a/src/Pipeline.php b/src/Pipeline.php index 41188f37..200173bd 100644 --- a/src/Pipeline.php +++ b/src/Pipeline.php @@ -4,7 +4,9 @@ namespace Phpml; -class Pipeline implements Estimator +use Phpml\Exception\InvalidOperationException; + +class Pipeline implements Estimator, Transformer { /** * @var Transformer[] @@ -12,29 +14,18 @@ class Pipeline implements Estimator private $transformers = []; /** - * @var Estimator + * @var Estimator|null */ private $estimator; /** * @param Transformer[] $transformers */ - public function __construct(array $transformers, Estimator $estimator) - { - foreach ($transformers as $transformer) { - $this->addTransformer($transformer); - } - - $this->estimator = $estimator; - } - - public function addTransformer(Transformer $transformer): void - { - $this->transformers[] = $transformer; - } - - public function setEstimator(Estimator $estimator): void + public function __construct(array $transformers, ?Estimator $estimator = null) { + $this->transformers = array_map(static function (Transformer $transformer): Transformer { + return $transformer; + }, $transformers); $this->estimator = $estimator; } @@ -46,16 +37,20 @@ public function getTransformers(): array return $this->transformers; } - public function getEstimator(): Estimator + public function getEstimator(): ?Estimator { return $this->estimator; } public function train(array $samples, array $targets): void { + if ($this->estimator === null) { + throw new InvalidOperationException('Pipeline without estimator can\'t use train method'); + } + foreach ($this->transformers as $transformer) { $transformer->fit($samples, $targets); - $transformer->transform($samples); + $transformer->transform($samples, $targets); } $this->estimator->train($samples, $targets); @@ -66,15 +61,27 @@ public function train(array $samples, array $targets): void */ public function predict(array $samples) { - $this->transformSamples($samples); + $this->transform($samples); + + if ($this->estimator === null) { + throw new InvalidOperationException('Pipeline without estimator can\'t use predict method'); + } return $this->estimator->predict($samples); } - private function transformSamples(array &$samples): void + public function fit(array $samples, ?array $targets = null): void + { + foreach ($this->transformers as $transformer) { + $transformer->fit($samples, $targets); + $transformer->transform($samples, $targets); + } + } + + public function transform(array &$samples, ?array &$targets = null): void { foreach ($this->transformers as $transformer) { - $transformer->transform($samples); + $transformer->transform($samples, $targets); } } } diff --git a/src/Preprocessing/ColumnFilter.php b/src/Preprocessing/ColumnFilter.php new file mode 100644 index 00000000..afe2db7d --- /dev/null +++ b/src/Preprocessing/ColumnFilter.php @@ -0,0 +1,42 @@ +datasetColumns = array_map(static function (string $column): string { + return $column; + }, $datasetColumns); + $this->filterColumns = array_map(static function (string $column): string { + return $column; + }, $filterColumns); + } + + public function fit(array $samples, ?array $targets = null): void + { + //nothing to do + } + + public function transform(array &$samples, ?array &$targets = null): void + { + $keys = array_intersect($this->datasetColumns, $this->filterColumns); + + foreach ($samples as &$sample) { + $sample = array_values(array_intersect_key($sample, $keys)); + } + } +} diff --git a/src/Preprocessing/Imputer.php b/src/Preprocessing/Imputer.php index e5b5af84..88ee2dd6 100644 --- a/src/Preprocessing/Imputer.php +++ b/src/Preprocessing/Imputer.php @@ -49,7 +49,7 @@ public function fit(array $samples, ?array $targets = null): void $this->samples = $samples; } - public function transform(array &$samples): void + public function transform(array &$samples, ?array &$targets = null): void { if ($this->samples === []) { throw new InvalidOperationException('Missing training samples for Imputer.'); diff --git a/src/Preprocessing/LabelEncoder.php b/src/Preprocessing/LabelEncoder.php index 9b5df2c1..1e612a17 100644 --- a/src/Preprocessing/LabelEncoder.php +++ b/src/Preprocessing/LabelEncoder.php @@ -22,7 +22,7 @@ public function fit(array $samples, ?array $targets = null): void } } - public function transform(array &$samples): void + public function transform(array &$samples, ?array &$targets = null): void { foreach ($samples as &$sample) { $sample = $this->classes[(string) $sample]; diff --git a/src/Preprocessing/LambdaTransformer.php b/src/Preprocessing/LambdaTransformer.php new file mode 100644 index 00000000..f6b5a8be --- /dev/null +++ b/src/Preprocessing/LambdaTransformer.php @@ -0,0 +1,30 @@ +lambda = $lambda; + } + + public function fit(array $samples, ?array $targets = null): void + { + // nothing to do + } + + public function transform(array &$samples, ?array &$targets = null): void + { + foreach ($samples as &$sample) { + $sample = call_user_func($this->lambda, $sample); + } + } +} diff --git a/src/Preprocessing/Normalizer.php b/src/Preprocessing/Normalizer.php index 9888e0e5..5ba43e65 100644 --- a/src/Preprocessing/Normalizer.php +++ b/src/Preprocessing/Normalizer.php @@ -66,7 +66,7 @@ public function fit(array $samples, ?array $targets = null): void $this->fitted = true; } - public function transform(array &$samples): void + public function transform(array &$samples, ?array &$targets = null): void { $methods = [ self::NORM_L1 => 'normalizeL1', diff --git a/src/Preprocessing/NumberConverter.php b/src/Preprocessing/NumberConverter.php new file mode 100644 index 00000000..68247b13 --- /dev/null +++ b/src/Preprocessing/NumberConverter.php @@ -0,0 +1,47 @@ +transformTargets = $transformTargets; + $this->nonNumericPlaceholder = $nonNumericPlaceholder; + } + + public function fit(array $samples, ?array $targets = null): void + { + //nothing to do + } + + public function transform(array &$samples, ?array &$targets = null): void + { + foreach ($samples as &$sample) { + foreach ($sample as &$feature) { + $feature = is_numeric($feature) ? (float) $feature : $this->nonNumericPlaceholder; + } + } + + if ($this->transformTargets && is_array($targets)) { + foreach ($targets as &$target) { + $target = is_numeric($target) ? (float) $target : $this->nonNumericPlaceholder; + } + } + } +} diff --git a/src/Preprocessing/OneHotEncoder.php b/src/Preprocessing/OneHotEncoder.php new file mode 100644 index 00000000..c9d4d0af --- /dev/null +++ b/src/Preprocessing/OneHotEncoder.php @@ -0,0 +1,66 @@ +ignoreUnknown = $ignoreUnknown; + } + + public function fit(array $samples, ?array $targets = null): void + { + foreach (array_keys(array_values(current($samples))) as $column) { + $this->fitColumn($column, array_values(array_unique(array_column($samples, $column)))); + } + } + + public function transform(array &$samples, ?array &$targets = null): void + { + foreach ($samples as &$sample) { + $sample = $this->transformSample(array_values($sample)); + } + } + + private function fitColumn(int $column, array $values): void + { + $count = count($values); + foreach ($values as $index => $value) { + $map = array_fill(0, $count, 0); + $map[$index] = 1; + $this->categories[$column][$value] = $map; + } + } + + private function transformSample(array $sample): array + { + $encoded = []; + foreach ($sample as $column => $feature) { + if (!isset($this->categories[$column][$feature]) && !$this->ignoreUnknown) { + throw new InvalidArgumentException(sprintf('Missing category "%s" for column %s in trained encoder', $feature, $column)); + } + + $encoded = array_merge( + $encoded, + $this->categories[$column][$feature] ?? array_fill(0, count($this->categories[$column]), 0) + ); + } + + return $encoded; + } +} diff --git a/src/Regression/DecisionTreeRegressor.php b/src/Regression/DecisionTreeRegressor.php new file mode 100644 index 00000000..afc2805b --- /dev/null +++ b/src/Regression/DecisionTreeRegressor.php @@ -0,0 +1,166 @@ +maxFeatures = $maxFeatures; + $this->tolerance = $tolerance; + + parent::__construct($maxDepth, $maxLeafSize, $minPurityIncrease); + } + + public function train(array $samples, array $targets): void + { + $features = count($samples[0]); + + $this->columns = range(0, $features - 1); + $this->maxFeatures = $this->maxFeatures ?? (int) round(sqrt($features)); + + $this->grow($samples, $targets); + + $this->columns = []; + } + + public function predict(array $samples) + { + if ($this->bare()) { + throw new InvalidOperationException('Regressor must be trained first'); + } + + $predictions = []; + + foreach ($samples as $sample) { + $node = $this->search($sample); + + $predictions[] = $node instanceof AverageNode + ? $node->outcome() + : null; + } + + return $predictions; + } + + protected function split(array $samples, array $targets): DecisionNode + { + $bestVariance = INF; + $bestColumn = $bestValue = null; + $bestGroups = []; + + shuffle($this->columns); + + foreach (array_slice($this->columns, 0, $this->maxFeatures) as $column) { + $values = array_unique(array_column($samples, $column)); + + foreach ($values as $value) { + $groups = $this->partition($column, $value, $samples, $targets); + + $variance = $this->splitImpurity($groups); + + if ($variance < $bestVariance) { + $bestColumn = $column; + $bestValue = $value; + $bestGroups = $groups; + $bestVariance = $variance; + } + + if ($variance <= $this->tolerance) { + break 2; + } + } + } + + return new DecisionNode($bestColumn, $bestValue, $bestGroups, $bestVariance); + } + + protected function terminate(array $targets): BinaryNode + { + return new AverageNode(Mean::arithmetic($targets), Variance::population($targets), count($targets)); + } + + protected function splitImpurity(array $groups): float + { + $samplesCount = (int) array_sum(array_map(static function (array $group): int { + return count($group[0]); + }, $groups)); + + $impurity = 0.; + + foreach ($groups as $group) { + $k = count($group[1]); + + if ($k < 2) { + continue 1; + } + + $variance = Variance::population($group[1]); + + $impurity += ($k / $samplesCount) * $variance; + } + + return $impurity; + } + + /** + * @param int|float $value + */ + private function partition(int $column, $value, array $samples, array $targets): array + { + $leftSamples = $leftTargets = $rightSamples = $rightTargets = []; + foreach ($samples as $index => $sample) { + if ($sample[$column] < $value) { + $leftSamples[] = $sample; + $leftTargets[] = $targets[$index]; + } else { + $rightSamples[] = $sample; + $rightTargets[] = $targets[$index]; + } + } + + return [ + [$leftSamples, $leftTargets], + [$rightSamples, $rightTargets], + ]; + } +} diff --git a/src/Transformer.php b/src/Transformer.php index 7350e2ce..3a9b91db 100644 --- a/src/Transformer.php +++ b/src/Transformer.php @@ -11,5 +11,5 @@ interface Transformer */ public function fit(array $samples, ?array $targets = null): void; - public function transform(array &$samples): void; + public function transform(array &$samples, ?array &$targets = null): void; } diff --git a/src/Tree/CART.php b/src/Tree/CART.php new file mode 100644 index 00000000..eb8cfe77 --- /dev/null +++ b/src/Tree/CART.php @@ -0,0 +1,176 @@ +maxDepth = $maxDepth; + $this->maxLeafSize = $maxLeafSize; + $this->minPurityIncrease = $minPurityIncrease; + } + + public function root(): ?DecisionNode + { + return $this->root; + } + + public function height(): int + { + return $this->root !== null ? $this->root->height() : 0; + } + + public function balance(): int + { + return $this->root !== null ? $this->root->balance() : 0; + } + + public function bare(): bool + { + return $this->root === null; + } + + public function grow(array $samples, array $targets): void + { + $this->featureCount = count($samples[0]); + $depth = 1; + $this->root = $this->split($samples, $targets); + $stack = [[$this->root, $depth]]; + + while ($stack) { + [$current, $depth] = array_pop($stack) ?? []; + + [$left, $right] = $current->groups(); + + $current->cleanup(); + + $depth++; + + if ($left[1] === [] || $right[1] === []) { + $node = $this->terminate(array_merge($left[1], $right[1])); + + $current->attachLeft($node); + $current->attachRight($node); + + continue 1; + } + + if ($depth >= $this->maxDepth) { + $current->attachLeft($this->terminate($left[1])); + $current->attachRight($this->terminate($right[1])); + + continue 1; + } + + if (count($left[1]) > $this->maxLeafSize) { + $node = $this->split($left[0], $left[1]); + + if ($node->purityIncrease() + 1e-8 > $this->minPurityIncrease) { + $current->attachLeft($node); + + $stack[] = [$node, $depth]; + } else { + $current->attachLeft($this->terminate($left[1])); + } + } else { + $current->attachLeft($this->terminate($left[1])); + } + + if (count($right[1]) > $this->maxLeafSize) { + $node = $this->split($right[0], $right[1]); + + if ($node->purityIncrease() + 1e-8 > $this->minPurityIncrease) { + $current->attachRight($node); + + $stack[] = [$node, $depth]; + } else { + $current->attachRight($this->terminate($right[1])); + } + } else { + $current->attachRight($this->terminate($right[1])); + } + } + } + + public function search(array $sample): ?BinaryNode + { + $current = $this->root; + + while ($current) { + if ($current instanceof DecisionNode) { + $value = $current->value(); + + if (is_string($value)) { + if ($sample[$current->column()] === $value) { + $current = $current->left(); + } else { + $current = $current->right(); + } + } else { + if ($sample[$current->column()] < $value) { + $current = $current->left(); + } else { + $current = $current->right(); + } + } + + continue 1; + } + + if ($current instanceof LeafNode) { + break 1; + } + } + + return $current; + } + + abstract protected function split(array $samples, array $targets): DecisionNode; + + abstract protected function terminate(array $targets): BinaryNode; +} diff --git a/src/Tree/Node.php b/src/Tree/Node.php new file mode 100644 index 00000000..3176b625 --- /dev/null +++ b/src/Tree/Node.php @@ -0,0 +1,9 @@ +outcome = $outcome; + $this->impurity = $impurity; + $this->samplesCount = $samplesCount; + } + + public function outcome(): float + { + return $this->outcome; + } + + public function impurity(): float + { + return $this->impurity; + } + + public function samplesCount(): int + { + return $this->samplesCount; + } +} diff --git a/src/Tree/Node/BinaryNode.php b/src/Tree/Node/BinaryNode.php new file mode 100644 index 00000000..c6797b5b --- /dev/null +++ b/src/Tree/Node/BinaryNode.php @@ -0,0 +1,83 @@ +parent; + } + + public function left(): ?self + { + return $this->left; + } + + public function right(): ?self + { + return $this->right; + } + + public function height(): int + { + return 1 + max($this->left !== null ? $this->left->height() : 0, $this->right !== null ? $this->right->height() : 0); + } + + public function balance(): int + { + return ($this->right !== null ? $this->right->height() : 0) - ($this->left !== null ? $this->left->height() : 0); + } + + public function setParent(?self $node = null): void + { + $this->parent = $node; + } + + public function attachLeft(self $node): void + { + $node->setParent($this); + $this->left = $node; + } + + public function detachLeft(): void + { + if ($this->left !== null) { + $this->left->setParent(); + $this->left = null; + } + } + + public function attachRight(self $node): void + { + $node->setParent($this); + $this->right = $node; + } + + public function detachRight(): void + { + if ($this->right !== null) { + $this->right->setParent(); + $this->right = null; + } + } +} diff --git a/src/Tree/Node/DecisionNode.php b/src/Tree/Node/DecisionNode.php new file mode 100644 index 00000000..311e0e77 --- /dev/null +++ b/src/Tree/Node/DecisionNode.php @@ -0,0 +1,107 @@ +column = $column; + $this->value = $value; + $this->groups = $groups; + $this->impurity = $impurity; + $this->samplesCount = (int) array_sum(array_map(static function (array $group): int { + return count($group[0]); + }, $groups)); + } + + public function column(): int + { + return $this->column; + } + + /** + * @return mixed + */ + public function value() + { + return $this->value; + } + + public function groups(): array + { + return $this->groups; + } + + public function impurity(): float + { + return $this->impurity; + } + + public function samplesCount(): int + { + return $this->samplesCount; + } + + public function purityIncrease(): float + { + $impurity = $this->impurity; + + if ($this->left() instanceof PurityNode) { + $impurity -= $this->left()->impurity() + * ($this->left()->samplesCount() / $this->samplesCount); + } + + if ($this->right() instanceof PurityNode) { + $impurity -= $this->right()->impurity() + * ($this->right()->samplesCount() / $this->samplesCount); + } + + return $impurity; + } + + public function cleanup(): void + { + $this->groups = [[], []]; + } +} diff --git a/src/Tree/Node/LeafNode.php b/src/Tree/Node/LeafNode.php new file mode 100644 index 00000000..ebb848e9 --- /dev/null +++ b/src/Tree/Node/LeafNode.php @@ -0,0 +1,9 @@ + ['depth' => 5], + DecisionTree::class => [ + 'depth' => 5, + ], NaiveBayes::class => [], ]; } diff --git a/tests/Classification/Ensemble/RandomForestTest.php b/tests/Classification/Ensemble/RandomForestTest.php index 2f21c5ca..abff9737 100644 --- a/tests/Classification/Ensemble/RandomForestTest.php +++ b/tests/Classification/Ensemble/RandomForestTest.php @@ -61,6 +61,10 @@ protected function getClassifier(int $numBaseClassifiers = 50): Classifier protected function getAvailableBaseClassifiers(): array { - return [DecisionTree::class => ['depth' => 5]]; + return [ + DecisionTree::class => [ + 'depth' => 5, + ], + ]; } } diff --git a/tests/DimensionReduction/KernelPCATest.php b/tests/DimensionReduction/KernelPCATest.php index 6e2ec2bb..da4e51b1 100644 --- a/tests/DimensionReduction/KernelPCATest.php +++ b/tests/DimensionReduction/KernelPCATest.php @@ -40,7 +40,7 @@ public function testKernelPCA(): void // during the calculation of eigenValues, we have to compare // absolute value of the values array_map(function ($val1, $val2) use ($epsilon): void { - self::assertEqualsWithDelta(abs($val1), abs($val2), $epsilon); + self::assertEqualsWithDelta(abs($val1[0]), abs($val2[0]), $epsilon); }, $transformed, $reducedData); // Fitted KernelPCA object can also transform an arbitrary sample of the diff --git a/tests/DimensionReduction/PCATest.php b/tests/DimensionReduction/PCATest.php index 5fbbc94b..3dbc5a6b 100644 --- a/tests/DimensionReduction/PCATest.php +++ b/tests/DimensionReduction/PCATest.php @@ -42,7 +42,7 @@ public function testPCA(): void // during the calculation of eigenValues, we have to compare // absolute value of the values array_map(function ($val1, $val2) use ($epsilon): void { - self::assertEqualsWithDelta(abs($val1), abs($val2), $epsilon); + self::assertEqualsWithDelta(abs($val1[0]), abs($val2[0]), $epsilon); }, $transformed, $reducedData); // Test fitted PCA object to transform an arbitrary sample of the @@ -52,7 +52,7 @@ public function testPCA(): void $newRow2 = $pca->transform($row); array_map(function ($val1, $val2) use ($epsilon): void { - self::assertEqualsWithDelta(abs($val1), abs($val2), $epsilon); + self::assertEqualsWithDelta(abs($val1[0][0]), abs($val2[0]), $epsilon); }, $newRow, $newRow2); } } diff --git a/tests/FeatureSelection/SelectKBestTest.php b/tests/FeatureSelection/SelectKBestTest.php index ebf119b5..5239954a 100644 --- a/tests/FeatureSelection/SelectKBestTest.php +++ b/tests/FeatureSelection/SelectKBestTest.php @@ -61,6 +61,48 @@ public function testSelectKBestWithRegressionScoring(): void ); } + public function testSelectKBestIssue386(): void + { + $samples = [ + [ + 0.0006729998475705993, + 0.0, + 0.999999773507577, + 0.0, + 0.0, + 6.66666515671718E-7, + 3.33333257835859E-6, + 6.66666515671718E-6, + ], + [ + 0.0006729998475849566, + 0.0, + 0.9999997735289103, + 0.0, + 0.0, + 6.666665156859402E-7, + 3.3333325784297012E-6, + 1.3333330313718804E-6, + ], + ]; + + $targets = [15.5844, 4.45284]; + + $selector = new SelectKBest(2); + $selector->fit($samples, $targets); + + self::assertEquals([ + -2.117582368135751E-22, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0097419586828951E-28, + 0.0, + 1.4222215779620095E-11, + ], $selector->scores()); + } + public function testThrowExceptionOnEmptyTargets(): void { $this->expectException(InvalidArgumentException::class); diff --git a/tests/FeatureUnionTest.php b/tests/FeatureUnionTest.php new file mode 100644 index 00000000..0a903b4c --- /dev/null +++ b/tests/FeatureUnionTest.php @@ -0,0 +1,105 @@ +fitAndTransform($samples, $targets); + + self::assertEquals([ + [0, 23.0, 100000.0], + [1, 23.0, 200000.0], + [1, 43.0, 150000.0], + [0, 33.0, 150000.0], + ], $samples); + self::assertEquals([1, 2, 1, 3], $targets); + } + + public function testFitAndTransformSeparate(): void + { + $columns = ['age', 'income', 'sex']; + $trainSamples = [ + ['23', '100000', 'male'], + ['23', '200000', 'female'], + ['43', '150000', 'female'], + ['33', 'n/a', 'male'], + ]; + $testSamples = [ + ['43', '500000', 'female'], + ['13', 'n/a', 'male'], + ['53', 'n/a', 'male'], + ['43', 'n/a', 'female'], + ]; + + $union = new FeatureUnion([ + new Pipeline([ + new ColumnFilter($columns, ['sex']), + new LambdaTransformer(function (array $sample) { + return $sample[0]; + }), + new LabelEncoder(), + ]), + new Pipeline([ + new ColumnFilter($columns, ['age', 'income']), + new NumberConverter(), + new Imputer(null, new MeanStrategy(), Imputer::AXIS_COLUMN), + ]), + ]); + + $union->fit($trainSamples); + $union->transform($testSamples); + + self::assertEquals([ + [1, 43.0, 500000.0], + [0, 13.0, 150000.0], + [0, 53.0, 150000.0], + [1, 43.0, 150000.0], + ], $testSamples); + } + + public function testNotAllowForEmptyPipelines(): void + { + $this->expectException(InvalidArgumentException::class); + + new FeatureUnion([]); + } +} diff --git a/tests/Helper/Optimizer/ConjugateGradientTest.php b/tests/Helper/Optimizer/ConjugateGradientTest.php index 86a2991b..fc85a600 100644 --- a/tests/Helper/Optimizer/ConjugateGradientTest.php +++ b/tests/Helper/Optimizer/ConjugateGradientTest.php @@ -21,7 +21,7 @@ public function testRunOptimization(): void $targets[] = -1 + 2 * $x; } - $callback = function ($theta, $sample, $target) { + $callback = static function ($theta, $sample, $target): array { $y = $theta[0] + $theta[1] * $sample[0]; $cost = (($y - $target) ** 2) / 2; $grad = $y - $target; @@ -47,7 +47,7 @@ public function testRunOptimizationWithCustomInitialTheta(): void $targets[] = -1 + 2 * $x; } - $callback = function ($theta, $sample, $target) { + $callback = static function ($theta, $sample, $target): array { $y = $theta[0] + $theta[1] * $sample[0]; $cost = (($y - $target) ** 2) / 2; $grad = $y - $target; @@ -76,7 +76,7 @@ public function testRunOptimization2Dim(): void $targets[] = -1 + 2 * $x0 - 3 * $x1; } - $callback = function ($theta, $sample, $target) { + $callback = static function ($theta, $sample, $target): array { $y = $theta[0] + $theta[1] * $sample[0] + $theta[2] * $sample[1]; $cost = (($y - $target) ** 2) / 2; $grad = $y - $target; diff --git a/tests/Helper/Optimizer/GDTest.php b/tests/Helper/Optimizer/GDTest.php index 96409889..a6b42776 100644 --- a/tests/Helper/Optimizer/GDTest.php +++ b/tests/Helper/Optimizer/GDTest.php @@ -20,7 +20,7 @@ public function testRunOptimization(): void $targets[] = -1 + 2 * $x; } - $callback = function ($theta, $sample, $target) { + $callback = static function ($theta, $sample, $target): array { $y = $theta[0] + $theta[1] * $sample[0]; $cost = (($y - $target) ** 2) / 2; $grad = $y - $target; @@ -47,7 +47,7 @@ public function testRunOptimization2Dim(): void $targets[] = -1 + 2 * $x0 - 3 * $x1; } - $callback = function ($theta, $sample, $target) { + $callback = static function ($theta, $sample, $target): array { $y = $theta[0] + $theta[1] * $sample[0] + $theta[2] * $sample[1]; $cost = (($y - $target) ** 2) / 2; $grad = $y - $target; diff --git a/tests/Helper/Optimizer/StochasticGDTest.php b/tests/Helper/Optimizer/StochasticGDTest.php index 07927af4..4f99f78a 100644 --- a/tests/Helper/Optimizer/StochasticGDTest.php +++ b/tests/Helper/Optimizer/StochasticGDTest.php @@ -20,7 +20,7 @@ public function testRunOptimization(): void $targets[] = -1 + 2 * $x; } - $callback = function ($theta, $sample, $target) { + $callback = static function ($theta, $sample, $target): array { $y = $theta[0] + $theta[1] * $sample[0]; $cost = (($y - $target) ** 2) / 2; $grad = $y - $target; @@ -47,7 +47,7 @@ public function testRunOptimization2Dim(): void $targets[] = -1 + 2 * $x0 - 3 * $x1; } - $callback = function ($theta, $sample, $target) { + $callback = static function ($theta, $sample, $target): array { $y = $theta[0] + $theta[1] * $sample[0] + $theta[2] * $sample[1]; $cost = (($y - $target) ** 2) / 2; $grad = $y - $target; diff --git a/tests/Metric/RegressionTest.php b/tests/Metric/RegressionTest.php new file mode 100644 index 00000000..1f75cfd9 --- /dev/null +++ b/tests/Metric/RegressionTest.php @@ -0,0 +1,97 @@ +getMockBuilder(Neuron::class)->getMock(); $node->method('getOutput')->willReturn($output); diff --git a/tests/NeuralNetwork/Node/NeuronTest.php b/tests/NeuralNetwork/Node/NeuronTest.php index 448c885b..376d78bb 100644 --- a/tests/NeuralNetwork/Node/NeuronTest.php +++ b/tests/NeuralNetwork/Node/NeuronTest.php @@ -56,7 +56,7 @@ public function testNeuronRefresh(): void /** * @return Synapse|MockObject */ - private function getSynapseMock(int $output = 2) + private function getSynapseMock(float $output = 2.) { $synapse = $this->getMockBuilder(Synapse::class)->disableOriginalConstructor()->getMock(); $synapse->method('getOutput')->willReturn($output); diff --git a/tests/PipelineTest.php b/tests/PipelineTest.php index 31c4f36d..f905c8b3 100644 --- a/tests/PipelineTest.php +++ b/tests/PipelineTest.php @@ -11,9 +11,9 @@ use Phpml\ModelManager; use Phpml\Pipeline; use Phpml\Preprocessing\Imputer; +use Phpml\Preprocessing\Imputer\Strategy\MeanStrategy; use Phpml\Preprocessing\Imputer\Strategy\MostFrequentStrategy; use Phpml\Preprocessing\Normalizer; -use Phpml\Regression\SVR; use Phpml\Tokenization\WordTokenizer; use PHPUnit\Framework\TestCase; @@ -32,16 +32,6 @@ public function testPipelineConstruction(): void self::assertEquals($estimator, $pipeline->getEstimator()); } - public function testPipelineEstimatorSetter(): void - { - $pipeline = new Pipeline([new TfIdfTransformer()], new SVC()); - - $estimator = new SVR(); - $pipeline->setEstimator($estimator); - - self::assertEquals($estimator, $pipeline->getEstimator()); - } - public function testPipelineWorkflow(): void { $transformers = [ @@ -119,6 +109,29 @@ public function testPipelineTransformersWithTargets(): void self::assertEquals(['b'], $pipeline->predict([[1, 3, 5]])); } + public function testPipelineAsTransformer(): void + { + $pipeline = new Pipeline([ + new Imputer(null, new MeanStrategy()), + ]); + + $trainSamples = [ + [10, 20, 30], + [20, 30, 40], + [30, 40, 50], + ]; + + $pipeline->fit($trainSamples); + + $testSamples = [ + [null, null, null], + ]; + + $pipeline->transform($testSamples); + + self::assertEquals([[20.0, 30.0, 40.0]], $testSamples); + } + public function testSaveAndRestore(): void { $pipeline = new Pipeline([ diff --git a/tests/Preprocessing/ColumnFilterTest.php b/tests/Preprocessing/ColumnFilterTest.php new file mode 100644 index 00000000..243c7ebb --- /dev/null +++ b/tests/Preprocessing/ColumnFilterTest.php @@ -0,0 +1,27 @@ +transform($samples); + + self::assertEquals([[100000, 4], [120000, 12], [200000, 0]], $samples); + } +} diff --git a/tests/Preprocessing/LambdaTransformerTest.php b/tests/Preprocessing/LambdaTransformerTest.php new file mode 100644 index 00000000..6f46f3ea --- /dev/null +++ b/tests/Preprocessing/LambdaTransformerTest.php @@ -0,0 +1,28 @@ +transform($samples); + + self::assertEquals([3, 7, 11], $samples); + } +} diff --git a/tests/Preprocessing/NormalizerTest.php b/tests/Preprocessing/NormalizerTest.php index ed6b2c5a..0a8f76cf 100644 --- a/tests/Preprocessing/NormalizerTest.php +++ b/tests/Preprocessing/NormalizerTest.php @@ -126,7 +126,7 @@ public function testStandardNorm(): void foreach ($samples as $sample) { $errors = array_filter( $sample, - function ($element) { + function ($element): bool { return $element < -3 || $element > 3; } ); diff --git a/tests/Preprocessing/NumberConverterTest.php b/tests/Preprocessing/NumberConverterTest.php new file mode 100644 index 00000000..287b7393 --- /dev/null +++ b/tests/Preprocessing/NumberConverterTest.php @@ -0,0 +1,47 @@ +transform($samples, $targets); + + self::assertEquals([[1.0, -4.0], [2.0, 3.0], [3.0, 112.5], [5.0, 0.0004]], $samples); + self::assertEquals(['1', '1', '2', '2'], $targets); + } + + public function testConvertTargets(): void + { + $samples = [['1', '-4'], ['2.0', 3.0], ['3', '112.5'], ['5', '0.0004']]; + $targets = ['1', '1', '2', 'not']; + + $converter = new NumberConverter(true); + $converter->transform($samples, $targets); + + self::assertEquals([[1.0, -4.0], [2.0, 3.0], [3.0, 112.5], [5.0, 0.0004]], $samples); + self::assertEquals([1.0, 1.0, 2.0, null], $targets); + } + + public function testConvertWithPlaceholder(): void + { + $samples = [['invalid'], ['13.5']]; + $targets = ['invalid', '2']; + + $converter = new NumberConverter(true, 'missing'); + $converter->transform($samples, $targets); + + self::assertEquals([['missing'], [13.5]], $samples); + self::assertEquals(['missing', 2.0], $targets); + } +} diff --git a/tests/Preprocessing/OneHotEncoderTest.php b/tests/Preprocessing/OneHotEncoderTest.php new file mode 100644 index 00000000..a5666b75 --- /dev/null +++ b/tests/Preprocessing/OneHotEncoderTest.php @@ -0,0 +1,66 @@ +fit($samples); + $encoder->transform($samples); + + self::assertEquals([ + [1, 0, 1, 0, 1, 0], + [0, 1, 1, 0, 1, 0], + [1, 0, 0, 1, 0, 1], + [0, 1, 0, 1, 1, 0], + ], $samples); + } + + public function testThrowExceptionWhenUnknownCategory(): void + { + $encoder = new OneHotEncoder(); + $encoder->fit([ + ['fish', 'New York', 'regression'], + ['dog', 'New York', 'regression'], + ['fish', 'Vancouver', 'classification'], + ['dog', 'Vancouver', 'regression'], + ]); + $samples = [['fish', 'New York', 'ka boom']]; + + $this->expectException(InvalidArgumentException::class); + + $encoder->transform($samples); + } + + public function testIgnoreMissingCategory(): void + { + $encoder = new OneHotEncoder(true); + $encoder->fit([ + ['fish', 'New York', 'regression'], + ['dog', 'New York', 'regression'], + ['fish', 'Vancouver', 'classification'], + ['dog', 'Vancouver', 'regression'], + ]); + $samples = [['ka', 'boom', 'riko']]; + $encoder->transform($samples); + + self::assertEquals([ + [0, 0, 0, 0, 0, 0], + ], $samples); + } +} diff --git a/tests/Regression/DecisionTreeRegressorTest.php b/tests/Regression/DecisionTreeRegressorTest.php new file mode 100644 index 00000000..046ce5d5 --- /dev/null +++ b/tests/Regression/DecisionTreeRegressorTest.php @@ -0,0 +1,83 @@ +train($samples, $targets); + + self::assertEqualsWithDelta([4.05], $regression->predict([[64]]), $delta); + + $samples = [[9300], [10565], [15000], [15000], [17764], [57000], [65940], [73676], [77006], [93739], [146088], [153260]]; + $targets = [7100, 15500, 4400, 4400, 5900, 4600, 8800, 2000, 2750, 2550, 960, 1025]; + + $regression = new DecisionTreeRegressor(); + $regression->train($samples, $targets); + + self::assertEqualsWithDelta([11300.0], $regression->predict([[9300]]), $delta); + self::assertEqualsWithDelta([5250.0], $regression->predict([[57000]]), $delta); + self::assertEqualsWithDelta([2433.33], $regression->predict([[77006]]), $delta); + self::assertEqualsWithDelta([11300.0], $regression->predict([[9300]]), $delta); + self::assertEqualsWithDelta([992.5], $regression->predict([[153260]]), $delta); + } + + public function testPreventPredictWhenNotTrained(): void + { + $regression = new DecisionTreeRegressor(); + + $this->expectException(InvalidOperationException::class); + + $regression->predict([[1]]); + } + + public function testMaxFeaturesLowerThanOne(): void + { + $this->expectException(InvalidArgumentException::class); + + new DecisionTreeRegressor(5, 3, 0.0, 0); + } + + public function testToleranceSmallerThanZero(): void + { + $this->expectException(InvalidArgumentException::class); + + new DecisionTreeRegressor(5, 3, 0.0, 20, -1); + } + + public function testSaveAndRestore(): void + { + $samples = [[60], [61], [62], [63], [65]]; + $targets = [3.1, 3.6, 3.8, 4, 4.1]; + + $regression = new DecisionTreeRegressor(4); + $regression->train($samples, $targets); + + $testSamples = [[9300], [10565], [15000]]; + $predicted = $regression->predict($testSamples); + + $filename = 'least-squares-test-'.random_int(100, 999).'-'.uniqid('', false); + $filepath = (string) tempnam(sys_get_temp_dir(), $filename); + $modelManager = new ModelManager(); + $modelManager->saveToFile($regression, $filepath); + + $restoredRegression = $modelManager->restoreFromFile($filepath); + self::assertEquals($regression, $restoredRegression); + self::assertEquals($predicted, $restoredRegression->predict($testSamples)); + } +} diff --git a/tests/Tree/Node/BinaryNodeTest.php b/tests/Tree/Node/BinaryNodeTest.php new file mode 100644 index 00000000..43db4181 --- /dev/null +++ b/tests/Tree/Node/BinaryNodeTest.php @@ -0,0 +1,47 @@ +height()); + self::assertEquals(0, $node->balance()); + } + + public function testAttachDetachLeft(): void + { + $node = new BinaryNode(); + $node->attachLeft(new BinaryNode()); + + self::assertEquals(2, $node->height()); + self::assertEquals(-1, $node->balance()); + + $node->detachLeft(); + + self::assertEquals(1, $node->height()); + self::assertEquals(0, $node->balance()); + } + + public function testAttachDetachRight(): void + { + $node = new BinaryNode(); + $node->attachRight(new BinaryNode()); + + self::assertEquals(2, $node->height()); + self::assertEquals(1, $node->balance()); + + $node->detachRight(); + + self::assertEquals(1, $node->height()); + self::assertEquals(0, $node->balance()); + } +} diff --git a/tests/Tree/Node/DecisionNodeTest.php b/tests/Tree/Node/DecisionNodeTest.php new file mode 100644 index 00000000..2db3482c --- /dev/null +++ b/tests/Tree/Node/DecisionNodeTest.php @@ -0,0 +1,57 @@ +column()); + self::assertEquals(2, $node->samplesCount()); + } + + public function testImpurityIncrease(): void + { + $node = new DecisionNode(2, 4, [ + [[[1, 2, 3]], [1]], + [[[2, 3, 4]], [2]], + ], 400); + + $node->attachRight(new DecisionNode(2, 4, [ + [[[1, 2, 3]], [1]], + [[[2, 3, 4]], [2]], + ], 200)); + + $node->attachLeft(new DecisionNode(2, 4, [ + [[[1, 2, 3]], [1]], + [[[2, 3, 4]], [2]], + ], 100)); + + self::assertEquals(100, $node->purityIncrease()); + } + + public function testThrowExceptionOnInvalidGroupsCount(): void + { + $this->expectException(InvalidArgumentException::class); + + new DecisionNode(2, 3, [], 200); + } + + public function testThrowExceptionOnInvalidImpurity(): void + { + $this->expectException(InvalidArgumentException::class); + + new DecisionNode(2, 3, [[], []], -2); + } +}
{$value}