From 00b04ac41d748c0d3d1f732c06330f832fc61186 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Wed, 20 Dec 2023 22:40:37 +0100 Subject: [PATCH 01/18] add Swoole backend --- .github/workflows/ci.yml | 2 +- src/Backends/Swoole.php | 92 +++++++++++++++++++++++++++++++++++ tests/Backends/SwooleTest.php | 81 ++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/Backends/Swoole.php create mode 100644 tests/Backends/SwooleTest.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b992d288c..84e25068b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: with: php-version: ${{ matrix.php-versions }} tools: composer, pecl - extensions: svm, mbstring, gd, fileinfo + extensions: svm, mbstring, gd, fileinfo, swoole ini-values: memory_limit=-1 - name: Validate composer.json diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php new file mode 100644 index 000000000..3f11a4893 --- /dev/null +++ b/src/Backends/Swoole.php @@ -0,0 +1,92 @@ + + */ + protected array $queue = [ + // + ]; + + protected float $timeout; + + public function __construct(float $timeout = -1) + { + $this->timeout = $timeout; + } + + /** + * Queue up a deferred task for backend processing. + * + * @internal + * + * @param \Rubix\ML\Backends\Tasks\Task $task + * @param callable(mixed,mixed):void $after + * @param mixed $context + */ + public function enqueue(Task $task, ?callable $after = null, $context = null) : void + { + $this->queue[] = function () use ($task, $after, $context) { + $result = $task(); + + if ($after) { + $after($result, $context); + } + + return $result; + }; + } + + /** + * Process the queue and return the results. + * + * @internal + * + * @return mixed[] + */ + public function process() : array + { + $results = batch($this->queue, $this->timeout); + + $this->queue = []; + + return $results; + } + + /** + * Flush the queue + */ + public function flush() : void + { + $this->queue = []; + } + + /** + * Return the string representation of the object. + * + * @internal + * + * @return string + */ + public function __toString() : string + { + return 'Swoole'; + } +} diff --git a/tests/Backends/SwooleTest.php b/tests/Backends/SwooleTest.php new file mode 100644 index 000000000..2736b41d2 --- /dev/null +++ b/tests/Backends/SwooleTest.php @@ -0,0 +1,81 @@ +markTestSkipped( + 'Swoole/OpenSwoole extension is not available.' + ); + + return; + } + + $this->backend = new Swoole(); + } + + /** + * @test + */ + public function build() : void + { + $this->assertInstanceOf(Swoole::class, $this->backend); + $this->assertInstanceOf(Backend::class, $this->backend); + } + + /** + * @test + */ + public function enqueueProcess() : void + { + for ($i = 0; $i < 10; ++$i) { + $this->backend->enqueue(new Task([self::class, 'foo'], [$i])); + } + + $results = $this->backend->process(); + + $this->assertCount(10, $results); + $this->assertEquals([ + 0, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18, + ], $results); + } +} From 946cab891e4b44d387ad34d245df3ca2cc790ac8 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Wed, 20 Dec 2023 22:53:49 +0100 Subject: [PATCH 02/18] phpstan: ignore swoole --- phpstan.neon | 1 + src/Backends/Swoole.php | 2 +- tests/Backends/SwooleTest.php | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 90d5425c3..4d1ae5782 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,3 +6,4 @@ parameters: - 'benchmarks' excludePaths: - src/Backends/Amp.php + - src/Backends/Swoole.php diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php index 3f11a4893..01cdf65ec 100644 --- a/src/Backends/Swoole.php +++ b/src/Backends/Swoole.php @@ -19,7 +19,7 @@ class Swoole implements Backend /** * The queue of tasks to be processed in parallel. * - * @var list + * @var list */ protected array $queue = [ // diff --git a/tests/Backends/SwooleTest.php b/tests/Backends/SwooleTest.php index 2736b41d2..6a1bbc594 100644 --- a/tests/Backends/SwooleTest.php +++ b/tests/Backends/SwooleTest.php @@ -37,8 +37,6 @@ protected function setUp() : void $this->markTestSkipped( 'Swoole/OpenSwoole extension is not available.' ); - - return; } $this->backend = new Swoole(); From 606363369efc0ea71bd6a66e320c909acc0b0156 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Sat, 6 Jan 2024 09:09:51 +0100 Subject: [PATCH 03/18] feat: swoole process scheduler --- .../{Swoole.php => Swoole/Coroutine.php} | 7 +- src/Backends/Swoole/Process.php | 127 ++++++++++++++++++ .../CoroutineTest.php} | 21 ++- tests/SwooleProcessBackend.php | 24 ++++ 4 files changed, 170 insertions(+), 9 deletions(-) rename src/Backends/{Swoole.php => Swoole/Coroutine.php} (92%) create mode 100644 src/Backends/Swoole/Process.php rename tests/Backends/{SwooleTest.php => Swoole/CoroutineTest.php} (74%) create mode 100644 tests/SwooleProcessBackend.php diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole/Coroutine.php similarity index 92% rename from src/Backends/Swoole.php rename to src/Backends/Swoole/Coroutine.php index 01cdf65ec..bf9341124 100644 --- a/src/Backends/Swoole.php +++ b/src/Backends/Swoole/Coroutine.php @@ -1,7 +1,8 @@ cpus = swoole_cpu_num(); + } + + /** + * Queue up a deferred task for backend processing. + * + * @internal + * + * @param \Rubix\ML\Backends\Tasks\Task $task + * @param callable(mixed,mixed):void $after + * @param mixed $context + */ + public function enqueue(Task $task, ?callable $after = null, $context = null) : void + { + $this->queue[] = function () use ($task, $after, $context) { + $result = $task(); + + if ($after) { + $after($result, $context); + } + + return $result; + }; + } + + /** + * Process the queue and return the results. + * + * @internal + * + * @return mixed[] + */ + public function process() : array + { + $resultsTable = new Table(count($this->queue) * 2); + $resultsTable->column('result', Table::TYPE_FLOAT); + $resultsTable->create(); + + $workersTable = new Table($this->cpus); + $workersTable->column('working', Table::TYPE_INT); + $workersTable->create(); + + $pool = new Pool($this->cpus); + $pool->on('WorkerStart', function (Pool $pool, $workerId) use ($resultsTable, $workersTable) { + try { + if (!$workersTable->exist($workerId)) { + $workersTable->set($workerId, [ + 'working' => 1, + ]); + + for ($i = $workerId; $i < count($this->queue); $i += $this->cpus) { + if (!$resultsTable->exist($i)) { + $resultsTable->set($i, [ + 'result' => $this->queue[$i](), + ]); + } + } + } + } finally { + $pool->shutdown(); + } + }); + $pool->start(); + + $results = []; + + for ($i = 0; $i < count($this->queue); $i += 1) { + $results[] = $resultsTable->get($i, 'result'); + } + + return $results; + } + + /** + * Flush the queue + */ + public function flush() : void + { + $this->queue = []; + } + + /** + * Return the string representation of the object. + * + * @internal + * + * @return string + */ + public function __toString() : string + { + return 'Swoole\\Process'; + } + + private static function nextPowerOf2($number) + { + return pow(2, ceil(log($number,2))); + } +} diff --git a/tests/Backends/SwooleTest.php b/tests/Backends/Swoole/CoroutineTest.php similarity index 74% rename from tests/Backends/SwooleTest.php rename to tests/Backends/Swoole/CoroutineTest.php index 6a1bbc594..f8ab50dd7 100644 --- a/tests/Backends/SwooleTest.php +++ b/tests/Backends/Swoole/CoroutineTest.php @@ -1,21 +1,22 @@ backend = new Swoole(); + $this->backend = new SwooleCoroutineBackend(); + } + + /** + * @after + */ + protected function tearDown(): void + { + Event::wait(); } /** @@ -47,7 +56,7 @@ protected function setUp() : void */ public function build() : void { - $this->assertInstanceOf(Swoole::class, $this->backend); + $this->assertInstanceOf(SwooleCoroutineBackend::class, $this->backend); $this->assertInstanceOf(Backend::class, $this->backend); } diff --git a/tests/SwooleProcessBackend.php b/tests/SwooleProcessBackend.php new file mode 100644 index 000000000..f2d1653d8 --- /dev/null +++ b/tests/SwooleProcessBackend.php @@ -0,0 +1,24 @@ +enqueue(new Task(function ($input) { + return $input * 2; + }, [$i])); +} + +$results = $backend->process(); + +var_dump(count($results)); +var_dump($results); From d812f8f9afbb7413047798334ee34b21e03230d3 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 8 Jan 2024 16:14:13 +0100 Subject: [PATCH 04/18] fix(swoole): redo tasks when hash collision happens --- composer.json | 3 +- phpunit.xml | 15 +++- src/Backends/Swoole/Process.php | 70 +++++++++++----- tests/Backends/Swoole/CoroutineTest.php | 2 +- tests/Backends/Swoole/ProcessTest.php | 88 +++++++++++++++++++++ tests/BootstrapAggregatorTest.php | 11 ++- tests/Classifiers/OneVsRestTest.php | 13 ++- tests/Classifiers/RandomForestTest.php | 13 ++- tests/CommitteeMachineTest.php | 11 ++- tests/CrossValidation/KFoldTest.php | 13 ++- tests/CrossValidation/LeavePOutTest.php | 13 ++- tests/CrossValidation/MonteCarloTest.php | 13 ++- tests/DataProvider/BackendProviderTrait.php | 36 +++++++++ tests/GridSearchTest.php | 11 ++- tests/SwooleProcessBackend.php | 24 ------ 15 files changed, 260 insertions(+), 76 deletions(-) create mode 100644 tests/Backends/Swoole/ProcessTest.php create mode 100644 tests/DataProvider/BackendProviderTrait.php delete mode 100644 tests/SwooleProcessBackend.php diff --git a/composer.json b/composer.json index 8cb313510..0f34eedb4 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,8 @@ "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.0", + "swoole/ide-helper": "^5.1" }, "suggest": { "ext-tensor": "For fast Matrix/Vector computing", diff --git a/phpunit.xml b/phpunit.xml index 33e100832..54289bc72 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,18 @@ - + src diff --git a/src/Backends/Swoole/Process.php b/src/Backends/Swoole/Process.php index b464ac9f8..c0979cb77 100644 --- a/src/Backends/Swoole/Process.php +++ b/src/Backends/Swoole/Process.php @@ -18,16 +18,26 @@ */ class Process implements Backend { + /** + * Swoole accepts values between 0.2 and 1 + */ + const HASH_COLLISIONS_ALLOWED = 0.25; + /** * The queue of tasks to be processed in parallel. */ protected array $queue = []; - private $cpus; + private int $serialiedRowLength; - public function __construct() - { - $this->cpus = swoole_cpu_num(); + private int $workersCount; + + public function __construct( + int $serialiedRowLength = 65536, + ?int $workersCount = null, + ) { + $this->serialiedRowLength = $serialiedRowLength; + $this->workersCount = $workersCount ?? swoole_cpu_num(); } /** @@ -61,40 +71,65 @@ public function enqueue(Task $task, ?callable $after = null, $context = null) : */ public function process() : array { - $resultsTable = new Table(count($this->queue) * 2); - $resultsTable->column('result', Table::TYPE_FLOAT); + $resultsTable = new Table(count($this->queue), self::HASH_COLLISIONS_ALLOWED); + $resultsTable->column('result', Table::TYPE_STRING, $this->serialiedRowLength); $resultsTable->create(); - $workersTable = new Table($this->cpus); + $workersTable = new Table($this->workersCount, self::HASH_COLLISIONS_ALLOWED); $workersTable->column('working', Table::TYPE_INT); $workersTable->create(); - $pool = new Pool($this->cpus); + $pool = new Pool($this->workersCount); + $pool->on('WorkerStart', function (Pool $pool, $workerId) use ($resultsTable, $workersTable) { try { if (!$workersTable->exist($workerId)) { - $workersTable->set($workerId, [ + if (!$workersTable->set($workerId, [ 'working' => 1, - ]); + ])) { + throw new RuntimeException('Unable to store worker status in the shared memory table'); + } - for ($i = $workerId; $i < count($this->queue); $i += $this->cpus) { + for ($i = $workerId; $i < count($this->queue); $i += $this->workersCount) { if (!$resultsTable->exist($i)) { - $resultsTable->set($i, [ - 'result' => $this->queue[$i](), - ]); + $result = $this->queue[$i](); + + if (!$resultsTable->set($i, [ + 'result' => serialize($result), + ])) { + throw new RuntimeException('Unable to store task result in the shared memory table'); + } } } } } finally { + // Shuts down only the current worker. Tells Pool to not + // create a new worker $pool->shutdown(); } }); + + // This is blocking, waits until all processes finish. $pool->start(); $results = []; for ($i = 0; $i < count($this->queue); $i += 1) { - $results[] = $resultsTable->get($i, 'result'); + $serialized = $resultsTable->get($i, 'result'); + $unserialized = unserialize($serialized); + + if (false === $unserialized) { + // Task needs to be repeated due to hash collision in the Table + // That should be at most HASH_COLLISIONS_ALLOWED, usually less + // + // If 'false' was serialized, then the task will be redone + // unnecessarily. That is the price we have to pay for the lack + // of proper error handling in 'unserialize'. If you disagree + // or have some better idea, please open an issue on GitHub. ;) + $results[] = $this->queue[$i](); + } else { + $results[] = $unserialized; + } } return $results; @@ -119,9 +154,4 @@ public function __toString() : string { return 'Swoole\\Process'; } - - private static function nextPowerOf2($number) - { - return pow(2, ceil(log($number,2))); - } } diff --git a/tests/Backends/Swoole/CoroutineTest.php b/tests/Backends/Swoole/CoroutineTest.php index f8ab50dd7..c3cb1ab7a 100644 --- a/tests/Backends/Swoole/CoroutineTest.php +++ b/tests/Backends/Swoole/CoroutineTest.php @@ -46,7 +46,7 @@ protected function setUp() : void /** * @after */ - protected function tearDown(): void + protected function tearDown() : void { Event::wait(); } diff --git a/tests/Backends/Swoole/ProcessTest.php b/tests/Backends/Swoole/ProcessTest.php new file mode 100644 index 000000000..cc80b012c --- /dev/null +++ b/tests/Backends/Swoole/ProcessTest.php @@ -0,0 +1,88 @@ +markTestSkipped( + 'Swoole/OpenSwoole extension is not available.' + ); + } + + $this->backend = new SwooleProcessBackend(); + } + + /** + * @after + */ + protected function tearDown() : void + { + Event::wait(); + } + + /** + * @test + */ + public function build() : void + { + $this->assertInstanceOf(SwooleProcessBackend::class, $this->backend); + $this->assertInstanceOf(Backend::class, $this->backend); + } + + /** + * @test + */ + public function enqueueProcess() : void + { + for ($i = 0; $i < 10; ++$i) { + $this->backend->enqueue(new Task([self::class, 'foo'], [$i])); + } + + $results = $this->backend->process(); + + $this->assertCount(10, $results); + $this->assertEquals([ + 0, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18, + ], $results); + } +} diff --git a/tests/BootstrapAggregatorTest.php b/tests/BootstrapAggregatorTest.php index 2a17276a7..d3cf83cb9 100644 --- a/tests/BootstrapAggregatorTest.php +++ b/tests/BootstrapAggregatorTest.php @@ -7,7 +7,6 @@ use Rubix\ML\Estimator; use Rubix\ML\Persistable; use Rubix\ML\EstimatorType; -use Rubix\ML\Backends\Serial; use Rubix\ML\Datasets\Unlabeled; use Rubix\ML\BootstrapAggregator; use Rubix\ML\Regressors\RegressionTree; @@ -15,6 +14,8 @@ use Rubix\ML\CrossValidation\Metrics\RSquared; use Rubix\ML\Exceptions\RuntimeException; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group MetaEstimators @@ -22,6 +23,8 @@ */ class BootstrapAggregatorTest extends TestCase { + use BackendProviderTrait; + protected const TRAIN_SIZE = 512; protected const TEST_SIZE = 256; @@ -111,11 +114,13 @@ public function params() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function trainPredict() : void + public function trainPredict(Backend $backend) : void { - $this->estimator->setBackend(new Serial()); + $this->estimator->setBackend($backend); $training = $this->generator->generate(self::TRAIN_SIZE); $testing = $this->generator->generate(self::TEST_SIZE); diff --git a/tests/Classifiers/OneVsRestTest.php b/tests/Classifiers/OneVsRestTest.php index 271e44c52..9b3353218 100644 --- a/tests/Classifiers/OneVsRestTest.php +++ b/tests/Classifiers/OneVsRestTest.php @@ -9,7 +9,6 @@ use Rubix\ML\Persistable; use Rubix\ML\Probabilistic; use Rubix\ML\EstimatorType; -use Rubix\ML\Backends\Serial; use Rubix\ML\Datasets\Unlabeled; use Rubix\ML\Classifiers\OneVsRest; use Rubix\ML\Classifiers\GaussianNB; @@ -18,6 +17,8 @@ use Rubix\ML\Datasets\Generators\Agglomerate; use Rubix\ML\Exceptions\RuntimeException; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group Classifiers @@ -25,6 +26,8 @@ */ class OneVsRestTest extends TestCase { + use BackendProviderTrait; + /** * The number of samples in the training set. * @@ -81,8 +84,6 @@ protected function setUp() : void $this->estimator = new OneVsRest(new GaussianNB()); - $this->estimator->setBackend(new Serial()); - $this->metric = new FBeta(); srand(self::RANDOM_SEED); @@ -139,10 +140,14 @@ public function params() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function trainPredictProba() : void + public function trainPredictProba(Backend $backend) : void { + $this->estimator->setBackend($backend); + $training = $this->generator->generate(self::TRAIN_SIZE); $testing = $this->generator->generate(self::TEST_SIZE); diff --git a/tests/Classifiers/RandomForestTest.php b/tests/Classifiers/RandomForestTest.php index c1caf5358..34d5c4d68 100644 --- a/tests/Classifiers/RandomForestTest.php +++ b/tests/Classifiers/RandomForestTest.php @@ -9,7 +9,6 @@ use Rubix\ML\Probabilistic; use Rubix\ML\RanksFeatures; use Rubix\ML\EstimatorType; -use Rubix\ML\Backends\Serial; use Rubix\ML\Datasets\Unlabeled; use Rubix\ML\Classifiers\RandomForest; use Rubix\ML\Datasets\Generators\Blob; @@ -19,6 +18,8 @@ use Rubix\ML\Exceptions\InvalidArgumentException; use Rubix\ML\Exceptions\RuntimeException; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group Classifiers @@ -26,6 +27,8 @@ */ class RandomForestTest extends TestCase { + use BackendProviderTrait; + /** * The number of samples in the training set. * @@ -82,8 +85,6 @@ protected function setUp() : void $this->estimator = new RandomForest(new ClassificationTree(3), 50, 0.2, true); - $this->estimator->setBackend(new Serial()); - $this->metric = new FBeta(); srand(self::RANDOM_SEED); @@ -154,10 +155,14 @@ public function params() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function trainPredictImportances() : void + public function trainPredictImportances(Backend $backend) : void { + $this->estimator->setBackend($backend); + $training = $this->generator->generate(self::TRAIN_SIZE); $testing = $this->generator->generate(self::TEST_SIZE); diff --git a/tests/CommitteeMachineTest.php b/tests/CommitteeMachineTest.php index a9330c86f..fde97ec7f 100644 --- a/tests/CommitteeMachineTest.php +++ b/tests/CommitteeMachineTest.php @@ -8,7 +8,6 @@ use Rubix\ML\Estimator; use Rubix\ML\Persistable; use Rubix\ML\EstimatorType; -use Rubix\ML\Backends\Serial; use Rubix\ML\CommitteeMachine; use Rubix\ML\Datasets\Unlabeled; use Rubix\ML\Classifiers\GaussianNB; @@ -20,6 +19,8 @@ use Rubix\ML\Exceptions\InvalidArgumentException; use Rubix\ML\Exceptions\RuntimeException; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group MetaEstimators @@ -27,6 +28,8 @@ */ class CommitteeMachineTest extends TestCase { + use BackendProviderTrait; + protected const TRAIN_SIZE = 512; protected const TEST_SIZE = 256; @@ -131,11 +134,13 @@ public function params() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function trainPredict() : void + public function trainPredict(Backend $backend) : void { - $this->estimator->setBackend(new Serial()); + $this->estimator->setBackend($backend); $training = $this->generator->generate(self::TRAIN_SIZE); $testing = $this->generator->generate(self::TEST_SIZE); diff --git a/tests/CrossValidation/KFoldTest.php b/tests/CrossValidation/KFoldTest.php index 7d917fd7b..496e8d1e9 100644 --- a/tests/CrossValidation/KFoldTest.php +++ b/tests/CrossValidation/KFoldTest.php @@ -3,7 +3,6 @@ namespace Rubix\ML\Tests\CrossValidation; use Rubix\ML\Parallel; -use Rubix\ML\Backends\Serial; use Rubix\ML\CrossValidation\KFold; use Rubix\ML\Datasets\Generators\Blob; use Rubix\ML\CrossValidation\Validator; @@ -11,6 +10,8 @@ use Rubix\ML\Datasets\Generators\Agglomerate; use Rubix\ML\CrossValidation\Metrics\Accuracy; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group Validators @@ -18,6 +19,8 @@ */ class KFoldTest extends TestCase { + use BackendProviderTrait; + protected const DATASET_SIZE = 50; /** @@ -54,8 +57,6 @@ protected function setUp() : void $this->validator = new KFold(10); - $this->validator->setBackend(new Serial()); - $this->metric = new Accuracy(); } @@ -70,10 +71,14 @@ public function build() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function test() : void + public function test(Backend $backend) : void { + $this->validator->setBackend($backend); + [$min, $max] = $this->metric->range()->list(); $dataset = $this->generator->generate(self::DATASET_SIZE); diff --git a/tests/CrossValidation/LeavePOutTest.php b/tests/CrossValidation/LeavePOutTest.php index afda69842..9f15d2f88 100644 --- a/tests/CrossValidation/LeavePOutTest.php +++ b/tests/CrossValidation/LeavePOutTest.php @@ -3,7 +3,6 @@ namespace Rubix\ML\Tests\CrossValidation; use Rubix\ML\Parallel; -use Rubix\ML\Backends\Serial; use Rubix\ML\Datasets\Generators\Blob; use Rubix\ML\CrossValidation\LeavePOut; use Rubix\ML\CrossValidation\Validator; @@ -11,6 +10,8 @@ use Rubix\ML\Datasets\Generators\Agglomerate; use Rubix\ML\CrossValidation\Metrics\Accuracy; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group Validators @@ -18,6 +19,8 @@ */ class LeavePOutTest extends TestCase { + use BackendProviderTrait; + protected const DATASET_SIZE = 50; /** @@ -54,8 +57,6 @@ protected function setUp() : void $this->validator = new LeavePOut(10); - $this->validator->setBackend(new Serial()); - $this->metric = new Accuracy(); } @@ -70,10 +71,14 @@ public function build() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function test() : void + public function test(Backend $backend) : void { + $this->validator->setBackend($backend); + [$min, $max] = $this->metric->range()->list(); $dataset = $this->generator->generate(self::DATASET_SIZE); diff --git a/tests/CrossValidation/MonteCarloTest.php b/tests/CrossValidation/MonteCarloTest.php index bc254b0b2..61a05ae6e 100644 --- a/tests/CrossValidation/MonteCarloTest.php +++ b/tests/CrossValidation/MonteCarloTest.php @@ -3,7 +3,6 @@ namespace Rubix\ML\Tests\CrossValidation; use Rubix\ML\Parallel; -use Rubix\ML\Backends\Serial; use Rubix\ML\Datasets\Generators\Blob; use Rubix\ML\CrossValidation\Validator; use Rubix\ML\CrossValidation\MonteCarlo; @@ -11,6 +10,8 @@ use Rubix\ML\Datasets\Generators\Agglomerate; use Rubix\ML\CrossValidation\Metrics\Accuracy; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group Validators @@ -18,6 +19,8 @@ */ class MonteCarloTest extends TestCase { + use BackendProviderTrait; + protected const DATASET_SIZE = 50; /** @@ -54,8 +57,6 @@ protected function setUp() : void $this->validator = new MonteCarlo(3, 0.2); - $this->validator->setBackend(new Serial()); - $this->metric = new Accuracy(); } @@ -70,10 +71,14 @@ public function build() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function test() : void + public function test(Backend $backend) : void { + $this->validator->setBackend($backend); + [$min, $max] = $this->metric->range()->list(); $dataset = $this->generator->generate(self::DATASET_SIZE); diff --git a/tests/DataProvider/BackendProviderTrait.php b/tests/DataProvider/BackendProviderTrait.php new file mode 100644 index 000000000..7207532df --- /dev/null +++ b/tests/DataProvider/BackendProviderTrait.php @@ -0,0 +1,36 @@ + + */ + public static function provideBackends() : array + { + $backends = []; + + $serialBackend = new Serial(); + $backends[(string) $serialBackend] = [$serialBackend]; + + $ampBackend = new AmpBackend(); + $backends[(string) $ampBackend] = [$ampBackend]; + + if (extension_loaded('swoole') || extension_loaded('openswoole')) { + $swooleCoroutineBackend = new SwooleCoroutineBackend(); + $backends[(string) $swooleCoroutineBackend] = [$swooleCoroutineBackend]; + + $swooleProcessBackend = new SwooleProcessBackend(); + $backends[(string) $swooleProcessBackend] = [$swooleProcessBackend]; + } + + return $backends; + } +} diff --git a/tests/GridSearchTest.php b/tests/GridSearchTest.php index a2a2c736a..b67973062 100644 --- a/tests/GridSearchTest.php +++ b/tests/GridSearchTest.php @@ -9,7 +9,6 @@ use Rubix\ML\GridSearch; use Rubix\ML\Persistable; use Rubix\ML\EstimatorType; -use Rubix\ML\Backends\Serial; use Rubix\ML\Loggers\BlackHole; use Rubix\ML\CrossValidation\HoldOut; use Rubix\ML\Kernels\Distance\Euclidean; @@ -20,6 +19,8 @@ use Rubix\ML\Datasets\Generators\Agglomerate; use Rubix\ML\CrossValidation\Metrics\Accuracy; use PHPUnit\Framework\TestCase; +use Rubix\ML\Backends\Backend; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @group MetaEstimators @@ -27,6 +28,8 @@ */ class GridSearchTest extends TestCase { + use BackendProviderTrait; + protected const TRAIN_SIZE = 512; protected const TEST_SIZE = 256; @@ -121,12 +124,14 @@ public function params() : void } /** + * @dataProvider provideBackends * @test + * @param Backend $backend */ - public function trainPredictBest() : void + public function trainPredictBest(Backend $backend) : void { $this->estimator->setLogger(new BlackHole()); - $this->estimator->setBackend(new Serial()); + $this->estimator->setBackend($backend); $training = $this->generator->generate(self::TRAIN_SIZE); $testing = $this->generator->generate(self::TEST_SIZE); diff --git a/tests/SwooleProcessBackend.php b/tests/SwooleProcessBackend.php deleted file mode 100644 index f2d1653d8..000000000 --- a/tests/SwooleProcessBackend.php +++ /dev/null @@ -1,24 +0,0 @@ -enqueue(new Task(function ($input) { - return $input * 2; - }, [$i])); -} - -$results = $backend->process(); - -var_dump(count($results)); -var_dump($results); From d8fe0ed3b9603744ba447db5bc97a420d69130db Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 8 Jan 2024 16:22:57 +0100 Subject: [PATCH 05/18] chore(swoole): make sure coroutines are at the root of the scheduler --- src/Backends/Swoole/Coroutine.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Backends/Swoole/Coroutine.php b/src/Backends/Swoole/Coroutine.php index bf9341124..18c25e188 100644 --- a/src/Backends/Swoole/Coroutine.php +++ b/src/Backends/Swoole/Coroutine.php @@ -4,8 +4,8 @@ use Rubix\ML\Backends\Backend; use Rubix\ML\Backends\Tasks\Task; - -use function Swoole\Coroutine\batch; +use RuntimeException; +use Swoole\Coroutine\Scheduler; /** * Swoole @@ -26,13 +26,6 @@ class Coroutine implements Backend // ]; - protected float $timeout; - - public function __construct(float $timeout = -1) - { - $this->timeout = $timeout; - } - /** * Queue up a deferred task for backend processing. * @@ -64,7 +57,23 @@ public function enqueue(Task $task, ?callable $after = null, $context = null) : */ public function process() : array { - $results = batch($this->queue, $this->timeout); + /** + * Swoole promises that all the coroutines added to the root of the + * scheduler will be executed in parallel. + */ + $scheduler = new Scheduler(); + + $results = []; + + foreach ($this->queue as $callback) { + $scheduler->add(function () use ($callback, &$results) { + $results[] = $callback(); + }); + } + + if (!$scheduler->start()) { + throw new RuntimeException('Not all coroutines finished successfully'); + } $this->queue = []; From 0c08ec51529c1a2a2bca99e129a675cfc18d0f9c Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 8 Jan 2024 17:55:52 +0100 Subject: [PATCH 06/18] chore(swoole): set affinity / bind worker to a specific CPU core --- src/Backends/Swoole/Process.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Backends/Swoole/Process.php b/src/Backends/Swoole/Process.php index c0979cb77..5275133d1 100644 --- a/src/Backends/Swoole/Process.php +++ b/src/Backends/Swoole/Process.php @@ -83,6 +83,9 @@ public function process() : array $pool->on('WorkerStart', function (Pool $pool, $workerId) use ($resultsTable, $workersTable) { try { + $process = $pool->getProcess(); + $process->setAffinity([$workerId]); + if (!$workersTable->exist($workerId)) { if (!$workersTable->set($workerId, [ 'working' => 1, From b69296abf9b8d126a73511a760c7c36221bddce1 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 8 Jan 2024 18:46:42 +0100 Subject: [PATCH 07/18] chore(swoole): use igbinary if available --- benchmarks/Classifiers/RandomForestBench.php | 26 +++++++++++--------- src/Backends/Swoole/IgbinarySerializer.php | 16 ++++++++++++ src/Backends/Swoole/PhpSerializer.php | 16 ++++++++++++ src/Backends/Swoole/Process.php | 18 ++++++++++++-- src/Backends/Swoole/Serializer.php | 10 ++++++++ 5 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 src/Backends/Swoole/IgbinarySerializer.php create mode 100644 src/Backends/Swoole/PhpSerializer.php create mode 100644 src/Backends/Swoole/Serializer.php diff --git a/benchmarks/Classifiers/RandomForestBench.php b/benchmarks/Classifiers/RandomForestBench.php index 1a03a9fc1..f7263ce3f 100644 --- a/benchmarks/Classifiers/RandomForestBench.php +++ b/benchmarks/Classifiers/RandomForestBench.php @@ -2,6 +2,7 @@ namespace Rubix\ML\Benchmarks\Classifiers; +use Rubix\ML\Backends\Swoole\Process as SwooleProcessBackend; use Rubix\ML\Classifiers\RandomForest; use Rubix\ML\Datasets\Generators\Blob; use Rubix\ML\Classifiers\ClassificationTree; @@ -45,6 +46,7 @@ public function setUpContinuous() : void $this->testing = $generator->generate(self::TESTING_SIZE); $this->estimator = new RandomForest(new ClassificationTree(30)); + // $this->estimator->setBackend(new SwooleProcessBackend()); } public function setUpCategorical() : void @@ -78,16 +80,16 @@ public function continuous() : void $this->estimator->predict($this->testing); } - /** - * @Subject - * @Iterations(5) - * @BeforeMethods({"setUpCategorical"}) - * @OutputTimeUnit("seconds", precision=3) - */ - public function categorical() : void - { - $this->estimator->train($this->training); - - $this->estimator->predict($this->testing); - } + // /** + // * @Subject + // * @Iterations(5) + // * @BeforeMethods({"setUpCategorical"}) + // * @OutputTimeUnit("seconds", precision=3) + // */ + // public function categorical() : void + // { + // $this->estimator->train($this->training); + + // $this->estimator->predict($this->testing); + // } } diff --git a/src/Backends/Swoole/IgbinarySerializer.php b/src/Backends/Swoole/IgbinarySerializer.php new file mode 100644 index 000000000..6bdcf01d4 --- /dev/null +++ b/src/Backends/Swoole/IgbinarySerializer.php @@ -0,0 +1,16 @@ +serializer = $serializer; + } else { + if (extension_loaded('igbinary')) { + $this->serializer = new IgbinarySerializer(); + } else { + $this->serializer = new PhpSerializer(); + } + } + $this->serialiedRowLength = $serialiedRowLength; $this->workersCount = $workersCount ?? swoole_cpu_num(); } @@ -96,9 +109,10 @@ public function process() : array for ($i = $workerId; $i < count($this->queue); $i += $this->workersCount) { if (!$resultsTable->exist($i)) { $result = $this->queue[$i](); + $serialized = $this->serializer->serialize($result); if (!$resultsTable->set($i, [ - 'result' => serialize($result), + 'result' => $serialized, ])) { throw new RuntimeException('Unable to store task result in the shared memory table'); } @@ -119,7 +133,7 @@ public function process() : array for ($i = 0; $i < count($this->queue); $i += 1) { $serialized = $resultsTable->get($i, 'result'); - $unserialized = unserialize($serialized); + $unserialized = $this->serializer->unserialize($serialized); if (false === $unserialized) { // Task needs to be repeated due to hash collision in the Table diff --git a/src/Backends/Swoole/Serializer.php b/src/Backends/Swoole/Serializer.php new file mode 100644 index 000000000..711dead90 --- /dev/null +++ b/src/Backends/Swoole/Serializer.php @@ -0,0 +1,10 @@ + Date: Mon, 8 Jan 2024 18:47:02 +0100 Subject: [PATCH 08/18] fix: remove comment --- benchmarks/Classifiers/RandomForestBench.php | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/benchmarks/Classifiers/RandomForestBench.php b/benchmarks/Classifiers/RandomForestBench.php index f7263ce3f..4d524cd73 100644 --- a/benchmarks/Classifiers/RandomForestBench.php +++ b/benchmarks/Classifiers/RandomForestBench.php @@ -80,16 +80,16 @@ public function continuous() : void $this->estimator->predict($this->testing); } - // /** - // * @Subject - // * @Iterations(5) - // * @BeforeMethods({"setUpCategorical"}) - // * @OutputTimeUnit("seconds", precision=3) - // */ - // public function categorical() : void - // { - // $this->estimator->train($this->training); - - // $this->estimator->predict($this->testing); - // } + /** + * @Subject + * @Iterations(5) + * @BeforeMethods({"setUpCategorical"}) + * @OutputTimeUnit("seconds", precision=3) + */ + public function categorical() : void + { + $this->estimator->train($this->training); + + $this->estimator->predict($this->testing); + } } From d4666f50497fdd360566836fbb9b28ad4d8a5ead Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 8 Jan 2024 18:52:22 +0100 Subject: [PATCH 09/18] fix(swoole): worker cpu affinity --- src/Backends/Swoole/Process.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Backends/Swoole/Process.php b/src/Backends/Swoole/Process.php index b97b5a85e..3e58e086e 100644 --- a/src/Backends/Swoole/Process.php +++ b/src/Backends/Swoole/Process.php @@ -28,15 +28,14 @@ class Process implements Backend */ protected array $queue = []; - private int $serialiedRowLength; + private int $cpus; - private int $workersCount; + private int $serialiedRowLength; private Serializer $serializer; public function __construct( int $serialiedRowLength = 65536, - ?int $workersCount = null, ?Serializer $serializer = null, ) { if ($serializer) { @@ -50,7 +49,6 @@ public function __construct( } $this->serialiedRowLength = $serialiedRowLength; - $this->workersCount = $workersCount ?? swoole_cpu_num(); } /** @@ -88,15 +86,19 @@ public function process() : array $resultsTable->column('result', Table::TYPE_STRING, $this->serialiedRowLength); $resultsTable->create(); - $workersTable = new Table($this->workersCount, self::HASH_COLLISIONS_ALLOWED); + $workersTable = new Table($this->cpus, self::HASH_COLLISIONS_ALLOWED); $workersTable->column('working', Table::TYPE_INT); $workersTable->create(); - $pool = new Pool($this->workersCount); + $pool = new Pool($this->cpus); $pool->on('WorkerStart', function (Pool $pool, $workerId) use ($resultsTable, $workersTable) { try { $process = $pool->getProcess(); + + // Worker id is an integer that goes from 0 to the number of + // workers. There are "$this->cpu" workers spawned, so worker + // id should correspond to a specific core. $process->setAffinity([$workerId]); if (!$workersTable->exist($workerId)) { @@ -106,7 +108,7 @@ public function process() : array throw new RuntimeException('Unable to store worker status in the shared memory table'); } - for ($i = $workerId; $i < count($this->queue); $i += $this->workersCount) { + for ($i = $workerId; $i < count($this->queue); $i += $this->cpus) { if (!$resultsTable->exist($i)) { $result = $this->queue[$i](); $serialized = $this->serializer->serialize($result); From bfa97d1342bc0dd14549c423cc062cb9da9d184d Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 8 Jan 2024 18:53:14 +0100 Subject: [PATCH 10/18] fix(swoole): cpu num --- src/Backends/Swoole/Process.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Backends/Swoole/Process.php b/src/Backends/Swoole/Process.php index 3e58e086e..bb0419827 100644 --- a/src/Backends/Swoole/Process.php +++ b/src/Backends/Swoole/Process.php @@ -38,6 +38,8 @@ public function __construct( int $serialiedRowLength = 65536, ?Serializer $serializer = null, ) { + $this->cpus = swoole_cpu_num(); + if ($serializer) { $this->serializer = $serializer; } else { From 6c267bcec14dc6fee02df27db3ef97a0c7909747 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Fri, 12 Jan 2024 16:29:11 +0100 Subject: [PATCH 11/18] feat: scheduler improvements --- benchmarks/Classifiers/RandomForestBench.php | 30 +-- src/Backends/Swoole.php | 162 ++++++++++++++++ src/Backends/Swoole/Coroutine.php | 102 ---------- src/Backends/Swoole/IgbinarySerializer.php | 16 -- src/Backends/Swoole/PhpSerializer.php | 16 -- src/Backends/Swoole/Process.php | 178 ------------------ src/Backends/Swoole/Serializer.php | 10 - src/Serializers/Igbinary.php | 87 +++++++++ .../SwooleExtensionIsLoaded.php | 31 +++ tests/Backends/Swoole/CoroutineTest.php | 88 --------- .../ProcessTest.php => SwooleTest.php} | 13 +- tests/DataProvider/BackendProviderTrait.php | 15 +- 12 files changed, 309 insertions(+), 439 deletions(-) create mode 100644 src/Backends/Swoole.php delete mode 100644 src/Backends/Swoole/Coroutine.php delete mode 100644 src/Backends/Swoole/IgbinarySerializer.php delete mode 100644 src/Backends/Swoole/PhpSerializer.php delete mode 100644 src/Backends/Swoole/Process.php delete mode 100644 src/Backends/Swoole/Serializer.php create mode 100644 src/Serializers/Igbinary.php create mode 100644 src/Specifications/SwooleExtensionIsLoaded.php delete mode 100644 tests/Backends/Swoole/CoroutineTest.php rename tests/Backends/{Swoole/ProcessTest.php => SwooleTest.php} (80%) diff --git a/benchmarks/Classifiers/RandomForestBench.php b/benchmarks/Classifiers/RandomForestBench.php index 4d524cd73..c1b02b817 100644 --- a/benchmarks/Classifiers/RandomForestBench.php +++ b/benchmarks/Classifiers/RandomForestBench.php @@ -2,7 +2,8 @@ namespace Rubix\ML\Benchmarks\Classifiers; -use Rubix\ML\Backends\Swoole\Process as SwooleProcessBackend; +use Rubix\ML\Backends\Amp; +use Rubix\ML\Backends\Swoole as SwooleBackend; use Rubix\ML\Classifiers\RandomForest; use Rubix\ML\Datasets\Generators\Blob; use Rubix\ML\Classifiers\ClassificationTree; @@ -46,7 +47,8 @@ public function setUpContinuous() : void $this->testing = $generator->generate(self::TESTING_SIZE); $this->estimator = new RandomForest(new ClassificationTree(30)); - // $this->estimator->setBackend(new SwooleProcessBackend()); + $this->estimator->setBackend(new SwooleBackend()); + // $this->estimator->setBackend(new Amp()); } public function setUpCategorical() : void @@ -80,16 +82,16 @@ public function continuous() : void $this->estimator->predict($this->testing); } - /** - * @Subject - * @Iterations(5) - * @BeforeMethods({"setUpCategorical"}) - * @OutputTimeUnit("seconds", precision=3) - */ - public function categorical() : void - { - $this->estimator->train($this->training); - - $this->estimator->predict($this->testing); - } + // /** + // * @Subject + // * @Iterations(5) + // * @BeforeMethods({"setUpCategorical"}) + // * @OutputTimeUnit("seconds", precision=3) + // */ + // public function categorical() : void + // { + // $this->estimator->train($this->training); + + // $this->estimator->predict($this->testing); + // } } diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php new file mode 100644 index 000000000..36946e593 --- /dev/null +++ b/src/Backends/Swoole.php @@ -0,0 +1,162 @@ +cpus = swoole_cpu_num(); + + if ($serializer) { + $this->serializer = $serializer; + } else { + if (ExtensionIsLoaded::with('igbinary')->passes()) { + $this->serializer = new Igbinary(); + } else { + $this->serializer = new Native(); + } + } + } + + /** + * Queue up a deferred task for backend processing. + * + * @internal + * + * @param \Rubix\ML\Backends\Tasks\Task $task + * @param callable(mixed,mixed):void $after + * @param mixed $context + */ + public function enqueue(Task $task, ?callable $after = null, $context = null) : void + { + $this->queue[] = function () use ($task, $after, $context) { + $result = $task(); + + if ($after) { + $after($result, $context); + } + + return $result; + }; + } + + /** + * Process the queue and return the results. + * + * @internal + * + * @return mixed[] + */ + public function process() : array + { + $results = []; + + $finishedTasksAtomic = new Atomic(); + $waitingAtomic = new Atomic(); + + $scheduledTasksTotal = count($this->queue); + $workerProcesses = []; + + $currentCpu = 0; + + while (($queueItem = array_shift($this->queue))) { + $workerProcess = new Process( + callback: function (Process $worker) use ($finishedTasksAtomic, $queueItem, $scheduledTasksTotal, $waitingAtomic) { + try { + $worker->exportSocket()->send(igbinary_serialize($queueItem())); + } finally { + $finishedTasksAtomic->add(1); + + if ($scheduledTasksTotal <= $finishedTasksAtomic->get()) { + $waitingAtomic->wakeup(); + } + } + }, + enable_coroutine: true, + pipe_type: 1, + redirect_stdin_and_stdout: false, + ); + + $workerProcess->setAffinity([ + $currentCpu, + ]); + $workerProcess->setBlocking(false); + $workerProcess->start(); + + $workerProcesses[] = $workerProcess; + + $currentCpu = ($currentCpu + 1) % $this->cpus; + } + + $waitingAtomic->wait(-1); + + run(function () use (&$results, $workerProcesses) { + foreach ($workerProcesses as $workerProcess) { + $receivedData = $workerProcess->exportSocket()->recv(); + $unserialized = igbinary_unserialize($receivedData); + + $results[] = $unserialized; + } + }); + + return $results; + } + + /** + * Flush the queue + */ + public function flush() : void + { + $this->queue = []; + } + + /** + * Return the string representation of the object. + * + * @internal + * + * @return string + */ + public function __toString() : string + { + return 'Swoole\\Process'; + } +} diff --git a/src/Backends/Swoole/Coroutine.php b/src/Backends/Swoole/Coroutine.php deleted file mode 100644 index 18c25e188..000000000 --- a/src/Backends/Swoole/Coroutine.php +++ /dev/null @@ -1,102 +0,0 @@ - - */ - protected array $queue = [ - // - ]; - - /** - * Queue up a deferred task for backend processing. - * - * @internal - * - * @param \Rubix\ML\Backends\Tasks\Task $task - * @param callable(mixed,mixed):void $after - * @param mixed $context - */ - public function enqueue(Task $task, ?callable $after = null, $context = null) : void - { - $this->queue[] = function () use ($task, $after, $context) { - $result = $task(); - - if ($after) { - $after($result, $context); - } - - return $result; - }; - } - - /** - * Process the queue and return the results. - * - * @internal - * - * @return mixed[] - */ - public function process() : array - { - /** - * Swoole promises that all the coroutines added to the root of the - * scheduler will be executed in parallel. - */ - $scheduler = new Scheduler(); - - $results = []; - - foreach ($this->queue as $callback) { - $scheduler->add(function () use ($callback, &$results) { - $results[] = $callback(); - }); - } - - if (!$scheduler->start()) { - throw new RuntimeException('Not all coroutines finished successfully'); - } - - $this->queue = []; - - return $results; - } - - /** - * Flush the queue - */ - public function flush() : void - { - $this->queue = []; - } - - /** - * Return the string representation of the object. - * - * @internal - * - * @return string - */ - public function __toString() : string - { - return 'Swoole\\Coroutine'; - } -} diff --git a/src/Backends/Swoole/IgbinarySerializer.php b/src/Backends/Swoole/IgbinarySerializer.php deleted file mode 100644 index 6bdcf01d4..000000000 --- a/src/Backends/Swoole/IgbinarySerializer.php +++ /dev/null @@ -1,16 +0,0 @@ -cpus = swoole_cpu_num(); - - if ($serializer) { - $this->serializer = $serializer; - } else { - if (extension_loaded('igbinary')) { - $this->serializer = new IgbinarySerializer(); - } else { - $this->serializer = new PhpSerializer(); - } - } - - $this->serialiedRowLength = $serialiedRowLength; - } - - /** - * Queue up a deferred task for backend processing. - * - * @internal - * - * @param \Rubix\ML\Backends\Tasks\Task $task - * @param callable(mixed,mixed):void $after - * @param mixed $context - */ - public function enqueue(Task $task, ?callable $after = null, $context = null) : void - { - $this->queue[] = function () use ($task, $after, $context) { - $result = $task(); - - if ($after) { - $after($result, $context); - } - - return $result; - }; - } - - /** - * Process the queue and return the results. - * - * @internal - * - * @return mixed[] - */ - public function process() : array - { - $resultsTable = new Table(count($this->queue), self::HASH_COLLISIONS_ALLOWED); - $resultsTable->column('result', Table::TYPE_STRING, $this->serialiedRowLength); - $resultsTable->create(); - - $workersTable = new Table($this->cpus, self::HASH_COLLISIONS_ALLOWED); - $workersTable->column('working', Table::TYPE_INT); - $workersTable->create(); - - $pool = new Pool($this->cpus); - - $pool->on('WorkerStart', function (Pool $pool, $workerId) use ($resultsTable, $workersTable) { - try { - $process = $pool->getProcess(); - - // Worker id is an integer that goes from 0 to the number of - // workers. There are "$this->cpu" workers spawned, so worker - // id should correspond to a specific core. - $process->setAffinity([$workerId]); - - if (!$workersTable->exist($workerId)) { - if (!$workersTable->set($workerId, [ - 'working' => 1, - ])) { - throw new RuntimeException('Unable to store worker status in the shared memory table'); - } - - for ($i = $workerId; $i < count($this->queue); $i += $this->cpus) { - if (!$resultsTable->exist($i)) { - $result = $this->queue[$i](); - $serialized = $this->serializer->serialize($result); - - if (!$resultsTable->set($i, [ - 'result' => $serialized, - ])) { - throw new RuntimeException('Unable to store task result in the shared memory table'); - } - } - } - } - } finally { - // Shuts down only the current worker. Tells Pool to not - // create a new worker - $pool->shutdown(); - } - }); - - // This is blocking, waits until all processes finish. - $pool->start(); - - $results = []; - - for ($i = 0; $i < count($this->queue); $i += 1) { - $serialized = $resultsTable->get($i, 'result'); - $unserialized = $this->serializer->unserialize($serialized); - - if (false === $unserialized) { - // Task needs to be repeated due to hash collision in the Table - // That should be at most HASH_COLLISIONS_ALLOWED, usually less - // - // If 'false' was serialized, then the task will be redone - // unnecessarily. That is the price we have to pay for the lack - // of proper error handling in 'unserialize'. If you disagree - // or have some better idea, please open an issue on GitHub. ;) - $results[] = $this->queue[$i](); - } else { - $results[] = $unserialized; - } - } - - return $results; - } - - /** - * Flush the queue - */ - public function flush() : void - { - $this->queue = []; - } - - /** - * Return the string representation of the object. - * - * @internal - * - * @return string - */ - public function __toString() : string - { - return 'Swoole\\Process'; - } -} diff --git a/src/Backends/Swoole/Serializer.php b/src/Backends/Swoole/Serializer.php deleted file mode 100644 index 711dead90..000000000 --- a/src/Backends/Swoole/Serializer.php +++ /dev/null @@ -1,10 +0,0 @@ -check(); + } + + /** + * Serialize a persistable object and return the data. + * + * @internal + * + * @param \Rubix\ML\Persistable $persistable + * @throws \Rubix\ML\Exceptions\RuntimeException + * @return \Rubix\ML\Encoding + */ + public function serialize(Persistable $persistable) : Encoding + { + $data = igbinary_serialize($persistable); + + if (!$data) { + throw new RuntimeException('Could not serialize data.'); + } + + return new Encoding($data); + } + + /** + * Deserialize a persistable object and return it. + * + * @internal + * + * @param \Rubix\ML\Encoding $encoding + * @throws \Rubix\ML\Exceptions\RuntimeException + * @return \Rubix\ML\Persistable + */ + public function deserialize(Encoding $encoding) : Persistable + { + $persistable = igbinary_unserialize($encoding); + + if (!is_object($persistable)) { + throw new RuntimeException('deserialized data must be an object.'); + } + + if ($persistable instanceof __PHP_Incomplete_Class) { + throw new RuntimeException('Missing class for object data.'); + } + + if (!$persistable instanceof Persistable) { + throw new RuntimeException('deserialized object must' + . ' implement the Persistable interface.'); + } + + return $persistable; + } + + /** + * Return the string representation of the object. + * + * @return string + */ + public function __toString() : string + { + return 'Igbinary'; + } +} \ No newline at end of file diff --git a/src/Specifications/SwooleExtensionIsLoaded.php b/src/Specifications/SwooleExtensionIsLoaded.php new file mode 100644 index 000000000..d2179ef51 --- /dev/null +++ b/src/Specifications/SwooleExtensionIsLoaded.php @@ -0,0 +1,31 @@ +passes() + || ExtensionIsLoaded::with('openswoole')->passes() + ) { + return; + } + + throw new MissingExtension('swoole'); + } +} diff --git a/tests/Backends/Swoole/CoroutineTest.php b/tests/Backends/Swoole/CoroutineTest.php deleted file mode 100644 index c3cb1ab7a..000000000 --- a/tests/Backends/Swoole/CoroutineTest.php +++ /dev/null @@ -1,88 +0,0 @@ -markTestSkipped( - 'Swoole/OpenSwoole extension is not available.' - ); - } - - $this->backend = new SwooleCoroutineBackend(); - } - - /** - * @after - */ - protected function tearDown() : void - { - Event::wait(); - } - - /** - * @test - */ - public function build() : void - { - $this->assertInstanceOf(SwooleCoroutineBackend::class, $this->backend); - $this->assertInstanceOf(Backend::class, $this->backend); - } - - /** - * @test - */ - public function enqueueProcess() : void - { - for ($i = 0; $i < 10; ++$i) { - $this->backend->enqueue(new Task([self::class, 'foo'], [$i])); - } - - $results = $this->backend->process(); - - $this->assertCount(10, $results); - $this->assertEquals([ - 0, - 2, - 4, - 6, - 8, - 10, - 12, - 14, - 16, - 18, - ], $results); - } -} diff --git a/tests/Backends/Swoole/ProcessTest.php b/tests/Backends/SwooleTest.php similarity index 80% rename from tests/Backends/Swoole/ProcessTest.php rename to tests/Backends/SwooleTest.php index cc80b012c..ece9e41a6 100644 --- a/tests/Backends/Swoole/ProcessTest.php +++ b/tests/Backends/SwooleTest.php @@ -1,11 +1,12 @@ passes()) { $this->markTestSkipped( 'Swoole/OpenSwoole extension is not available.' ); } - $this->backend = new SwooleProcessBackend(); + $this->backend = new SwooleBackend(); } /** @@ -56,7 +57,7 @@ protected function tearDown() : void */ public function build() : void { - $this->assertInstanceOf(SwooleProcessBackend::class, $this->backend); + $this->assertInstanceOf(SwooleBackend::class, $this->backend); $this->assertInstanceOf(Backend::class, $this->backend); } diff --git a/tests/DataProvider/BackendProviderTrait.php b/tests/DataProvider/BackendProviderTrait.php index 7207532df..f33d72a6a 100644 --- a/tests/DataProvider/BackendProviderTrait.php +++ b/tests/DataProvider/BackendProviderTrait.php @@ -4,9 +4,9 @@ use Rubix\ML\Backends\Backend; use Rubix\ML\Backends\Serial; -use Rubix\ML\Backends\Amp as AmpBackend; -use Rubix\ML\Backends\Swoole\Coroutine as SwooleCoroutineBackend; -use Rubix\ML\Backends\Swoole\Process as SwooleProcessBackend; +use Rubix\ML\Backends\Amp; +use Rubix\ML\Backends\Swoole; +use Rubix\ML\Specifications\SwooleExtensionIsLoaded; trait BackendProviderTrait { @@ -20,14 +20,11 @@ public static function provideBackends() : array $serialBackend = new Serial(); $backends[(string) $serialBackend] = [$serialBackend]; - $ampBackend = new AmpBackend(); + $ampBackend = new Amp(); $backends[(string) $ampBackend] = [$ampBackend]; - if (extension_loaded('swoole') || extension_loaded('openswoole')) { - $swooleCoroutineBackend = new SwooleCoroutineBackend(); - $backends[(string) $swooleCoroutineBackend] = [$swooleCoroutineBackend]; - - $swooleProcessBackend = new SwooleProcessBackend(); + if (SwooleExtensionIsLoaded::create()->passes()) { + $swooleProcessBackend = new Swoole(); $backends[(string) $swooleProcessBackend] = [$swooleProcessBackend]; } From 7b200f594422396781d699de0dd5f59e800b2ead Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Fri, 12 Jan 2024 16:36:39 +0100 Subject: [PATCH 12/18] style --- src/Backends/Swoole.php | 5 ----- src/Serializers/Igbinary.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php index 36946e593..8c528a183 100644 --- a/src/Backends/Swoole.php +++ b/src/Backends/Swoole.php @@ -2,18 +2,13 @@ namespace Rubix\ML\Backends; -use Rubix\ML\Backends\Backend; use Rubix\ML\Backends\Tasks\Task; -use Rubix\ML\Encoding; use Rubix\ML\Serializers\Serializer; use Rubix\ML\Serializers\Igbinary; use Rubix\ML\Serializers\Native; use Rubix\ML\Specifications\ExtensionIsLoaded; -use RuntimeException; use Swoole\Atomic; use Swoole\Process; -use Swoole\Process\Pool; -use Swoole\Table; use function Swoole\Coroutine\run; diff --git a/src/Serializers/Igbinary.php b/src/Serializers/Igbinary.php index 7439b965c..2c18ec348 100644 --- a/src/Serializers/Igbinary.php +++ b/src/Serializers/Igbinary.php @@ -84,4 +84,4 @@ public function __toString() : string { return 'Igbinary'; } -} \ No newline at end of file +} From 1d75ce9a8ca418018fe70d7a3c32b237cd9e6826 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Fri, 12 Jan 2024 16:42:58 +0100 Subject: [PATCH 13/18] chore(swoole): remove unnecessary atomics --- src/Backends/Swoole.php | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php index 8c528a183..0c27bcb94 100644 --- a/src/Backends/Swoole.php +++ b/src/Backends/Swoole.php @@ -7,7 +7,6 @@ use Rubix\ML\Serializers\Igbinary; use Rubix\ML\Serializers\Native; use Rubix\ML\Specifications\ExtensionIsLoaded; -use Swoole\Atomic; use Swoole\Process; use function Swoole\Coroutine\run; @@ -22,11 +21,6 @@ */ class Swoole implements Backend { - /** - * Swoole accepts values between 0.2 and 1 - */ - const CONFLICT_PROPORTION = 0.25; - /** * The queue of tasks to be processed in parallel. */ @@ -84,26 +78,14 @@ public function process() : array { $results = []; - $finishedTasksAtomic = new Atomic(); - $waitingAtomic = new Atomic(); - - $scheduledTasksTotal = count($this->queue); $workerProcesses = []; $currentCpu = 0; while (($queueItem = array_shift($this->queue))) { $workerProcess = new Process( - callback: function (Process $worker) use ($finishedTasksAtomic, $queueItem, $scheduledTasksTotal, $waitingAtomic) { - try { - $worker->exportSocket()->send(igbinary_serialize($queueItem())); - } finally { - $finishedTasksAtomic->add(1); - - if ($scheduledTasksTotal <= $finishedTasksAtomic->get()) { - $waitingAtomic->wakeup(); - } - } + callback: function (Process $worker) use ($queueItem) { + $worker->exportSocket()->send(igbinary_serialize($queueItem())); }, enable_coroutine: true, pipe_type: 1, @@ -121,8 +103,6 @@ public function process() : array $currentCpu = ($currentCpu + 1) % $this->cpus; } - $waitingAtomic->wait(-1); - run(function () use (&$results, $workerProcesses) { foreach ($workerProcesses as $workerProcess) { $receivedData = $workerProcess->exportSocket()->recv(); From f2d829a313a1d32df3ef27c3f33319a08324a269 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Fri, 12 Jan 2024 16:46:46 +0100 Subject: [PATCH 14/18] chore(swoole): php backwards compatibility --- src/Backends/Swoole.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php index 0c27bcb94..358e3a17e 100644 --- a/src/Backends/Swoole.php +++ b/src/Backends/Swoole.php @@ -84,17 +84,18 @@ public function process() : array while (($queueItem = array_shift($this->queue))) { $workerProcess = new Process( - callback: function (Process $worker) use ($queueItem) { + function (Process $worker) use ($queueItem) { $worker->exportSocket()->send(igbinary_serialize($queueItem())); }, - enable_coroutine: true, - pipe_type: 1, - redirect_stdin_and_stdout: false, + // redirect_stdin_and_stdout + false, + // pipe_type + SOCK_STREAM, + // enable_coroutine + true, ); - $workerProcess->setAffinity([ - $currentCpu, - ]); + $workerProcess->setAffinity([$currentCpu]); $workerProcess->setBlocking(false); $workerProcess->start(); From cfd31fb2e68225bf4217e3bda67f28c35a0233c4 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 15 Jan 2024 20:25:49 +0100 Subject: [PATCH 15/18] fix: phpstan, socket message size --- benchmarks/Classifiers/OneVsRestBench.php | 10 ++- benchmarks/Classifiers/RandomForestBench.php | 42 +++++---- phpunit.xml | 2 +- src/Backends/Swoole.php | 85 ++++++++++++------ src/Classifiers/LogisticRegression.php | 16 ++++ src/Serializers/Igbinary.php | 87 ------------------- tests/Backends/SwooleTest.php | 2 +- tests/Classifiers/OneVsRestTest.php | 18 ++-- tests/DataProvider/BackendProviderTrait.php | 32 ++++--- .../{SQTableTest.php => SQLTableTest.php} | 0 tests/Transformers/ImageRotatorTest.php | 2 +- 11 files changed, 143 insertions(+), 153 deletions(-) delete mode 100644 src/Serializers/Igbinary.php rename tests/Extractors/{SQTableTest.php => SQLTableTest.php} (100%) diff --git a/benchmarks/Classifiers/OneVsRestBench.php b/benchmarks/Classifiers/OneVsRestBench.php index 2bb8bc319..86fb1de06 100644 --- a/benchmarks/Classifiers/OneVsRestBench.php +++ b/benchmarks/Classifiers/OneVsRestBench.php @@ -2,11 +2,13 @@ namespace Rubix\ML\Benchmarks\Classifiers; +use Rubix\ML\Backends\Backend; use Rubix\ML\Classifiers\OneVsRest; use Rubix\ML\Datasets\Generators\Blob; use Rubix\ML\Classifiers\LogisticRegression; use Rubix\ML\NeuralNet\Optimizers\Stochastic; use Rubix\ML\Datasets\Generators\Agglomerate; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; /** * @Groups({"Classifiers"}) @@ -14,6 +16,8 @@ */ class OneVsRestBench { + use BackendProviderTrait; + protected const TRAINING_SIZE = 10000; protected const TESTING_SIZE = 10000; @@ -52,9 +56,13 @@ public function setUp() : void * @Subject * @Iterations(5) * @OutputTimeUnit("seconds", precision=3) + * @ParamProviders("provideBackends") + * @param array{ backend: Backend } $params */ - public function trainPredict() : void + public function trainPredict(array $params) : void { + $this->estimator->setBackend($params['backend']); + $this->estimator->train($this->training); $this->estimator->predict($this->testing); diff --git a/benchmarks/Classifiers/RandomForestBench.php b/benchmarks/Classifiers/RandomForestBench.php index c1b02b817..95713bfe2 100644 --- a/benchmarks/Classifiers/RandomForestBench.php +++ b/benchmarks/Classifiers/RandomForestBench.php @@ -2,12 +2,12 @@ namespace Rubix\ML\Benchmarks\Classifiers; -use Rubix\ML\Backends\Amp; -use Rubix\ML\Backends\Swoole as SwooleBackend; +use Rubix\ML\Backends\Backend; use Rubix\ML\Classifiers\RandomForest; use Rubix\ML\Datasets\Generators\Blob; use Rubix\ML\Classifiers\ClassificationTree; use Rubix\ML\Datasets\Generators\Agglomerate; +use Rubix\ML\Tests\DataProvider\BackendProviderTrait; use Rubix\ML\Transformers\IntervalDiscretizer; /** @@ -15,6 +15,8 @@ */ class RandomForestBench { + use BackendProviderTrait; + protected const TRAINING_SIZE = 10000; protected const TESTING_SIZE = 10000; @@ -47,8 +49,6 @@ public function setUpContinuous() : void $this->testing = $generator->generate(self::TESTING_SIZE); $this->estimator = new RandomForest(new ClassificationTree(30)); - $this->estimator->setBackend(new SwooleBackend()); - // $this->estimator->setBackend(new Amp()); } public function setUpCategorical() : void @@ -74,24 +74,32 @@ public function setUpCategorical() : void * @Iterations(5) * @BeforeMethods({"setUpContinuous"}) * @OutputTimeUnit("seconds", precision=3) + * @ParamProviders("provideBackends") + * @param array{ backend: Backend } $params */ - public function continuous() : void + public function continuous(array $params) : void { + $this->estimator->setBackend($params['backend']); + $this->estimator->train($this->training); $this->estimator->predict($this->testing); } - // /** - // * @Subject - // * @Iterations(5) - // * @BeforeMethods({"setUpCategorical"}) - // * @OutputTimeUnit("seconds", precision=3) - // */ - // public function categorical() : void - // { - // $this->estimator->train($this->training); - - // $this->estimator->predict($this->testing); - // } + /** + * @Subject + * @Iterations(5) + * @BeforeMethods({"setUpCategorical"}) + * @OutputTimeUnit("seconds", precision=3) + * @ParamProviders("provideBackends") + * @param array{ backend: Backend } $params + */ + public function categorical(array $params) : void + { + $this->estimator->setBackend($params['backend']); + + $this->estimator->train($this->training); + + $this->estimator->predict($this->testing); + } } diff --git a/phpunit.xml b/phpunit.xml index 54289bc72..f2656a836 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,7 +9,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" forceCoversAnnotation="true" - processIsolation="false" + processIsolation="true" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" > diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php index 358e3a17e..65a5ca56a 100644 --- a/src/Backends/Swoole.php +++ b/src/Backends/Swoole.php @@ -3,10 +3,10 @@ namespace Rubix\ML\Backends; use Rubix\ML\Backends\Tasks\Task; -use Rubix\ML\Serializers\Serializer; -use Rubix\ML\Serializers\Igbinary; -use Rubix\ML\Serializers\Native; use Rubix\ML\Specifications\ExtensionIsLoaded; +use Rubix\ML\Specifications\SwooleExtensionIsLoaded; +use RuntimeException; +use Swoole\Atomic; use Swoole\Process; use function Swoole\Coroutine\run; @@ -28,21 +28,14 @@ class Swoole implements Backend private int $cpus; - private Serializer $serializer; + private int $hasIgbinary; - public function __construct(?Serializer $serializer = null) + public function __construct() { - $this->cpus = swoole_cpu_num(); + SwooleExtensionIsLoaded::create()->check(); - if ($serializer) { - $this->serializer = $serializer; - } else { - if (ExtensionIsLoaded::with('igbinary')->passes()) { - $this->serializer = new Igbinary(); - } else { - $this->serializer = new Native(); - } - } + $this->cpus = swoole_cpu_num(); + $this->hasIgbinary = ExtensionIsLoaded::with('igbinary')->passes(); } /** @@ -78,19 +71,29 @@ public function process() : array { $results = []; + $maxMessageLength = new Atomic(0); $workerProcesses = []; $currentCpu = 0; - while (($queueItem = array_shift($this->queue))) { + foreach ($this->queue as $index => $queueItem) { $workerProcess = new Process( - function (Process $worker) use ($queueItem) { - $worker->exportSocket()->send(igbinary_serialize($queueItem())); + function (Process $worker) use ($maxMessageLength, $queueItem) { + $serialized = $this->serialize($queueItem()); + + $serializedLength = strlen($serialized); + $currentMaxSerializedLength = $maxMessageLength->get(); + + if ($serializedLength > $currentMaxSerializedLength) { + $maxMessageLength->set($serializedLength); + } + + $worker->exportSocket()->send($serialized); }, // redirect_stdin_and_stdout false, // pipe_type - SOCK_STREAM, + SOCK_DGRAM, // enable_coroutine true, ); @@ -99,15 +102,29 @@ function (Process $worker) use ($queueItem) { $workerProcess->setBlocking(false); $workerProcess->start(); - $workerProcesses[] = $workerProcess; + $workerProcesses[$index] = $workerProcess; $currentCpu = ($currentCpu + 1) % $this->cpus; } - run(function () use (&$results, $workerProcesses) { - foreach ($workerProcesses as $workerProcess) { - $receivedData = $workerProcess->exportSocket()->recv(); - $unserialized = igbinary_unserialize($receivedData); + run(function () use ($maxMessageLength, &$results, $workerProcesses) { + foreach ($workerProcesses as $index => $workerProcess) { + $status = $workerProcess->wait(); + + if (0 !== $status['code']) { + throw new RuntimeException('Worker process exited with an error'); + } + + $socket = $workerProcess->exportSocket(); + + if ($socket->isClosed()) { + throw new RuntimeException('Coroutine socket is closed'); + } + + $maxMessageLengthValue = $maxMessageLength->get(); + + $receivedData = $socket->recv($maxMessageLengthValue); + $unserialized = $this->unserialize($receivedData); $results[] = $unserialized; } @@ -124,6 +141,24 @@ public function flush() : void $this->queue = []; } + private function serialize(mixed $data) : string + { + if ($this->hasIgbinary) { + return igbinary_serialize($data); + } + + return serialize($data); + } + + private function unserialize(string $serialized) : mixed + { + if ($this->hasIgbinary) { + return igbinary_unserialize($serialized); + } + + return unserialize($serialized); + } + /** * Return the string representation of the object. * @@ -133,6 +168,6 @@ public function flush() : void */ public function __toString() : string { - return 'Swoole\\Process'; + return 'Swoole'; } } diff --git a/src/Classifiers/LogisticRegression.php b/src/Classifiers/LogisticRegression.php index 1626fbb57..d0cac23a8 100644 --- a/src/Classifiers/LogisticRegression.php +++ b/src/Classifiers/LogisticRegression.php @@ -491,4 +491,20 @@ public function __toString() : string { return 'Logistic Regression (' . Params::stringify($this->params()) . ')'; } + + /** + * Without this method, causes errors with Swoole backend + Igbinary + * serialization. + * + * Can be removed if it's no longer the case. + * + * @internal + * @param array $data + */ + public function __unserialize(array $data) : void + { + foreach ($data as $propertyName => $propertyValue) { + $this->{$propertyName} = $propertyValue; + } + } } diff --git a/src/Serializers/Igbinary.php b/src/Serializers/Igbinary.php deleted file mode 100644 index 2c18ec348..000000000 --- a/src/Serializers/Igbinary.php +++ /dev/null @@ -1,87 +0,0 @@ -check(); - } - - /** - * Serialize a persistable object and return the data. - * - * @internal - * - * @param \Rubix\ML\Persistable $persistable - * @throws \Rubix\ML\Exceptions\RuntimeException - * @return \Rubix\ML\Encoding - */ - public function serialize(Persistable $persistable) : Encoding - { - $data = igbinary_serialize($persistable); - - if (!$data) { - throw new RuntimeException('Could not serialize data.'); - } - - return new Encoding($data); - } - - /** - * Deserialize a persistable object and return it. - * - * @internal - * - * @param \Rubix\ML\Encoding $encoding - * @throws \Rubix\ML\Exceptions\RuntimeException - * @return \Rubix\ML\Persistable - */ - public function deserialize(Encoding $encoding) : Persistable - { - $persistable = igbinary_unserialize($encoding); - - if (!is_object($persistable)) { - throw new RuntimeException('deserialized data must be an object.'); - } - - if ($persistable instanceof __PHP_Incomplete_Class) { - throw new RuntimeException('Missing class for object data.'); - } - - if (!$persistable instanceof Persistable) { - throw new RuntimeException('deserialized object must' - . ' implement the Persistable interface.'); - } - - return $persistable; - } - - /** - * Return the string representation of the object. - * - * @return string - */ - public function __toString() : string - { - return 'Igbinary'; - } -} diff --git a/tests/Backends/SwooleTest.php b/tests/Backends/SwooleTest.php index ece9e41a6..60cbf526f 100644 --- a/tests/Backends/SwooleTest.php +++ b/tests/Backends/SwooleTest.php @@ -17,7 +17,7 @@ class SwooleTest extends TestCase { /** - * @var \Rubix\ML\Backends\Swoole\Process + * @var \Rubix\ML\Backends\Swoole */ protected $backend; diff --git a/tests/Classifiers/OneVsRestTest.php b/tests/Classifiers/OneVsRestTest.php index 9b3353218..f52b5066b 100644 --- a/tests/Classifiers/OneVsRestTest.php +++ b/tests/Classifiers/OneVsRestTest.php @@ -162,13 +162,13 @@ public function trainPredictProba(Backend $backend) : void $this->assertGreaterThanOrEqual(self::MIN_SCORE, $score); } - /** - * @test - */ - public function predictUntrained() : void - { - $this->expectException(RuntimeException::class); - - $this->estimator->predict(Unlabeled::quick()); - } + // /** + // * @test + // */ + // public function predictUntrained() : void + // { + // $this->expectException(RuntimeException::class); + + // $this->estimator->predict(Unlabeled::quick()); + // } } diff --git a/tests/DataProvider/BackendProviderTrait.php b/tests/DataProvider/BackendProviderTrait.php index f33d72a6a..08851742f 100644 --- a/tests/DataProvider/BackendProviderTrait.php +++ b/tests/DataProvider/BackendProviderTrait.php @@ -2,32 +2,42 @@ namespace Rubix\ML\Tests\DataProvider; +use Generator; use Rubix\ML\Backends\Backend; use Rubix\ML\Backends\Serial; use Rubix\ML\Backends\Amp; use Rubix\ML\Backends\Swoole; +use Rubix\ML\Specifications\ExtensionIsLoaded; use Rubix\ML\Specifications\SwooleExtensionIsLoaded; trait BackendProviderTrait { /** - * @return array + * @return Generator> */ - public static function provideBackends() : array + public static function provideBackends() : Generator { - $backends = []; - $serialBackend = new Serial(); - $backends[(string) $serialBackend] = [$serialBackend]; - $ampBackend = new Amp(); - $backends[(string) $ampBackend] = [$ampBackend]; + yield (string) $serialBackend => [ + 'backend' => $serialBackend, + ]; + + // $ampBackend = new Amp(); + + // yield (string) $ampBackend => [ + // 'backend' => $ampBackend, + // ]; - if (SwooleExtensionIsLoaded::create()->passes()) { + if ( + SwooleExtensionIsLoaded::create()->passes() + && ExtensionIsLoaded::with('igbinary')->passes() + ) { $swooleProcessBackend = new Swoole(); - $backends[(string) $swooleProcessBackend] = [$swooleProcessBackend]; - } - return $backends; + yield (string) $swooleProcessBackend => [ + 'backend' => $swooleProcessBackend, + ]; + } } } diff --git a/tests/Extractors/SQTableTest.php b/tests/Extractors/SQLTableTest.php similarity index 100% rename from tests/Extractors/SQTableTest.php rename to tests/Extractors/SQLTableTest.php diff --git a/tests/Transformers/ImageRotatorTest.php b/tests/Transformers/ImageRotatorTest.php index ef63b5d68..2ea9004ac 100644 --- a/tests/Transformers/ImageRotatorTest.php +++ b/tests/Transformers/ImageRotatorTest.php @@ -12,7 +12,7 @@ * @requires extension gd * @covers \Rubix\ML\Transformers\ImageRotator */ -class RandomizedImageRotatorTest extends TestCase +class ImageRotatorTest extends TestCase { /** * @var \Rubix\ML\Transformers\ImageRotator From 703404b979215273cfca2de6f67da735a6883ed7 Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Mon, 15 Jan 2024 20:27:25 +0100 Subject: [PATCH 16/18] fix: uncomment test --- tests/Classifiers/OneVsRestTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Classifiers/OneVsRestTest.php b/tests/Classifiers/OneVsRestTest.php index f52b5066b..9b3353218 100644 --- a/tests/Classifiers/OneVsRestTest.php +++ b/tests/Classifiers/OneVsRestTest.php @@ -162,13 +162,13 @@ public function trainPredictProba(Backend $backend) : void $this->assertGreaterThanOrEqual(self::MIN_SCORE, $score); } - // /** - // * @test - // */ - // public function predictUntrained() : void - // { - // $this->expectException(RuntimeException::class); - - // $this->estimator->predict(Unlabeled::quick()); - // } + /** + * @test + */ + public function predictUntrained() : void + { + $this->expectException(RuntimeException::class); + + $this->estimator->predict(Unlabeled::quick()); + } } From cb1ee71360ba19c85b7e0509bd85204f39977dff Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Wed, 24 Jan 2024 19:44:59 +0100 Subject: [PATCH 17/18] style: composer fix --- src/AnomalyDetectors/LocalOutlierFactor.php | 2 +- src/AnomalyDetectors/Loda.php | 2 +- src/AnomalyDetectors/OneClassSVM.php | 4 ++-- src/Backends/Swoole.php | 2 +- src/BootstrapAggregator.php | 2 +- src/Classifiers/AdaBoost.php | 2 +- src/Classifiers/KDNeighbors.php | 2 +- src/Classifiers/KNearestNeighbors.php | 2 +- src/Classifiers/LogisticRegression.php | 6 +++--- src/Classifiers/LogitBoost.php | 4 ++-- src/Classifiers/MultilayerPerceptron.php | 8 ++++---- src/Classifiers/OneVsRest.php | 2 +- src/Classifiers/RadiusNeighbors.php | 2 +- src/Classifiers/RandomForest.php | 2 +- src/Classifiers/SoftmaxClassifier.php | 6 +++--- src/Clusterers/DBSCAN.php | 2 +- src/Clusterers/FuzzyCMeans.php | 4 ++-- src/Clusterers/GaussianMixture.php | 2 +- src/Clusterers/KMeans.php | 4 ++-- src/Clusterers/MeanShift.php | 4 ++-- src/Clusterers/Seeders/KMC2.php | 2 +- src/Clusterers/Seeders/PlusPlus.php | 2 +- src/Datasets/Generators/Blob.php | 2 +- src/Datasets/Generators/Circle.php | 2 +- src/Datasets/Generators/HalfMoon.php | 2 +- src/Datasets/Generators/Hyperplane.php | 2 +- src/Datasets/Generators/SwissRoll.php | 2 +- src/Extractors/SQLTable.php | 2 +- src/Graph/Nodes/Clique.php | 2 +- src/Graph/Nodes/Neighborhood.php | 2 +- src/Graph/Nodes/Traits/HasBinaryChildrenTrait.php | 4 ++-- src/Graph/Trees/BallTree.php | 4 ++-- src/Graph/Trees/DecisionTree.php | 2 +- src/Graph/Trees/ITree.php | 2 +- src/Graph/Trees/KDTree.php | 4 ++-- src/GridSearch.php | 6 +++--- src/NeuralNet/FeedForward.php | 6 +++--- src/NeuralNet/Layers/Activation.php | 6 +++--- src/NeuralNet/Layers/BatchNorm.php | 10 +++++----- src/NeuralNet/Layers/Binary.php | 8 ++++---- src/NeuralNet/Layers/Continuous.php | 4 ++-- src/NeuralNet/Layers/Dense.php | 10 +++++----- src/NeuralNet/Layers/Dropout.php | 2 +- src/NeuralNet/Layers/Multiclass.php | 8 ++++---- src/NeuralNet/Layers/PReLU.php | 6 +++--- src/NeuralNet/Layers/Swish.php | 10 +++++----- src/NeuralNet/Parameter.php | 2 +- src/PersistentModel.php | 6 +++--- src/Pipeline.php | 2 +- src/Regressors/Adaline.php | 6 +++--- src/Regressors/GradientBoost.php | 4 ++-- src/Regressors/KDNeighborsRegressor.php | 2 +- src/Regressors/KNNRegressor.php | 2 +- src/Regressors/MLPRegressor.php | 8 ++++---- src/Regressors/RadiusNeighborsRegressor.php | 2 +- src/Regressors/Ridge.php | 2 +- src/Regressors/SVR.php | 4 ++-- src/Serializers/GzipNative.php | 2 +- src/Serializers/RBX.php | 2 +- src/Specifications/DatasetHasDimensionality.php | 2 +- src/Specifications/DatasetIsLabeled.php | 2 +- src/Specifications/DatasetIsNotEmpty.php | 2 +- src/Specifications/EstimatorIsCompatibleWithMetric.php | 4 ++-- src/Specifications/LabelsAreCompatibleWithLearner.php | 4 ++-- .../SamplesAreCompatibleWithDistance.php | 4 ++-- .../SamplesAreCompatibleWithEstimator.php | 4 ++-- .../SamplesAreCompatibleWithTransformer.php | 4 ++-- src/Specifications/SwooleExtensionIsLoaded.php | 2 +- src/Tokenizers/KSkipNGram.php | 4 ++-- src/Tokenizers/NGram.php | 4 ++-- src/Traits/LoggerAware.php | 2 +- src/Traits/Multiprocessing.php | 2 +- src/Transformers/GaussianRandomProjector.php | 2 +- src/Transformers/HotDeckImputer.php | 2 +- src/Transformers/KNNImputer.php | 2 +- src/Transformers/LinearDiscriminantAnalysis.php | 2 +- src/Transformers/MissingDataImputer.php | 4 ++-- src/Transformers/PrincipalComponentAnalysis.php | 2 +- src/Transformers/TSNE.php | 2 +- src/Transformers/TokenHashingVectorizer.php | 2 +- src/Transformers/TruncatedSVD.php | 2 +- src/Transformers/WordCountVectorizer.php | 2 +- tests/Backends/SwooleTest.php | 2 +- tests/Graph/Nodes/NeighborhoodTest.php | 2 +- tests/NeuralNet/ParameterTest.php | 2 +- tests/Transformers/ImageRotatorTest.php | 2 +- 86 files changed, 145 insertions(+), 145 deletions(-) diff --git a/src/AnomalyDetectors/LocalOutlierFactor.php b/src/AnomalyDetectors/LocalOutlierFactor.php index 4ebda0f00..5c798b4b6 100644 --- a/src/AnomalyDetectors/LocalOutlierFactor.php +++ b/src/AnomalyDetectors/LocalOutlierFactor.php @@ -67,7 +67,7 @@ class LocalOutlierFactor implements Estimator, Learner, Scoring, Persistable * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * The precomputed k distances between each training sample and its k'th nearest neighbor. diff --git a/src/AnomalyDetectors/Loda.php b/src/AnomalyDetectors/Loda.php index f06b9a4a7..cf76762e3 100644 --- a/src/AnomalyDetectors/Loda.php +++ b/src/AnomalyDetectors/Loda.php @@ -100,7 +100,7 @@ class Loda implements Estimator, Learner, Online, Scoring, Persistable * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $r = null; + protected ?Matrix $r = null; /** * The edges and bin counts of each histogram. diff --git a/src/AnomalyDetectors/OneClassSVM.php b/src/AnomalyDetectors/OneClassSVM.php index faf1111be..10969ab6f 100644 --- a/src/AnomalyDetectors/OneClassSVM.php +++ b/src/AnomalyDetectors/OneClassSVM.php @@ -44,7 +44,7 @@ class OneClassSVM implements Estimator, Learner * * @var svm */ - protected \svm $svm; + protected svm $svm; /** * The hyper-parameters of the model. @@ -58,7 +58,7 @@ class OneClassSVM implements Estimator, Learner * * @var \svmmodel|null */ - protected ?\svmmodel $model = null; + protected ?svmmodel $model = null; /** * @param float $nu diff --git a/src/Backends/Swoole.php b/src/Backends/Swoole.php index 65a5ca56a..34eb894b8 100644 --- a/src/Backends/Swoole.php +++ b/src/Backends/Swoole.php @@ -43,7 +43,7 @@ public function __construct() * * @internal * - * @param \Rubix\ML\Backends\Tasks\Task $task + * @param Task $task * @param callable(mixed,mixed):void $after * @param mixed $context */ diff --git a/src/BootstrapAggregator.php b/src/BootstrapAggregator.php index 742dcc6ab..fc30cc882 100644 --- a/src/BootstrapAggregator.php +++ b/src/BootstrapAggregator.php @@ -64,7 +64,7 @@ class BootstrapAggregator implements Estimator, Learner, Parallel, Persistable * * @var Learner */ - protected \Rubix\ML\Learner $base; + protected Learner $base; /** * The number of base learners to train in the ensemble. diff --git a/src/Classifiers/AdaBoost.php b/src/Classifiers/AdaBoost.php index 4f428c5f4..9c74fbd7a 100644 --- a/src/Classifiers/AdaBoost.php +++ b/src/Classifiers/AdaBoost.php @@ -72,7 +72,7 @@ class AdaBoost implements Estimator, Learner, Probabilistic, Verbose, Persistabl * * @var Learner */ - protected \Rubix\ML\Learner $base; + protected Learner $base; /** * The learning rate of the ensemble i.e. the *shrinkage* applied to each step. diff --git a/src/Classifiers/KDNeighbors.php b/src/Classifiers/KDNeighbors.php index 642b64e16..4ef9f5864 100644 --- a/src/Classifiers/KDNeighbors.php +++ b/src/Classifiers/KDNeighbors.php @@ -60,7 +60,7 @@ class KDNeighbors implements Estimator, Learner, Probabilistic, Persistable * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * The zero vector for the possible class outcomes. diff --git a/src/Classifiers/KNearestNeighbors.php b/src/Classifiers/KNearestNeighbors.php index d5293c932..ee5c4b39b 100644 --- a/src/Classifiers/KNearestNeighbors.php +++ b/src/Classifiers/KNearestNeighbors.php @@ -62,7 +62,7 @@ class KNearestNeighbors implements Estimator, Learner, Online, Probabilistic, Pe * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * The zero vector for the possible class outcomes. diff --git a/src/Classifiers/LogisticRegression.php b/src/Classifiers/LogisticRegression.php index ffa291a84..81eef3ac3 100644 --- a/src/Classifiers/LogisticRegression.php +++ b/src/Classifiers/LogisticRegression.php @@ -67,7 +67,7 @@ class LogisticRegression implements Estimator, Learner, Online, Probabilistic, R * * @var Optimizer */ - protected \Rubix\ML\NeuralNet\Optimizers\Optimizer $optimizer; + protected Optimizer $optimizer; /** * The amount of L2 regularization applied to the weights of the output layer. @@ -103,14 +103,14 @@ class LogisticRegression implements Estimator, Learner, Online, Probabilistic, R * * @var ClassificationLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\ClassificationLoss $costFn; + protected ClassificationLoss $costFn; /** * The underlying neural network instance. * * @var \Rubix\ML\NeuralNet\FeedForward|null */ - protected ?\Rubix\ML\NeuralNet\FeedForward $network = null; + protected ?FeedForward $network = null; /** * The unique class labels. diff --git a/src/Classifiers/LogitBoost.php b/src/Classifiers/LogitBoost.php index 071dfed39..f12588cfb 100644 --- a/src/Classifiers/LogitBoost.php +++ b/src/Classifiers/LogitBoost.php @@ -89,7 +89,7 @@ class LogitBoost implements Estimator, Learner, Probabilistic, RanksFeatures, Ve * * @var Learner */ - protected \Rubix\ML\Learner $booster; + protected Learner $booster; /** * The learning rate of the ensemble i.e. the *shrinkage* applied to each step. @@ -138,7 +138,7 @@ class LogitBoost implements Estimator, Learner, Probabilistic, RanksFeatures, Ve * * @var Metric */ - protected \Rubix\ML\CrossValidation\Metrics\Metric $metric; + protected Metric $metric; /** * The ensemble of boosters. diff --git a/src/Classifiers/MultilayerPerceptron.php b/src/Classifiers/MultilayerPerceptron.php index 1018d10c4..233c8b1eb 100644 --- a/src/Classifiers/MultilayerPerceptron.php +++ b/src/Classifiers/MultilayerPerceptron.php @@ -85,7 +85,7 @@ class MultilayerPerceptron implements Estimator, Learner, Online, Probabilistic, * * @var Optimizer */ - protected \Rubix\ML\NeuralNet\Optimizers\Optimizer $optimizer; + protected Optimizer $optimizer; /** * The amount of L2 regularization applied to the weights of the output layer. @@ -127,21 +127,21 @@ class MultilayerPerceptron implements Estimator, Learner, Online, Probabilistic, * * @var ClassificationLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\ClassificationLoss $costFn; + protected ClassificationLoss $costFn; /** * The validation metric used to score the generalization performance of the model during training. * * @var Metric */ - protected \Rubix\ML\CrossValidation\Metrics\Metric $metric; + protected Metric $metric; /** * The underlying neural network instance. * * @var \Rubix\ML\NeuralNet\FeedForward|null */ - protected ?\Rubix\ML\NeuralNet\FeedForward $network = null; + protected ?FeedForward $network = null; /** * The unique class labels. diff --git a/src/Classifiers/OneVsRest.php b/src/Classifiers/OneVsRest.php index 7c07e2627..841fb2751 100644 --- a/src/Classifiers/OneVsRest.php +++ b/src/Classifiers/OneVsRest.php @@ -51,7 +51,7 @@ class OneVsRest implements Estimator, Learner, Probabilistic, Parallel, Persista * * @var Learner */ - protected \Rubix\ML\Learner $base; + protected Learner $base; /** * A map of each class to its binary classifier. diff --git a/src/Classifiers/RadiusNeighbors.php b/src/Classifiers/RadiusNeighbors.php index b1e3544c9..1dc670186 100644 --- a/src/Classifiers/RadiusNeighbors.php +++ b/src/Classifiers/RadiusNeighbors.php @@ -60,7 +60,7 @@ class RadiusNeighbors implements Estimator, Learner, Probabilistic, Persistable * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * The class label for any samples that have 0 neighbors within the specified radius. diff --git a/src/Classifiers/RandomForest.php b/src/Classifiers/RandomForest.php index 5d2b8d5cb..eb62f5e32 100644 --- a/src/Classifiers/RandomForest.php +++ b/src/Classifiers/RandomForest.php @@ -73,7 +73,7 @@ class RandomForest implements Estimator, Learner, Probabilistic, Parallel, Ranks * * @var Learner */ - protected \Rubix\ML\Learner $base; + protected Learner $base; /** * The number of learners to train in the ensemble. diff --git a/src/Classifiers/SoftmaxClassifier.php b/src/Classifiers/SoftmaxClassifier.php index 998035701..3038c04a3 100644 --- a/src/Classifiers/SoftmaxClassifier.php +++ b/src/Classifiers/SoftmaxClassifier.php @@ -64,7 +64,7 @@ class SoftmaxClassifier implements Estimator, Learner, Online, Probabilistic, Ve * * @var Optimizer */ - protected \Rubix\ML\NeuralNet\Optimizers\Optimizer $optimizer; + protected Optimizer $optimizer; /** * The amount of L2 regularization applied to the weights of the output layer. @@ -99,14 +99,14 @@ class SoftmaxClassifier implements Estimator, Learner, Online, Probabilistic, Ve * * @var ClassificationLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\ClassificationLoss $costFn; + protected ClassificationLoss $costFn; /** * The underlying neural network instance. * * @var \Rubix\ML\NeuralNet\FeedForward|null */ - protected ?\Rubix\ML\NeuralNet\FeedForward $network = null; + protected ?FeedForward $network = null; /** * The unique class labels. diff --git a/src/Clusterers/DBSCAN.php b/src/Clusterers/DBSCAN.php index 44112e02a..c24546d37 100644 --- a/src/Clusterers/DBSCAN.php +++ b/src/Clusterers/DBSCAN.php @@ -73,7 +73,7 @@ class DBSCAN implements Estimator * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * @param float $radius diff --git a/src/Clusterers/FuzzyCMeans.php b/src/Clusterers/FuzzyCMeans.php index 49d5716ff..dd3b27b84 100644 --- a/src/Clusterers/FuzzyCMeans.php +++ b/src/Clusterers/FuzzyCMeans.php @@ -92,14 +92,14 @@ class FuzzyCMeans implements Estimator, Learner, Probabilistic, Verbose, Persist * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * The cluster centroid seeder. * * @var Seeder */ - protected \Rubix\ML\Clusterers\Seeders\Seeder $seeder; + protected Seeder $seeder; /** * The computed centroid vectors of the training data. diff --git a/src/Clusterers/GaussianMixture.php b/src/Clusterers/GaussianMixture.php index 4445d0422..68338cfd9 100644 --- a/src/Clusterers/GaussianMixture.php +++ b/src/Clusterers/GaussianMixture.php @@ -97,7 +97,7 @@ class GaussianMixture implements Estimator, Learner, Probabilistic, Verbose, Per * * @var Seeder */ - protected \Rubix\ML\Clusterers\Seeders\Seeder $seeder; + protected Seeder $seeder; /** * The precomputed log prior probabilities of each cluster. diff --git a/src/Clusterers/KMeans.php b/src/Clusterers/KMeans.php index 852b178c4..280e70922 100644 --- a/src/Clusterers/KMeans.php +++ b/src/Clusterers/KMeans.php @@ -96,14 +96,14 @@ class KMeans implements Estimator, Learner, Online, Probabilistic, Verbose, Pers * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * The cluster centroid seeder. * * @var Seeder */ - protected \Rubix\ML\Clusterers\Seeders\Seeder $seeder; + protected Seeder $seeder; /** * The computed centroid vectors of the training data. diff --git a/src/Clusterers/MeanShift.php b/src/Clusterers/MeanShift.php index 0d89ce00f..97af51353 100644 --- a/src/Clusterers/MeanShift.php +++ b/src/Clusterers/MeanShift.php @@ -104,14 +104,14 @@ class MeanShift implements Estimator, Learner, Probabilistic, Verbose, Persistab * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * The cluster centroid seeder. * * @var Seeder */ - protected \Rubix\ML\Clusterers\Seeders\Seeder $seeder; + protected Seeder $seeder; /** * The computed centroid vectors of the training data. diff --git a/src/Clusterers/Seeders/KMC2.php b/src/Clusterers/Seeders/KMC2.php index d4e155e5e..717a29426 100644 --- a/src/Clusterers/Seeders/KMC2.php +++ b/src/Clusterers/Seeders/KMC2.php @@ -39,7 +39,7 @@ class KMC2 implements Seeder * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * @param int $m diff --git a/src/Clusterers/Seeders/PlusPlus.php b/src/Clusterers/Seeders/PlusPlus.php index ad4f82e24..4a59d98b4 100644 --- a/src/Clusterers/Seeders/PlusPlus.php +++ b/src/Clusterers/Seeders/PlusPlus.php @@ -32,7 +32,7 @@ class PlusPlus implements Seeder * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * @param \Rubix\ML\Kernels\Distance\Distance|null $kernel diff --git a/src/Datasets/Generators/Blob.php b/src/Datasets/Generators/Blob.php index 994d6fa52..62f703ae6 100644 --- a/src/Datasets/Generators/Blob.php +++ b/src/Datasets/Generators/Blob.php @@ -32,7 +32,7 @@ class Blob implements Generator * * @var Vector */ - protected \Tensor\Vector $center; + protected Vector $center; /** * The standard deviation of the blob. diff --git a/src/Datasets/Generators/Circle.php b/src/Datasets/Generators/Circle.php index d0a5ee14c..aed785d65 100644 --- a/src/Datasets/Generators/Circle.php +++ b/src/Datasets/Generators/Circle.php @@ -27,7 +27,7 @@ class Circle implements Generator * * @var Vector */ - protected \Tensor\Vector $center; + protected Vector $center; /** * The scaling factor of the circle. diff --git a/src/Datasets/Generators/HalfMoon.php b/src/Datasets/Generators/HalfMoon.php index 26486240e..e41a4a265 100644 --- a/src/Datasets/Generators/HalfMoon.php +++ b/src/Datasets/Generators/HalfMoon.php @@ -26,7 +26,7 @@ class HalfMoon implements Generator * * @var Vector */ - protected \Tensor\Vector $center; + protected Vector $center; /** * The scaling factor of the half moon. diff --git a/src/Datasets/Generators/Hyperplane.php b/src/Datasets/Generators/Hyperplane.php index 8afa59934..a5ae532bc 100644 --- a/src/Datasets/Generators/Hyperplane.php +++ b/src/Datasets/Generators/Hyperplane.php @@ -27,7 +27,7 @@ class Hyperplane implements Generator * * @var Vector */ - protected \Tensor\Vector $coefficients; + protected Vector $coefficients; /** * The y intercept term. diff --git a/src/Datasets/Generators/SwissRoll.php b/src/Datasets/Generators/SwissRoll.php index 8cd017ffa..f0899a284 100644 --- a/src/Datasets/Generators/SwissRoll.php +++ b/src/Datasets/Generators/SwissRoll.php @@ -33,7 +33,7 @@ class SwissRoll implements Generator * * @var Vector */ - protected \Tensor\Vector $center; + protected Vector $center; /** * The scaling factor of the swiss roll. diff --git a/src/Extractors/SQLTable.php b/src/Extractors/SQLTable.php index 4d2b8ed5f..50359addf 100644 --- a/src/Extractors/SQLTable.php +++ b/src/Extractors/SQLTable.php @@ -30,7 +30,7 @@ class SQLTable implements Extractor * * @var PDO */ - protected \PDO $connection; + protected PDO $connection; /** * The name of the table to select from. diff --git a/src/Graph/Nodes/Clique.php b/src/Graph/Nodes/Clique.php index 8b6dedd45..169c023a0 100644 --- a/src/Graph/Nodes/Clique.php +++ b/src/Graph/Nodes/Clique.php @@ -26,7 +26,7 @@ class Clique implements Hypersphere, BinaryNode * * @var Labeled */ - protected \Rubix\ML\Datasets\Labeled $dataset; + protected Labeled $dataset; /** * The centroid or multivariate mean of the cluster. diff --git a/src/Graph/Nodes/Neighborhood.php b/src/Graph/Nodes/Neighborhood.php index 9fce001f2..688f892fd 100644 --- a/src/Graph/Nodes/Neighborhood.php +++ b/src/Graph/Nodes/Neighborhood.php @@ -24,7 +24,7 @@ class Neighborhood implements Hypercube, BinaryNode * * @var Labeled */ - protected \Rubix\ML\Datasets\Labeled $dataset; + protected Labeled $dataset; /** * The multivariate minimum of the bounding box. diff --git a/src/Graph/Nodes/Traits/HasBinaryChildrenTrait.php b/src/Graph/Nodes/Traits/HasBinaryChildrenTrait.php index a0c08a4c4..76aa8f484 100644 --- a/src/Graph/Nodes/Traits/HasBinaryChildrenTrait.php +++ b/src/Graph/Nodes/Traits/HasBinaryChildrenTrait.php @@ -23,14 +23,14 @@ trait HasBinaryChildrenTrait * * @var \Rubix\ML\Graph\Nodes\BinaryNode|null */ - protected ?\Rubix\ML\Graph\Nodes\BinaryNode $left = null; + protected ?BinaryNode $left = null; /** * The right child node. * * @var \Rubix\ML\Graph\Nodes\BinaryNode|null */ - protected ?\Rubix\ML\Graph\Nodes\BinaryNode $right = null; + protected ?BinaryNode $right = null; /** * Return the children of this node in a generator. diff --git a/src/Graph/Trees/BallTree.php b/src/Graph/Trees/BallTree.php index f6e02d029..8194e779a 100644 --- a/src/Graph/Trees/BallTree.php +++ b/src/Graph/Trees/BallTree.php @@ -47,14 +47,14 @@ class BallTree implements BinaryTree, Spatial * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * The root node of the tree. * * @var \Rubix\ML\Graph\Nodes\Ball|null */ - protected ?\Rubix\ML\Graph\Nodes\Ball $root = null; + protected ?Ball $root = null; /** * @param int $maxLeafSize diff --git a/src/Graph/Trees/DecisionTree.php b/src/Graph/Trees/DecisionTree.php index 5c98f0e44..63be69730 100644 --- a/src/Graph/Trees/DecisionTree.php +++ b/src/Graph/Trees/DecisionTree.php @@ -67,7 +67,7 @@ abstract class DecisionTree implements BinaryTree, IteratorAggregate * * @var \Rubix\ML\Graph\Nodes\Split|null */ - protected ?\Rubix\ML\Graph\Nodes\Split $root = null; + protected ?Split $root = null; /** * The number of feature columns in the training set. diff --git a/src/Graph/Trees/ITree.php b/src/Graph/Trees/ITree.php index d44883033..23df4e8d7 100644 --- a/src/Graph/Trees/ITree.php +++ b/src/Graph/Trees/ITree.php @@ -43,7 +43,7 @@ class ITree implements BinaryTree * * @var \Rubix\ML\Graph\Nodes\Isolator|null */ - protected ?\Rubix\ML\Graph\Nodes\Isolator $root = null; + protected ?Isolator $root = null; /** * @param int $maxHeight diff --git a/src/Graph/Trees/KDTree.php b/src/Graph/Trees/KDTree.php index 20174695d..737b075be 100644 --- a/src/Graph/Trees/KDTree.php +++ b/src/Graph/Trees/KDTree.php @@ -46,14 +46,14 @@ class KDTree implements BinaryTree, Spatial * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * The root node of the tree. * * @var \Rubix\ML\Graph\Nodes\Box|null */ - protected ?\Rubix\ML\Graph\Nodes\Box $root = null; + protected ?Box $root = null; /** * @param int $maxLeafSize diff --git a/src/GridSearch.php b/src/GridSearch.php index 42ab7f3a3..71adcb361 100644 --- a/src/GridSearch.php +++ b/src/GridSearch.php @@ -62,21 +62,21 @@ class GridSearch implements Estimator, Learner, Parallel, Verbose, Persistable * * @var Metric */ - protected \Rubix\ML\CrossValidation\Metrics\Metric $metric; + protected Metric $metric; /** * The validator used to test the estimator. * * @var Validator */ - protected \Rubix\ML\CrossValidation\Validator $validator; + protected Validator $validator; /** * The base estimator instance. * * @var Learner */ - protected \Rubix\ML\Learner $base; + protected Learner $base; /** * The validation scores obtained from the last search. diff --git a/src/NeuralNet/FeedForward.php b/src/NeuralNet/FeedForward.php index 957824c8c..af12139d7 100644 --- a/src/NeuralNet/FeedForward.php +++ b/src/NeuralNet/FeedForward.php @@ -34,7 +34,7 @@ class FeedForward implements Network * * @var Input */ - protected \Rubix\ML\NeuralNet\Layers\Input $input; + protected Input $input; /** * The hidden layers of the network. @@ -59,14 +59,14 @@ class FeedForward implements Network * * @var Output */ - protected \Rubix\ML\NeuralNet\Layers\Output $output; + protected Output $output; /** * The gradient descent optimizer used to train the network. * * @var Optimizer */ - protected \Rubix\ML\NeuralNet\Optimizers\Optimizer $optimizer; + protected Optimizer $optimizer; /** * @param Input $input diff --git a/src/NeuralNet/Layers/Activation.php b/src/NeuralNet/Layers/Activation.php index f0370f49e..29b5f37c2 100644 --- a/src/NeuralNet/Layers/Activation.php +++ b/src/NeuralNet/Layers/Activation.php @@ -25,7 +25,7 @@ class Activation implements Hidden * * @var ActivationFunction */ - protected \Rubix\ML\NeuralNet\ActivationFunctions\ActivationFunction $activationFn; + protected ActivationFunction $activationFn; /** * The width of the layer. @@ -39,14 +39,14 @@ class Activation implements Hidden * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $input = null; + protected ?Matrix $input = null; /** * The memorized activation matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $output = null; + protected ?Matrix $output = null; /** * @param ActivationFunction $activationFn diff --git a/src/NeuralNet/Layers/BatchNorm.php b/src/NeuralNet/Layers/BatchNorm.php index bc720dc68..d1a8e8631 100644 --- a/src/NeuralNet/Layers/BatchNorm.php +++ b/src/NeuralNet/Layers/BatchNorm.php @@ -45,14 +45,14 @@ class BatchNorm implements Hidden, Parametric * * @var Initializer */ - protected \Rubix\ML\NeuralNet\Initializers\Initializer $betaInitializer; + protected Initializer $betaInitializer; /** * The initializer for the gamma parameter. * * @var Initializer */ - protected \Rubix\ML\NeuralNet\Initializers\Initializer $gammaInitializer; + protected Initializer $gammaInitializer; /** * The width of the layer. i.e. the number of neurons. @@ -66,14 +66,14 @@ class BatchNorm implements Hidden, Parametric * * @var \Rubix\ML\NeuralNet\Parameter|null */ - protected ?\Rubix\ML\NeuralNet\Parameter $beta = null; + protected ?Parameter $beta = null; /** * The learnable scaling parameter. * * @var \Rubix\ML\NeuralNet\Parameter|null */ - protected ?\Rubix\ML\NeuralNet\Parameter $gamma = null; + protected ?Parameter $gamma = null; /** * The running mean of each input dimension. @@ -101,7 +101,7 @@ class BatchNorm implements Hidden, Parametric * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $xHat = null; + protected ?Matrix $xHat = null; /** * @param float $decay diff --git a/src/NeuralNet/Layers/Binary.php b/src/NeuralNet/Layers/Binary.php index fdd3d9807..109231823 100644 --- a/src/NeuralNet/Layers/Binary.php +++ b/src/NeuralNet/Layers/Binary.php @@ -41,28 +41,28 @@ class Binary implements Output * * @var ClassificationLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\ClassificationLoss $costFn; + protected ClassificationLoss $costFn; /** * The sigmoid activation function. * * @var Sigmoid */ - protected \Rubix\ML\NeuralNet\ActivationFunctions\Sigmoid $sigmoid; + protected Sigmoid $sigmoid; /** * The memorized input matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $input = null; + protected ?Matrix $input = null; /** * The memorized activation matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $output = null; + protected ?Matrix $output = null; /** * @param string[] $classes diff --git a/src/NeuralNet/Layers/Continuous.php b/src/NeuralNet/Layers/Continuous.php index b5be4fe29..938c0900a 100644 --- a/src/NeuralNet/Layers/Continuous.php +++ b/src/NeuralNet/Layers/Continuous.php @@ -28,14 +28,14 @@ class Continuous implements Output * * @var RegressionLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\RegressionLoss $costFn; + protected RegressionLoss $costFn; /** * The memorized input matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $input = null; + protected ?Matrix $input = null; /** * @param \Rubix\ML\NeuralNet\CostFunctions\RegressionLoss|null $costFn diff --git a/src/NeuralNet/Layers/Dense.php b/src/NeuralNet/Layers/Dense.php index 677e1f942..4bcfcb0bb 100644 --- a/src/NeuralNet/Layers/Dense.php +++ b/src/NeuralNet/Layers/Dense.php @@ -54,35 +54,35 @@ class Dense implements Hidden, Parametric * * @var Initializer */ - protected \Rubix\ML\NeuralNet\Initializers\Initializer $weightInitializer; + protected Initializer $weightInitializer; /** * The bias initializer. * * @var Initializer */ - protected \Rubix\ML\NeuralNet\Initializers\Initializer $biasInitializer; + protected Initializer $biasInitializer; /** * The weights. * * @var \Rubix\ML\NeuralNet\Parameter|null */ - protected ?\Rubix\ML\NeuralNet\Parameter $weights = null; + protected ?Parameter $weights = null; /** * The biases. * * @var \Rubix\ML\NeuralNet\Parameter|null */ - protected ?\Rubix\ML\NeuralNet\Parameter $biases = null; + protected ?Parameter $biases = null; /** * The memorized inputs to the layer. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $input = null; + protected ?Matrix $input = null; /** * @param int $neurons diff --git a/src/NeuralNet/Layers/Dropout.php b/src/NeuralNet/Layers/Dropout.php index ee8a9585c..3f888dbda 100644 --- a/src/NeuralNet/Layers/Dropout.php +++ b/src/NeuralNet/Layers/Dropout.php @@ -52,7 +52,7 @@ class Dropout implements Hidden * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $mask = null; + protected ?Matrix $mask = null; /** * @param float $ratio diff --git a/src/NeuralNet/Layers/Multiclass.php b/src/NeuralNet/Layers/Multiclass.php index 9415e7e08..f5073d2e9 100644 --- a/src/NeuralNet/Layers/Multiclass.php +++ b/src/NeuralNet/Layers/Multiclass.php @@ -41,28 +41,28 @@ class Multiclass implements Output * * @var ClassificationLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\ClassificationLoss $costFn; + protected ClassificationLoss $costFn; /** * The softmax activation function. * * @var Softmax */ - protected \Rubix\ML\NeuralNet\ActivationFunctions\Softmax $softmax; + protected Softmax $softmax; /** * The memorized input matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $input = null; + protected ?Matrix $input = null; /** * The memorized activation matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $output = null; + protected ?Matrix $output = null; /** * @param string[] $classes diff --git a/src/NeuralNet/Layers/PReLU.php b/src/NeuralNet/Layers/PReLU.php index e208703c9..c90eda9d9 100644 --- a/src/NeuralNet/Layers/PReLU.php +++ b/src/NeuralNet/Layers/PReLU.php @@ -32,7 +32,7 @@ class PReLU implements Hidden, Parametric * * @var Initializer */ - protected \Rubix\ML\NeuralNet\Initializers\Initializer $initializer; + protected Initializer $initializer; /** * The width of the layer. @@ -46,14 +46,14 @@ class PReLU implements Hidden, Parametric * * @var \Rubix\ML\NeuralNet\Parameter|null */ - protected ?\Rubix\ML\NeuralNet\Parameter $alpha = null; + protected ?Parameter $alpha = null; /** * The memoized input matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $input = null; + protected ?Matrix $input = null; /** * @param \Rubix\ML\NeuralNet\Initializers\Initializer|null $initializer diff --git a/src/NeuralNet/Layers/Swish.php b/src/NeuralNet/Layers/Swish.php index 3a85e8c50..4ad02959d 100644 --- a/src/NeuralNet/Layers/Swish.php +++ b/src/NeuralNet/Layers/Swish.php @@ -33,14 +33,14 @@ class Swish implements Hidden, Parametric * * @var Initializer */ - protected \Rubix\ML\NeuralNet\Initializers\Initializer $initializer; + protected Initializer $initializer; /** * The sigmoid activation function. * * @var Sigmoid */ - protected \Rubix\ML\NeuralNet\ActivationFunctions\Sigmoid $sigmoid; + protected Sigmoid $sigmoid; /** * The width of the layer. @@ -54,21 +54,21 @@ class Swish implements Hidden, Parametric * * @var \Rubix\ML\NeuralNet\Parameter|null */ - protected ?\Rubix\ML\NeuralNet\Parameter $beta = null; + protected ?Parameter $beta = null; /** * The memoized input matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $input = null; + protected ?Matrix $input = null; /** * The memorized activation matrix. * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $output = null; + protected ?Matrix $output = null; /** * @param \Rubix\ML\NeuralNet\Initializers\Initializer|null $initializer diff --git a/src/NeuralNet/Parameter.php b/src/NeuralNet/Parameter.php index 202aa1e5b..39fc34c9a 100644 --- a/src/NeuralNet/Parameter.php +++ b/src/NeuralNet/Parameter.php @@ -35,7 +35,7 @@ class Parameter * * @var Tensor */ - protected \Tensor\Tensor $param; + protected Tensor $param; /** * @param Tensor $param diff --git a/src/PersistentModel.php b/src/PersistentModel.php index a7964a8a7..ceb3880bc 100644 --- a/src/PersistentModel.php +++ b/src/PersistentModel.php @@ -28,21 +28,21 @@ class PersistentModel implements Estimator, Learner, Probabilistic, Scoring * * @var Learner */ - protected \Rubix\ML\Learner $base; + protected Learner $base; /** * The persister used to interface with the storage layer. * * @var Persister */ - protected \Rubix\ML\Persisters\Persister $persister; + protected Persister $persister; /** * The object serializer. * * @var Serializer */ - protected \Rubix\ML\Serializers\Serializer $serializer; + protected Serializer $serializer; /** * Factory method to restore the model from persistence. diff --git a/src/Pipeline.php b/src/Pipeline.php index 7a04e080c..62abc5c9b 100644 --- a/src/Pipeline.php +++ b/src/Pipeline.php @@ -43,7 +43,7 @@ class Pipeline implements Online, Probabilistic, Scoring, Persistable * * @var Estimator */ - protected \Rubix\ML\Estimator $base; + protected Estimator $base; /** * Should we update the elastic transformers during partial train? diff --git a/src/Regressors/Adaline.php b/src/Regressors/Adaline.php index 605484353..fa29764a9 100644 --- a/src/Regressors/Adaline.php +++ b/src/Regressors/Adaline.php @@ -68,7 +68,7 @@ class Adaline implements Estimator, Learner, Online, RanksFeatures, Verbose, Per * * @var Optimizer */ - protected \Rubix\ML\NeuralNet\Optimizers\Optimizer $optimizer; + protected Optimizer $optimizer; /** * The amount of L2 regularization applied to the weights of the output layer. @@ -104,14 +104,14 @@ class Adaline implements Estimator, Learner, Online, RanksFeatures, Verbose, Per * * @var RegressionLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\RegressionLoss $costFn; + protected RegressionLoss $costFn; /** * The underlying neural network instance. * * @var \Rubix\ML\NeuralNet\FeedForward|null */ - protected ?\Rubix\ML\NeuralNet\FeedForward $network = null; + protected ?FeedForward $network = null; /** * The loss at each epoch from the last training session. diff --git a/src/Regressors/GradientBoost.php b/src/Regressors/GradientBoost.php index 979812c8b..c7d78e913 100644 --- a/src/Regressors/GradientBoost.php +++ b/src/Regressors/GradientBoost.php @@ -85,7 +85,7 @@ class GradientBoost implements Estimator, Learner, RanksFeatures, Verbose, Persi * * @var Learner */ - protected \Rubix\ML\Learner $booster; + protected Learner $booster; /** * The learning rate of the ensemble i.e. the *shrinkage* applied to each step. @@ -135,7 +135,7 @@ class GradientBoost implements Estimator, Learner, RanksFeatures, Verbose, Persi * * @var Metric */ - protected \Rubix\ML\CrossValidation\Metrics\Metric $metric; + protected Metric $metric; /** * An ensemble of weak regressors. diff --git a/src/Regressors/KDNeighborsRegressor.php b/src/Regressors/KDNeighborsRegressor.php index 1c2ec75da..7324002ce 100644 --- a/src/Regressors/KDNeighborsRegressor.php +++ b/src/Regressors/KDNeighborsRegressor.php @@ -58,7 +58,7 @@ class KDNeighborsRegressor implements Estimator, Learner, Persistable * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * The dimensionality of the training set. diff --git a/src/Regressors/KNNRegressor.php b/src/Regressors/KNNRegressor.php index be9390e6e..aeaaabe5c 100644 --- a/src/Regressors/KNNRegressor.php +++ b/src/Regressors/KNNRegressor.php @@ -62,7 +62,7 @@ class KNNRegressor implements Estimator, Learner, Online, Persistable * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * The training samples. diff --git a/src/Regressors/MLPRegressor.php b/src/Regressors/MLPRegressor.php index 57cf7be97..426cbd754 100644 --- a/src/Regressors/MLPRegressor.php +++ b/src/Regressors/MLPRegressor.php @@ -84,7 +84,7 @@ class MLPRegressor implements Estimator, Learner, Online, Verbose, Persistable * * @var Optimizer */ - protected \Rubix\ML\NeuralNet\Optimizers\Optimizer $optimizer; + protected Optimizer $optimizer; /** * The amount of L2 regularization applied to the weights of the output layer. @@ -126,21 +126,21 @@ class MLPRegressor implements Estimator, Learner, Online, Verbose, Persistable * * @var RegressionLoss */ - protected \Rubix\ML\NeuralNet\CostFunctions\RegressionLoss $costFn; + protected RegressionLoss $costFn; /** * The metric used to score the generalization performance of the model during training. * * @var Metric */ - protected \Rubix\ML\CrossValidation\Metrics\Metric $metric; + protected Metric $metric; /** * The underlying neural network instance. * * @var \Rubix\ML\NeuralNet\FeedForward|null */ - protected ?\Rubix\ML\NeuralNet\FeedForward $network = null; + protected ?FeedForward $network = null; /** * The validation scores at each epoch from the last training session. diff --git a/src/Regressors/RadiusNeighborsRegressor.php b/src/Regressors/RadiusNeighborsRegressor.php index 4748acfc6..2075e7b2e 100644 --- a/src/Regressors/RadiusNeighborsRegressor.php +++ b/src/Regressors/RadiusNeighborsRegressor.php @@ -66,7 +66,7 @@ class RadiusNeighborsRegressor implements Estimator, Learner, Persistable * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * The dimensionality of the training set. diff --git a/src/Regressors/Ridge.php b/src/Regressors/Ridge.php index 329b3935c..999d3afd5 100644 --- a/src/Regressors/Ridge.php +++ b/src/Regressors/Ridge.php @@ -58,7 +58,7 @@ class Ridge implements Estimator, Learner, RanksFeatures, Persistable * * @var \Tensor\Vector|null */ - protected ?\Tensor\Vector $coefficients = null; + protected ?Vector $coefficients = null; /** * @param float $l2Penalty diff --git a/src/Regressors/SVR.php b/src/Regressors/SVR.php index a289b1953..5967f6678 100644 --- a/src/Regressors/SVR.php +++ b/src/Regressors/SVR.php @@ -50,7 +50,7 @@ class SVR implements Estimator, Learner * * @var svm */ - protected \svm $svm; + protected svm $svm; /** * The memoized hyper-parameters of the model. @@ -64,7 +64,7 @@ class SVR implements Estimator, Learner * * @var \svmmodel|null */ - protected ?\svmmodel $model = null; + protected ?svmmodel $model = null; /** * @param float $c diff --git a/src/Serializers/GzipNative.php b/src/Serializers/GzipNative.php index 24ae98585..f55134378 100644 --- a/src/Serializers/GzipNative.php +++ b/src/Serializers/GzipNative.php @@ -34,7 +34,7 @@ class GzipNative implements Serializer * * @var Native */ - protected \Rubix\ML\Serializers\Native $base; + protected Native $base; /** * @param int $level diff --git a/src/Serializers/RBX.php b/src/Serializers/RBX.php index 5e9b9999b..4ba5d9e94 100644 --- a/src/Serializers/RBX.php +++ b/src/Serializers/RBX.php @@ -64,7 +64,7 @@ class RBX implements Serializer * * @var GzipNative */ - protected \Rubix\ML\Serializers\GzipNative $base; + protected GzipNative $base; /** * @param int $level diff --git a/src/Specifications/DatasetHasDimensionality.php b/src/Specifications/DatasetHasDimensionality.php index bb71b086c..cf08ae837 100644 --- a/src/Specifications/DatasetHasDimensionality.php +++ b/src/Specifications/DatasetHasDimensionality.php @@ -16,7 +16,7 @@ class DatasetHasDimensionality extends Specification * * @var Dataset */ - protected \Rubix\ML\Datasets\Dataset $dataset; + protected Dataset $dataset; /** * The target dimensionality. diff --git a/src/Specifications/DatasetIsLabeled.php b/src/Specifications/DatasetIsLabeled.php index 7ebf4e56d..55614bc99 100644 --- a/src/Specifications/DatasetIsLabeled.php +++ b/src/Specifications/DatasetIsLabeled.php @@ -16,7 +16,7 @@ class DatasetIsLabeled extends Specification * * @var Dataset */ - protected \Rubix\ML\Datasets\Dataset $dataset; + protected Dataset $dataset; /** * Build a specification object with the given arguments. diff --git a/src/Specifications/DatasetIsNotEmpty.php b/src/Specifications/DatasetIsNotEmpty.php index be7048efc..8e53ea129 100644 --- a/src/Specifications/DatasetIsNotEmpty.php +++ b/src/Specifications/DatasetIsNotEmpty.php @@ -15,7 +15,7 @@ class DatasetIsNotEmpty extends Specification * * @var Dataset */ - protected \Rubix\ML\Datasets\Dataset $dataset; + protected Dataset $dataset; /** * Build a specification object with the given arguments. diff --git a/src/Specifications/EstimatorIsCompatibleWithMetric.php b/src/Specifications/EstimatorIsCompatibleWithMetric.php index 16dd51b52..47a4db9de 100644 --- a/src/Specifications/EstimatorIsCompatibleWithMetric.php +++ b/src/Specifications/EstimatorIsCompatibleWithMetric.php @@ -18,14 +18,14 @@ class EstimatorIsCompatibleWithMetric extends Specification * * @var Estimator */ - protected \Rubix\ML\Estimator $estimator; + protected Estimator $estimator; /** * The validation metric. * * @var Metric */ - protected \Rubix\ML\CrossValidation\Metrics\Metric $metric; + protected Metric $metric; /** * Build a specification object with the given arguments. diff --git a/src/Specifications/LabelsAreCompatibleWithLearner.php b/src/Specifications/LabelsAreCompatibleWithLearner.php index d207a0577..23e8f70d5 100644 --- a/src/Specifications/LabelsAreCompatibleWithLearner.php +++ b/src/Specifications/LabelsAreCompatibleWithLearner.php @@ -18,14 +18,14 @@ class LabelsAreCompatibleWithLearner extends Specification * * @var Labeled */ - protected \Rubix\ML\Datasets\Labeled $dataset; + protected Labeled $dataset; /** * The learner instance. * * @var Learner */ - protected \Rubix\ML\Learner $estimator; + protected Learner $estimator; /** * Build a specification object with the given arguments. diff --git a/src/Specifications/SamplesAreCompatibleWithDistance.php b/src/Specifications/SamplesAreCompatibleWithDistance.php index 30af77575..047c34bb6 100644 --- a/src/Specifications/SamplesAreCompatibleWithDistance.php +++ b/src/Specifications/SamplesAreCompatibleWithDistance.php @@ -18,14 +18,14 @@ class SamplesAreCompatibleWithDistance extends Specification * * @var Dataset */ - protected \Rubix\ML\Datasets\Dataset $dataset; + protected Dataset $dataset; /** * The distance kernel. * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * Build a specification object with the given arguments. diff --git a/src/Specifications/SamplesAreCompatibleWithEstimator.php b/src/Specifications/SamplesAreCompatibleWithEstimator.php index 07d78a520..5383fbb4a 100644 --- a/src/Specifications/SamplesAreCompatibleWithEstimator.php +++ b/src/Specifications/SamplesAreCompatibleWithEstimator.php @@ -18,14 +18,14 @@ class SamplesAreCompatibleWithEstimator extends Specification * * @var Dataset */ - protected \Rubix\ML\Datasets\Dataset $dataset; + protected Dataset $dataset; /** * The estimator. * * @var Estimator */ - protected \Rubix\ML\Estimator $estimator; + protected Estimator $estimator; /** * Build a specification object with the given arguments. diff --git a/src/Specifications/SamplesAreCompatibleWithTransformer.php b/src/Specifications/SamplesAreCompatibleWithTransformer.php index 0396d491e..c5e601d07 100644 --- a/src/Specifications/SamplesAreCompatibleWithTransformer.php +++ b/src/Specifications/SamplesAreCompatibleWithTransformer.php @@ -18,14 +18,14 @@ class SamplesAreCompatibleWithTransformer extends Specification * * @var Dataset */ - protected \Rubix\ML\Datasets\Dataset $dataset; + protected Dataset $dataset; /** * The transformer. * * @var Transformer */ - protected \Rubix\ML\Transformers\Transformer $transformer; + protected Transformer $transformer; /** * Build a specification object with the given arguments. diff --git a/src/Specifications/SwooleExtensionIsLoaded.php b/src/Specifications/SwooleExtensionIsLoaded.php index d2179ef51..d15342649 100644 --- a/src/Specifications/SwooleExtensionIsLoaded.php +++ b/src/Specifications/SwooleExtensionIsLoaded.php @@ -15,7 +15,7 @@ public static function create() : self } /** - * @throws \Rubix\ML\Exceptions\MissingExtension + * @throws MissingExtension */ public function check() : void { diff --git a/src/Tokenizers/KSkipNGram.php b/src/Tokenizers/KSkipNGram.php index d51f13529..e77884b97 100644 --- a/src/Tokenizers/KSkipNGram.php +++ b/src/Tokenizers/KSkipNGram.php @@ -57,14 +57,14 @@ class KSkipNGram implements Tokenizer * * @var Word */ - protected \Rubix\ML\Tokenizers\Word $wordTokenizer; + protected Word $wordTokenizer; /** * The sentence tokenizer. * * @var Sentence */ - protected \Rubix\ML\Tokenizers\Sentence $sentenceTokenizer; + protected Sentence $sentenceTokenizer; /** * @param int $min diff --git a/src/Tokenizers/NGram.php b/src/Tokenizers/NGram.php index 92becb5d9..744959029 100644 --- a/src/Tokenizers/NGram.php +++ b/src/Tokenizers/NGram.php @@ -46,14 +46,14 @@ class NGram implements Tokenizer * * @var Word */ - protected \Rubix\ML\Tokenizers\Word $wordTokenizer; + protected Word $wordTokenizer; /** * The sentence tokenizer. * * @var Sentence */ - protected \Rubix\ML\Tokenizers\Sentence $sentenceTokenizer; + protected Sentence $sentenceTokenizer; /** * @param int $min diff --git a/src/Traits/LoggerAware.php b/src/Traits/LoggerAware.php index 371da7271..b08e30219 100644 --- a/src/Traits/LoggerAware.php +++ b/src/Traits/LoggerAware.php @@ -20,7 +20,7 @@ trait LoggerAware * * @var \Psr\Log\LoggerInterface|null */ - protected ?\Psr\Log\LoggerInterface $logger = null; + protected ?LoggerInterface $logger = null; /** * Sets a PSR-3 logger instance. diff --git a/src/Traits/Multiprocessing.php b/src/Traits/Multiprocessing.php index a9d1b9b28..de1e862ee 100644 --- a/src/Traits/Multiprocessing.php +++ b/src/Traits/Multiprocessing.php @@ -27,7 +27,7 @@ trait Multiprocessing * * @var Backend */ - protected \Rubix\ML\Backends\Backend $backend; + protected Backend $backend; /** * Set the parallel processing backend. diff --git a/src/Transformers/GaussianRandomProjector.php b/src/Transformers/GaussianRandomProjector.php index 9af543c8f..ae383213b 100644 --- a/src/Transformers/GaussianRandomProjector.php +++ b/src/Transformers/GaussianRandomProjector.php @@ -41,7 +41,7 @@ class GaussianRandomProjector implements Transformer, Stateful, Persistable * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $r = null; + protected ?Matrix $r = null; /** * Estimate the minimum dimensionality needed to satisfy a *max distortion* constraint with *n* diff --git a/src/Transformers/HotDeckImputer.php b/src/Transformers/HotDeckImputer.php index 8d1c3183d..9d6633815 100644 --- a/src/Transformers/HotDeckImputer.php +++ b/src/Transformers/HotDeckImputer.php @@ -73,7 +73,7 @@ class HotDeckImputer implements Transformer, Stateful, Persistable * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * @param int $k diff --git a/src/Transformers/KNNImputer.php b/src/Transformers/KNNImputer.php index 9415940cb..8bac119ab 100644 --- a/src/Transformers/KNNImputer.php +++ b/src/Transformers/KNNImputer.php @@ -73,7 +73,7 @@ class KNNImputer implements Transformer, Stateful, Persistable * * @var Spatial */ - protected \Rubix\ML\Graph\Trees\Spatial $tree; + protected Spatial $tree; /** * The data types of the fitted feature columns. diff --git a/src/Transformers/LinearDiscriminantAnalysis.php b/src/Transformers/LinearDiscriminantAnalysis.php index dc024fad2..1a1164d66 100644 --- a/src/Transformers/LinearDiscriminantAnalysis.php +++ b/src/Transformers/LinearDiscriminantAnalysis.php @@ -49,7 +49,7 @@ class LinearDiscriminantAnalysis implements Transformer, Stateful, Persistable * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $eigenvectors = null; + protected ?Matrix $eigenvectors = null; /** * The percentage of information lost due to the transformation. diff --git a/src/Transformers/MissingDataImputer.php b/src/Transformers/MissingDataImputer.php index 5175ed0f4..71b4cb337 100644 --- a/src/Transformers/MissingDataImputer.php +++ b/src/Transformers/MissingDataImputer.php @@ -34,14 +34,14 @@ class MissingDataImputer implements Transformer, Stateful, Persistable * * @var Strategy */ - protected \Rubix\ML\Strategies\Strategy $continuous; + protected Strategy $continuous; /** * The guessing strategy to use when imputing categorical values. * * @var Strategy */ - protected \Rubix\ML\Strategies\Strategy $categorical; + protected Strategy $categorical; /** * The placeholder category that denotes missing values. diff --git a/src/Transformers/PrincipalComponentAnalysis.php b/src/Transformers/PrincipalComponentAnalysis.php index aeabdbc2d..896795d86 100644 --- a/src/Transformers/PrincipalComponentAnalysis.php +++ b/src/Transformers/PrincipalComponentAnalysis.php @@ -53,7 +53,7 @@ class PrincipalComponentAnalysis implements Transformer, Stateful, Persistable * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $eigenvectors = null; + protected ?Matrix $eigenvectors = null; /** * The percentage of information lost due to the transformation. diff --git a/src/Transformers/TSNE.php b/src/Transformers/TSNE.php index b12407e4f..dc39961fb 100644 --- a/src/Transformers/TSNE.php +++ b/src/Transformers/TSNE.php @@ -190,7 +190,7 @@ class TSNE implements Transformer, Verbose * * @var Distance */ - protected \Rubix\ML\Kernels\Distance\Distance $kernel; + protected Distance $kernel; /** * The loss at each epoch from the last embedding. diff --git a/src/Transformers/TokenHashingVectorizer.php b/src/Transformers/TokenHashingVectorizer.php index ca8f7c56a..a0eb0d45b 100644 --- a/src/Transformers/TokenHashingVectorizer.php +++ b/src/Transformers/TokenHashingVectorizer.php @@ -70,7 +70,7 @@ class TokenHashingVectorizer implements Transformer * * @var Tokenizer */ - protected \Rubix\ML\Tokenizers\Tokenizer $tokenizer; + protected Tokenizer $tokenizer; /** * The hash function that accepts a string token and returns an integer. diff --git a/src/Transformers/TruncatedSVD.php b/src/Transformers/TruncatedSVD.php index 399bf7f05..143f570be 100644 --- a/src/Transformers/TruncatedSVD.php +++ b/src/Transformers/TruncatedSVD.php @@ -49,7 +49,7 @@ class TruncatedSVD implements Transformer, Stateful, Persistable * * @var \Tensor\Matrix|null */ - protected ?\Tensor\Matrix $components = null; + protected ?Matrix $components = null; /** * The proportion of information lost due to the transformation. diff --git a/src/Transformers/WordCountVectorizer.php b/src/Transformers/WordCountVectorizer.php index 3c79c9a7f..9545f560b 100644 --- a/src/Transformers/WordCountVectorizer.php +++ b/src/Transformers/WordCountVectorizer.php @@ -62,7 +62,7 @@ class WordCountVectorizer implements Transformer, Stateful, Persistable * * @var Tokenizer */ - protected \Rubix\ML\Tokenizers\Tokenizer $tokenizer; + protected Tokenizer $tokenizer; /** * The vocabularies of each categorical feature column of the fitted dataset. diff --git a/tests/Backends/SwooleTest.php b/tests/Backends/SwooleTest.php index 60cbf526f..ab6ac6cb1 100644 --- a/tests/Backends/SwooleTest.php +++ b/tests/Backends/SwooleTest.php @@ -17,7 +17,7 @@ class SwooleTest extends TestCase { /** - * @var \Rubix\ML\Backends\Swoole + * @var SwooleBackend */ protected $backend; diff --git a/tests/Graph/Nodes/NeighborhoodTest.php b/tests/Graph/Nodes/NeighborhoodTest.php index d2f17fb91..755957c2f 100644 --- a/tests/Graph/Nodes/NeighborhoodTest.php +++ b/tests/Graph/Nodes/NeighborhoodTest.php @@ -63,7 +63,7 @@ public function terminate() : void { $node = Neighborhood::terminate(Labeled::quick(self::SAMPLES, self::LABELS)); - $this->assertInstanceOf(NeighborHood::class, $node); + $this->assertInstanceOf(Neighborhood::class, $node); $this->assertInstanceOf(Labeled::class, $node->dataset()); $this->assertEquals(self::BOX, iterator_to_array($node->sides())); } diff --git a/tests/NeuralNet/ParameterTest.php b/tests/NeuralNet/ParameterTest.php index 80fc03603..ec54adc51 100644 --- a/tests/NeuralNet/ParameterTest.php +++ b/tests/NeuralNet/ParameterTest.php @@ -16,7 +16,7 @@ class ParameterTest extends TestCase /** * @var Parameter */ - protected \Rubix\ML\NeuralNet\Parameter $param; + protected Parameter $param; /** * @var \Rubix\ML\NeuralNet\Optimizers\Optimizer diff --git a/tests/Transformers/ImageRotatorTest.php b/tests/Transformers/ImageRotatorTest.php index 13772f54e..10ccd5bef 100644 --- a/tests/Transformers/ImageRotatorTest.php +++ b/tests/Transformers/ImageRotatorTest.php @@ -17,7 +17,7 @@ class ImageRotatorTest extends TestCase /** * @var ImageRotator */ - protected \Rubix\ML\Transformers\ImageRotator $transformer; + protected ImageRotator $transformer; /** * @before From 251a1b46693939d26b24d86360f8fc630261bfec Mon Sep 17 00:00:00 2001 From: Mateusz Charytoniuk Date: Sat, 16 Mar 2024 15:58:51 +0100 Subject: [PATCH 18/18] docs: Swoole backend --- docs/backends/swoole.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docs/backends/swoole.md diff --git a/docs/backends/swoole.md b/docs/backends/swoole.md new file mode 100644 index 000000000..b49b09e78 --- /dev/null +++ b/docs/backends/swoole.md @@ -0,0 +1,18 @@ +[source] + +# Swoole +[Swoole](https://swoole.com)/[OpenSwoole](https://openswoole.com/) is an async PHP extension that also supports multiprocessing. + +!!! tip + Swoole backend makes use of [Igbinary](https://www.php.net/manual/en/intro.igbinary.php) serializer. If you need to + optimize the memory usage (or getting out-of-memory errors) consider installing [Igbinary](https://www.php.net/manual/en/intro.igbinary.php). + +## Example + +No parameters are required. It's a drop-in replacement for the [Serial](backends/serial.md) backend. + +```php +use Rubix\ML\Backends\Swoole; + +$backend = new Swoole(); +``` \ No newline at end of file