summaryrefslogtreecommitdiffstats
path: root/vendor/markbaker
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/markbaker')
-rw-r--r--vendor/markbaker/complex/.github/workflows/main.yml150
-rw-r--r--vendor/markbaker/complex/README.md156
-rw-r--r--vendor/markbaker/complex/classes/Autoloader.php53
-rw-r--r--vendor/markbaker/complex/classes/Bootstrap.php38
-rw-r--r--vendor/markbaker/complex/classes/src/Complex.php390
-rw-r--r--vendor/markbaker/complex/classes/src/Exception.php13
-rw-r--r--vendor/markbaker/complex/classes/src/functions/abs.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/acos.php40
-rw-r--r--vendor/markbaker/complex/classes/src/functions/acosh.php36
-rw-r--r--vendor/markbaker/complex/classes/src/functions/acot.php27
-rw-r--r--vendor/markbaker/complex/classes/src/functions/acoth.php27
-rw-r--r--vendor/markbaker/complex/classes/src/functions/acsc.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/acsch.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/argument.php30
-rw-r--r--vendor/markbaker/complex/classes/src/functions/asec.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/asech.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/asin.php39
-rw-r--r--vendor/markbaker/complex/classes/src/functions/asinh.php35
-rw-r--r--vendor/markbaker/complex/classes/src/functions/atan.php47
-rw-r--r--vendor/markbaker/complex/classes/src/functions/atanh.php40
-rw-r--r--vendor/markbaker/complex/classes/src/functions/conjugate.php30
-rw-r--r--vendor/markbaker/complex/classes/src/functions/cos.php36
-rw-r--r--vendor/markbaker/complex/classes/src/functions/cosh.php34
-rw-r--r--vendor/markbaker/complex/classes/src/functions/cot.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/coth.php26
-rw-r--r--vendor/markbaker/complex/classes/src/functions/csc.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/csch.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/exp.php36
-rw-r--r--vendor/markbaker/complex/classes/src/functions/inverse.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/ln.php35
-rw-r--r--vendor/markbaker/complex/classes/src/functions/log10.php34
-rw-r--r--vendor/markbaker/complex/classes/src/functions/log2.php34
-rw-r--r--vendor/markbaker/complex/classes/src/functions/negative.php33
-rw-r--r--vendor/markbaker/complex/classes/src/functions/pow.php42
-rw-r--r--vendor/markbaker/complex/classes/src/functions/rho.php30
-rw-r--r--vendor/markbaker/complex/classes/src/functions/sec.php27
-rw-r--r--vendor/markbaker/complex/classes/src/functions/sech.php27
-rw-r--r--vendor/markbaker/complex/classes/src/functions/sin.php34
-rw-r--r--vendor/markbaker/complex/classes/src/functions/sinh.php34
-rw-r--r--vendor/markbaker/complex/classes/src/functions/sqrt.php31
-rw-r--r--vendor/markbaker/complex/classes/src/functions/tan.php42
-rw-r--r--vendor/markbaker/complex/classes/src/functions/tanh.php37
-rw-r--r--vendor/markbaker/complex/classes/src/functions/theta.php40
-rw-r--r--vendor/markbaker/complex/classes/src/operations/add.php48
-rw-r--r--vendor/markbaker/complex/classes/src/operations/divideby.php58
-rw-r--r--vendor/markbaker/complex/classes/src/operations/divideinto.php58
-rw-r--r--vendor/markbaker/complex/classes/src/operations/multiply.php50
-rw-r--r--vendor/markbaker/complex/classes/src/operations/subtract.php48
-rw-r--r--vendor/markbaker/complex/composer.json77
-rw-r--r--vendor/markbaker/complex/examples/complexTest.php154
-rw-r--r--vendor/markbaker/complex/examples/testFunctions.php52
-rw-r--r--vendor/markbaker/complex/examples/testOperations.php34
-rw-r--r--vendor/markbaker/complex/license.md25
-rw-r--r--vendor/markbaker/matrix/.github/workflows/main.yaml124
-rw-r--r--vendor/markbaker/matrix/README.md207
-rw-r--r--vendor/markbaker/matrix/buildPhar.php62
-rw-r--r--vendor/markbaker/matrix/classes/src/Builder.php70
-rw-r--r--vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php27
-rw-r--r--vendor/markbaker/matrix/classes/src/Decomposition/LU.php260
-rw-r--r--vendor/markbaker/matrix/classes/src/Decomposition/QR.php191
-rw-r--r--vendor/markbaker/matrix/classes/src/Div0Exception.php13
-rw-r--r--vendor/markbaker/matrix/classes/src/Exception.php13
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions.php337
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/adjoint.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/antidiagonal.php31
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/cofactors.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/determinant.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/diagonal.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/identity.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/inverse.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/minors.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/trace.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Functions/transpose.php32
-rw-r--r--vendor/markbaker/matrix/classes/src/Matrix.php423
-rw-r--r--vendor/markbaker/matrix/classes/src/Operations/add.php46
-rw-r--r--vendor/markbaker/matrix/classes/src/Operations/directsum.php46
-rw-r--r--vendor/markbaker/matrix/classes/src/Operations/divideby.php46
-rw-r--r--vendor/markbaker/matrix/classes/src/Operations/divideinto.php47
-rw-r--r--vendor/markbaker/matrix/classes/src/Operations/multiply.php46
-rw-r--r--vendor/markbaker/matrix/classes/src/Operations/subtract.php46
-rw-r--r--vendor/markbaker/matrix/classes/src/Operators/Addition.php68
-rw-r--r--vendor/markbaker/matrix/classes/src/Operators/DirectSum.php64
-rw-r--r--vendor/markbaker/matrix/classes/src/Operators/Division.php35
-rw-r--r--vendor/markbaker/matrix/classes/src/Operators/Multiplication.php86
-rw-r--r--vendor/markbaker/matrix/classes/src/Operators/Operator.php78
-rw-r--r--vendor/markbaker/matrix/classes/src/Operators/Subtraction.php68
-rw-r--r--vendor/markbaker/matrix/composer.json89
-rw-r--r--vendor/markbaker/matrix/examples/test.php33
-rw-r--r--vendor/markbaker/matrix/infection.json.dist17
-rw-r--r--vendor/markbaker/matrix/license.md25
-rw-r--r--vendor/markbaker/matrix/phpstan.neon6
91 files changed, 5538 insertions, 0 deletions
diff --git a/vendor/markbaker/complex/.github/workflows/main.yml b/vendor/markbaker/complex/.github/workflows/main.yml
new file mode 100644
index 0000000..3b41498
--- /dev/null
+++ b/vendor/markbaker/complex/.github/workflows/main.yml
@@ -0,0 +1,150 @@
+name: main
+on: [ push, pull_request ]
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ experimental:
+ - false
+ php-version:
+ - '7.2'
+ - '7.3'
+ - '7.4'
+ - '8.0'
+
+ include:
+ - php-version: '8.1'
+ experimental: true
+
+ name: PHP ${{ matrix.php-version }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-version }}
+ coverage: none
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Delete composer lock file
+ id: composer-lock
+ if: ${{ matrix.php-version == '8.1' }}
+ run: |
+ echo "::set-output name=flags::--ignore-platform-reqs"
+
+ - name: Install dependencies
+ run: composer update --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }}
+
+ - name: Setup problem matchers for PHP
+ run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
+
+ - name: Setup problem matchers for PHPUnit
+ run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
+
+ - name: "Run PHPUnit tests (Experimental: ${{ matrix.experimental }})"
+ env:
+ FAILURE_ACTION: "${{ matrix.experimental == true }}"
+ run: vendor/bin/phpunit --verbose || $FAILURE_ACTION
+
+ phpcs:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ coverage: none
+ tools: cs2pr
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --no-progress --prefer-dist --optimize-autoloader
+
+ - name: Code style with PHP_CodeSniffer
+ run: ./vendor/bin/phpcs -q --report=checkstyle classes/src/ | cs2pr
+
+ versions:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ coverage: none
+ tools: cs2pr
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --no-progress --prefer-dist --optimize-autoloader
+
+ - name: Code Version Compatibility check with PHP_CodeSniffer
+ run: ./vendor/bin/phpcs -q --report-width=200 --report=summary,full classes/src/ --standard=PHPCompatibility --runtime-set testVersion 7.2-
+
+ coverage:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ coverage: pcov
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --no-progress --prefer-dist --optimize-autoloader
+
+ - name: Test Coverage
+ run: ./vendor/bin/phpunit --verbose --coverage-text
diff --git a/vendor/markbaker/complex/README.md b/vendor/markbaker/complex/README.md
new file mode 100644
index 0000000..8ded0df
--- /dev/null
+++ b/vendor/markbaker/complex/README.md
@@ -0,0 +1,156 @@
+PHPComplex
+==========
+
+---
+
+PHP Class for handling Complex numbers
+
+Master: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=master)](http://travis-ci.org/MarkBaker/PHPComplex)
+
+Develop: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=develop)](http://travis-ci.org/MarkBaker/PHPComplex)
+
+[![Complex Numbers](https://imgs.xkcd.com/comics/complex_numbers_2x.png)](https://xkcd.com/2028/)
+
+---
+
+The library currently provides the following operations:
+
+ - addition
+ - subtraction
+ - multiplication
+ - division
+ - division by
+ - division into
+
+together with functions for
+
+ - theta (polar theta angle)
+ - rho (polar distance/radius)
+ - conjugate
+ * negative
+ - inverse (1 / complex)
+ - cos (cosine)
+ - acos (inverse cosine)
+ - cosh (hyperbolic cosine)
+ - acosh (inverse hyperbolic cosine)
+ - sin (sine)
+ - asin (inverse sine)
+ - sinh (hyperbolic sine)
+ - asinh (inverse hyperbolic sine)
+ - sec (secant)
+ - asec (inverse secant)
+ - sech (hyperbolic secant)
+ - asech (inverse hyperbolic secant)
+ - csc (cosecant)
+ - acsc (inverse cosecant)
+ - csch (hyperbolic secant)
+ - acsch (inverse hyperbolic secant)
+ - tan (tangent)
+ - atan (inverse tangent)
+ - tanh (hyperbolic tangent)
+ - atanh (inverse hyperbolic tangent)
+ - cot (cotangent)
+ - acot (inverse cotangent)
+ - coth (hyperbolic cotangent)
+ - acoth (inverse hyperbolic cotangent)
+ - sqrt (square root)
+ - exp (exponential)
+ - ln (natural log)
+ - log10 (base-10 log)
+ - log2 (base-2 log)
+ - pow (raised to the power of a real number)
+
+
+---
+
+# Usage
+
+To create a new complex object, you can provide either the real, imaginary and suffix parts as individual values, or as an array of values passed passed to the constructor; or a string representing the value. e.g
+
+```
+$real = 1.23;
+$imaginary = -4.56;
+$suffix = 'i';
+
+$complexObject = new Complex\Complex($real, $imaginary, $suffix);
+```
+or
+```
+$real = 1.23;
+$imaginary = -4.56;
+$suffix = 'i';
+
+$arguments = [$real, $imaginary, $suffix];
+
+$complexObject = new Complex\Complex($arguments);
+```
+or
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+```
+
+Complex objects are immutable: whenever you call a method or pass a complex value to a function that returns a complex value, a new Complex object will be returned, and the original will remain unchanged.
+This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Complex result).
+
+## Performing Mathematical Operations
+
+To perform mathematical operations with Complex values, you can call the appropriate method against a complex value, passing other values as arguments
+
+```
+$complexString1 = '1.23-4.56i';
+$complexString2 = '2.34+5.67i';
+
+$complexObject = new Complex\Complex($complexString1);
+echo $complexObject->add($complexString2);
+```
+or pass all values to the appropriate function
+```
+$complexString1 = '1.23-4.56i';
+$complexString2 = '2.34+5.67i';
+
+echo Complex\add($complexString1, $complexString2);
+```
+If you want to perform the same operation against multiple values (e.g. to add three or more complex numbers), then you can pass multiple arguments to any of the operations.
+
+You can pass these arguments as Complex objects, or as an array or string that will parse to a complex object.
+
+## Using functions
+
+When calling any of the available functions for a complex value, you can either call the relevant method for the Complex object
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo $complexObject->sinh();
+```
+or you can call the function as you would in procedural code, passing the Complex object as an argument
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo Complex\sinh($complexObject);
+```
+When called procedurally using the function, you can pass in the argument as a Complex object, or as an array or string that will parse to a complex object.
+```
+$complexString = '1.23-4.56i';
+
+echo Complex\sinh($complexString);
+```
+
+In the case of the `pow()` function (the only implemented function that requires an additional argument) you need to pass both arguments when calling the function procedurally
+
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo Complex\pow($complexObject, 2);
+```
+or pass the additional argument when calling the method
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo $complexObject->pow(2);
+```
diff --git a/vendor/markbaker/complex/classes/Autoloader.php b/vendor/markbaker/complex/classes/Autoloader.php
new file mode 100644
index 0000000..e7cfdc4
--- /dev/null
+++ b/vendor/markbaker/complex/classes/Autoloader.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Complex;
+
+/**
+ *
+ * Autoloader for Complex classes
+ *
+ * @package Complex
+ * @copyright Copyright (c) 2014 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+class Autoloader
+{
+ /**
+ * Register the Autoloader with SPL
+ *
+ */
+ public static function Register()
+ {
+ if (function_exists('__autoload')) {
+ // Register any existing autoloader function with SPL, so we don't get any clashes
+ spl_autoload_register('__autoload');
+ }
+ // Register ourselves with SPL
+ return spl_autoload_register(['Complex\\Autoloader', 'Load']);
+ }
+
+
+ /**
+ * Autoload a class identified by name
+ *
+ * @param string $pClassName Name of the object to load
+ */
+ public static function Load($pClassName)
+ {
+ if ((class_exists($pClassName, false)) || (strpos($pClassName, 'Complex\\') !== 0)) {
+ // Either already loaded, or not a Complex class request
+ return false;
+ }
+
+ $pClassFilePath = __DIR__ . DIRECTORY_SEPARATOR .
+ 'src' . DIRECTORY_SEPARATOR .
+ str_replace(['Complex\\', '\\'], ['', '/'], $pClassName) .
+ '.php';
+
+ if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
+ // Can't load
+ return false;
+ }
+ require($pClassFilePath);
+ }
+}
diff --git a/vendor/markbaker/complex/classes/Bootstrap.php b/vendor/markbaker/complex/classes/Bootstrap.php
new file mode 100644
index 0000000..e933413
--- /dev/null
+++ b/vendor/markbaker/complex/classes/Bootstrap.php
@@ -0,0 +1,38 @@
+<?php
+
+include_once __DIR__ . '/Autoloader.php';
+
+\Complex\Autoloader::Register();
+
+
+abstract class FilesystemRegexFilter extends RecursiveRegexIterator
+{
+ protected $regex;
+ public function __construct(RecursiveIterator $it, $regex)
+ {
+ $this->regex = $regex;
+ parent::__construct($it, $regex);
+ }
+}
+
+class FilenameFilter extends FilesystemRegexFilter
+{
+ // Filter files against the regex
+ public function accept()
+ {
+ return (!$this->isFile() || preg_match($this->regex, $this->getFilename()));
+ }
+}
+
+
+$srcFolder = __DIR__ . DIRECTORY_SEPARATOR . 'src';
+$srcDirectory = new RecursiveDirectoryIterator($srcFolder);
+
+$filteredFileList = new FilenameFilter($srcDirectory, '/(?:php)$/i');
+$filteredFileList = new FilenameFilter($filteredFileList, '/^(?!.*(Complex|Exception)\.php).*$/i');
+
+foreach (new RecursiveIteratorIterator($filteredFileList) as $file) {
+ if ($file->isFile()) {
+ include_once $file;
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/Complex.php b/vendor/markbaker/complex/classes/src/Complex.php
new file mode 100644
index 0000000..3666486
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/Complex.php
@@ -0,0 +1,390 @@
+<?php
+
+/**
+ *
+ * Class for the management of Complex numbers
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Complex Number object.
+ *
+ * @package Complex
+ *
+ * @method float abs()
+ * @method Complex acos()
+ * @method Complex acosh()
+ * @method Complex acot()
+ * @method Complex acoth()
+ * @method Complex acsc()
+ * @method Complex acsch()
+ * @method float argument()
+ * @method Complex asec()
+ * @method Complex asech()
+ * @method Complex asin()
+ * @method Complex asinh()
+ * @method Complex atan()
+ * @method Complex atanh()
+ * @method Complex conjugate()
+ * @method Complex cos()
+ * @method Complex cosh()
+ * @method Complex cot()
+ * @method Complex coth()
+ * @method Complex csc()
+ * @method Complex csch()
+ * @method Complex exp()
+ * @method Complex inverse()
+ * @method Complex ln()
+ * @method Complex log2()
+ * @method Complex log10()
+ * @method Complex negative()
+ * @method Complex pow(int|float $power)
+ * @method float rho()
+ * @method Complex sec()
+ * @method Complex sech()
+ * @method Complex sin()
+ * @method Complex sinh()
+ * @method Complex sqrt()
+ * @method Complex tan()
+ * @method Complex tanh()
+ * @method float theta()
+ * @method Complex add(...$complexValues)
+ * @method Complex subtract(...$complexValues)
+ * @method Complex multiply(...$complexValues)
+ * @method Complex divideby(...$complexValues)
+ * @method Complex divideinto(...$complexValues)
+ */
+class Complex
+{
+ /**
+ * @constant Euler's Number.
+ */
+ const EULER = 2.7182818284590452353602874713526624977572;
+
+ /**
+ * @constant Regexp to split an input string into real and imaginary components and suffix
+ */
+ const NUMBER_SPLIT_REGEXP =
+ '` ^
+ ( # Real part
+ [-+]?(\d+\.?\d*|\d*\.?\d+) # Real value (integer or float)
+ ([Ee][-+]?[0-2]?\d{1,3})? # Optional real exponent for scientific format
+ )
+ ( # Imaginary part
+ [-+]?(\d+\.?\d*|\d*\.?\d+) # Imaginary value (integer or float)
+ ([Ee][-+]?[0-2]?\d{1,3})? # Optional imaginary exponent for scientific format
+ )?
+ ( # Imaginary part is optional
+ ([-+]?) # Imaginary (implicit 1 or -1) only
+ ([ij]?) # Imaginary i or j - depending on whether mathematical or engineering
+ )
+ $`uix';
+
+ /**
+ * @var float $realPart The value of of this complex number on the real plane.
+ */
+ protected $realPart = 0.0;
+
+ /**
+ * @var float $imaginaryPart The value of of this complex number on the imaginary plane.
+ */
+ protected $imaginaryPart = 0.0;
+
+ /**
+ * @var string $suffix The suffix for this complex number (i or j).
+ */
+ protected $suffix;
+
+
+ /**
+ * Validates whether the argument is a valid complex number, converting scalar or array values if possible
+ *
+ * @param mixed $complexNumber The value to parse
+ * @return array
+ * @throws Exception If the argument isn't a Complex number or cannot be converted to one
+ */
+ private static function parseComplex($complexNumber)
+ {
+ // Test for real number, with no imaginary part
+ if (is_numeric($complexNumber)) {
+ return [$complexNumber, 0, null];
+ }
+
+ // Fix silly human errors
+ $complexNumber = str_replace(
+ ['+-', '-+', '++', '--'],
+ ['-', '-', '+', '+'],
+ $complexNumber
+ );
+
+ // Basic validation of string, to parse out real and imaginary parts, and any suffix
+ $validComplex = preg_match(
+ self::NUMBER_SPLIT_REGEXP,
+ $complexNumber,
+ $complexParts
+ );
+
+ if (!$validComplex) {
+ // Neither real nor imaginary part, so test to see if we actually have a suffix
+ $validComplex = preg_match('/^([\-\+]?)([ij])$/ui', $complexNumber, $complexParts);
+ if (!$validComplex) {
+ throw new Exception('Invalid complex number');
+ }
+ // We have a suffix, so set the real to 0, the imaginary to either 1 or -1 (as defined by the sign)
+ $imaginary = 1;
+ if ($complexParts[1] === '-') {
+ $imaginary = 0 - $imaginary;
+ }
+ return [0, $imaginary, $complexParts[2]];
+ }
+
+ // If we don't have an imaginary part, identify whether it should be +1 or -1...
+ if (($complexParts[4] === '') && ($complexParts[9] !== '')) {
+ if ($complexParts[7] !== $complexParts[9]) {
+ $complexParts[4] = 1;
+ if ($complexParts[8] === '-') {
+ $complexParts[4] = -1;
+ }
+ } else {
+ // ... or if we have only the real and no imaginary part
+ // (in which case our real should be the imaginary)
+ $complexParts[4] = $complexParts[1];
+ $complexParts[1] = 0;
+ }
+ }
+
+ // Return real and imaginary parts and suffix as an array, and set a default suffix if user input lazily
+ return [
+ $complexParts[1],
+ $complexParts[4],
+ !empty($complexParts[9]) ? $complexParts[9] : 'i'
+ ];
+ }
+
+
+ public function __construct($realPart = 0.0, $imaginaryPart = null, $suffix = 'i')
+ {
+ if ($imaginaryPart === null) {
+ if (is_array($realPart)) {
+ // We have an array of (potentially) real and imaginary parts, and any suffix
+ list ($realPart, $imaginaryPart, $suffix) = array_values($realPart) + [0.0, 0.0, 'i'];
+ } elseif ((is_string($realPart)) || (is_numeric($realPart))) {
+ // We've been given a string to parse to extract the real and imaginary parts, and any suffix
+ list($realPart, $imaginaryPart, $suffix) = self::parseComplex($realPart);
+ }
+ }
+
+ if ($imaginaryPart != 0.0 && empty($suffix)) {
+ $suffix = 'i';
+ } elseif ($imaginaryPart == 0.0 && !empty($suffix)) {
+ $suffix = '';
+ }
+
+ // Set parsed values in our properties
+ $this->realPart = (float) $realPart;
+ $this->imaginaryPart = (float) $imaginaryPart;
+ $this->suffix = strtolower($suffix ?? '');
+ }
+
+ /**
+ * Gets the real part of this complex number
+ *
+ * @return Float
+ */
+ public function getReal(): float
+ {
+ return $this->realPart;
+ }
+
+ /**
+ * Gets the imaginary part of this complex number
+ *
+ * @return Float
+ */
+ public function getImaginary(): float
+ {
+ return $this->imaginaryPart;
+ }
+
+ /**
+ * Gets the suffix of this complex number
+ *
+ * @return String
+ */
+ public function getSuffix(): string
+ {
+ return $this->suffix;
+ }
+
+ /**
+ * Returns true if this is a real value, false if a complex value
+ *
+ * @return Bool
+ */
+ public function isReal(): bool
+ {
+ return $this->imaginaryPart == 0.0;
+ }
+
+ /**
+ * Returns true if this is a complex value, false if a real value
+ *
+ * @return Bool
+ */
+ public function isComplex(): bool
+ {
+ return !$this->isReal();
+ }
+
+ public function format(): string
+ {
+ $str = "";
+ if ($this->imaginaryPart != 0.0) {
+ if (\abs($this->imaginaryPart) != 1.0) {
+ $str .= $this->imaginaryPart . $this->suffix;
+ } else {
+ $str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix;
+ }
+ }
+ if ($this->realPart != 0.0) {
+ if (($str) && ($this->imaginaryPart > 0.0)) {
+ $str = "+" . $str;
+ }
+ $str = $this->realPart . $str;
+ }
+ if (!$str) {
+ $str = "0.0";
+ }
+
+ return $str;
+ }
+
+ public function __toString(): string
+ {
+ return $this->format();
+ }
+
+ /**
+ * Validates whether the argument is a valid complex number, converting scalar or array values if possible
+ *
+ * @param mixed $complex The value to validate
+ * @return Complex
+ * @throws Exception If the argument isn't a Complex number or cannot be converted to one
+ */
+ public static function validateComplexArgument($complex): Complex
+ {
+ if (is_scalar($complex) || is_array($complex)) {
+ $complex = new Complex($complex);
+ } elseif (!is_object($complex) || !($complex instanceof Complex)) {
+ throw new Exception('Value is not a valid complex number');
+ }
+
+ return $complex;
+ }
+
+ /**
+ * Returns the reverse of this complex number
+ *
+ * @return Complex
+ */
+ public function reverse(): Complex
+ {
+ return new Complex(
+ $this->imaginaryPart,
+ $this->realPart,
+ ($this->realPart == 0.0) ? null : $this->suffix
+ );
+ }
+
+ public function invertImaginary(): Complex
+ {
+ return new Complex(
+ $this->realPart,
+ $this->imaginaryPart * -1,
+ ($this->imaginaryPart == 0.0) ? null : $this->suffix
+ );
+ }
+
+ public function invertReal(): Complex
+ {
+ return new Complex(
+ $this->realPart * -1,
+ $this->imaginaryPart,
+ ($this->imaginaryPart == 0.0) ? null : $this->suffix
+ );
+ }
+
+ protected static $functions = [
+ 'abs',
+ 'acos',
+ 'acosh',
+ 'acot',
+ 'acoth',
+ 'acsc',
+ 'acsch',
+ 'argument',
+ 'asec',
+ 'asech',
+ 'asin',
+ 'asinh',
+ 'atan',
+ 'atanh',
+ 'conjugate',
+ 'cos',
+ 'cosh',
+ 'cot',
+ 'coth',
+ 'csc',
+ 'csch',
+ 'exp',
+ 'inverse',
+ 'ln',
+ 'log2',
+ 'log10',
+ 'negative',
+ 'pow',
+ 'rho',
+ 'sec',
+ 'sech',
+ 'sin',
+ 'sinh',
+ 'sqrt',
+ 'tan',
+ 'tanh',
+ 'theta',
+ ];
+
+ protected static $operations = [
+ 'add',
+ 'subtract',
+ 'multiply',
+ 'divideby',
+ 'divideinto',
+ ];
+
+ /**
+ * Returns the result of the function call or operation
+ *
+ * @return Complex|float
+ * @throws Exception|\InvalidArgumentException
+ */
+ public function __call($functionName, $arguments)
+ {
+ $functionName = strtolower(str_replace('_', '', $functionName));
+
+ // Test for function calls
+ if (in_array($functionName, self::$functions, true)) {
+ $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
+ return $functionName($this, ...$arguments);
+ }
+ // Test for operation calls
+ if (in_array($functionName, self::$operations, true)) {
+ $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
+ return $functionName($this, ...$arguments);
+ }
+ throw new Exception('Complex Function or Operation does not exist');
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/Exception.php b/vendor/markbaker/complex/classes/src/Exception.php
new file mode 100644
index 0000000..14dd545
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/Exception.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * Exception.
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+class Exception extends \Exception
+{
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/abs.php b/vendor/markbaker/complex/classes/src/functions/abs.php
new file mode 100644
index 0000000..400cb2a
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/abs.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex abs() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the absolute value (modulus) of a complex number.
+ * Also known as the rho of the complex number, i.e. the distance/radius
+ * from the centrepoint to the representation of the number in polar coordinates.
+ *
+ * This function is a synonym for rho()
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return float The absolute (or rho) value of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ *
+ * @see rho
+ *
+ */
+if (!function_exists(__NAMESPACE__ . '\\abs')) {
+ function abs($complex): float
+ {
+ return rho($complex);
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/acos.php b/vendor/markbaker/complex/classes/src/functions/acos.php
new file mode 100644
index 0000000..378a1a9
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/acos.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acos() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse cosine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse cosine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\acos')) {
+ function acos($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ $square = clone $complex;
+ $square = multiply($square, $complex);
+ $invsqrt = new Complex(1.0);
+ $invsqrt = subtract($invsqrt, $square);
+ $invsqrt = sqrt($invsqrt);
+ $adjust = new Complex(
+ $complex->getReal() - $invsqrt->getImaginary(),
+ $complex->getImaginary() + $invsqrt->getReal()
+ );
+ $log = ln($adjust);
+
+ return new Complex(
+ $log->getImaginary(),
+ -1 * $log->getReal()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/acosh.php b/vendor/markbaker/complex/classes/src/functions/acosh.php
new file mode 100644
index 0000000..37e604c
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/acosh.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acosh() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic cosine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse hyperbolic cosine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\acosh')) {
+ function acosh($complex)
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal() && ($complex->getReal() > 1)) {
+ return new Complex(\acosh($complex->getReal()));
+ }
+
+ $acosh = acos($complex)
+ ->reverse();
+ if ($acosh->getReal() < 0.0) {
+ $acosh = $acosh->invertReal();
+ }
+
+ return $acosh;
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/acot.php b/vendor/markbaker/complex/classes/src/functions/acot.php
new file mode 100644
index 0000000..bc77379
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/acot.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acot() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse cotangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse cotangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\acot')) {
+ function acot($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ return atan(inverse($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/acoth.php b/vendor/markbaker/complex/classes/src/functions/acoth.php
new file mode 100644
index 0000000..80fbffd
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/acoth.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acoth() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic cotangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse hyperbolic cotangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\acoth')) {
+ function acoth($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ return atanh(inverse($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/acsc.php b/vendor/markbaker/complex/classes/src/functions/acsc.php
new file mode 100644
index 0000000..8c18db9
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/acsc.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acsc() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse cosecant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse cosecant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\acsc')) {
+ function acsc($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ return new Complex(INF);
+ }
+
+ return asin(inverse($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/acsch.php b/vendor/markbaker/complex/classes/src/functions/acsch.php
new file mode 100644
index 0000000..fb909c2
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/acsch.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acsch() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic cosecant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse hyperbolic cosecant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\acsch')) {
+ function acsch($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ return new Complex(INF);
+ }
+
+ return asinh(inverse($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/argument.php b/vendor/markbaker/complex/classes/src/functions/argument.php
new file mode 100644
index 0000000..17e6ecb
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/argument.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ *
+ * Function code for the complex argument() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the argument of a complex number.
+ * Also known as the theta of the complex number, i.e. the angle in radians
+ * from the real axis to the representation of the number in polar coordinates.
+ *
+ * This function is a synonym for theta()
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return float The argument (or theta) value of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ *
+ * @see theta
+ */
+if (!function_exists(__NAMESPACE__ . '\\argument')) {
+ function argument($complex): float
+ {
+ return theta($complex);
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/asec.php b/vendor/markbaker/complex/classes/src/functions/asec.php
new file mode 100644
index 0000000..4ad69fc
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/asec.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asec() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse secant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse secant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\asec')) {
+ function asec($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ return new Complex(INF);
+ }
+
+ return acos(inverse($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/asech.php b/vendor/markbaker/complex/classes/src/functions/asech.php
new file mode 100644
index 0000000..a1571a1
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/asech.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asech() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic secant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse hyperbolic secant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\asech')) {
+ function asech($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ return new Complex(INF);
+ }
+
+ return acosh(inverse($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/asin.php b/vendor/markbaker/complex/classes/src/functions/asin.php
new file mode 100644
index 0000000..05790ff
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/asin.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asin() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse sine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse sine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\asin')) {
+ function asin($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ $square = multiply($complex, $complex);
+ $invsqrt = new Complex(1.0);
+ $invsqrt = subtract($invsqrt, $square);
+ $invsqrt = sqrt($invsqrt);
+ $adjust = new Complex(
+ $invsqrt->getReal() - $complex->getImaginary(),
+ $invsqrt->getImaginary() + $complex->getReal()
+ );
+ $log = ln($adjust);
+
+ return new Complex(
+ $log->getImaginary(),
+ -1 * $log->getReal()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/asinh.php b/vendor/markbaker/complex/classes/src/functions/asinh.php
new file mode 100644
index 0000000..cee7610
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/asinh.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asinh() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic sine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse hyperbolic sine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\asinh')) {
+ function asinh($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal() && ($complex->getReal() > 1)) {
+ return new Complex(\asinh($complex->getReal()));
+ }
+
+ $asinh = clone $complex;
+ $asinh = $asinh->reverse()
+ ->invertReal();
+ $asinh = asin($asinh);
+ return $asinh->reverse()
+ ->invertImaginary();
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/atan.php b/vendor/markbaker/complex/classes/src/functions/atan.php
new file mode 100644
index 0000000..e026e7a
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/atan.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ *
+ * Function code for the complex atan() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+//include_once 'Math/Complex.php';
+//include_once 'Math/ComplexOp.php';
+
+/**
+ * Returns the inverse tangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse tangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\atan')) {
+ function atan($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal()) {
+ return new Complex(\atan($complex->getReal()));
+ }
+
+ $t1Value = new Complex(-1 * $complex->getImaginary(), $complex->getReal());
+ $uValue = new Complex(1, 0);
+
+ $d1Value = clone $uValue;
+ $d1Value = subtract($d1Value, $t1Value);
+ $d2Value = add($t1Value, $uValue);
+ $uResult = $d1Value->divideBy($d2Value);
+ $uResult = ln($uResult);
+
+ return new Complex(
+ (($uResult->getImaginary() == M_PI) ? -M_PI : $uResult->getImaginary()) * -0.5,
+ $uResult->getReal() * 0.5,
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/atanh.php b/vendor/markbaker/complex/classes/src/functions/atanh.php
new file mode 100644
index 0000000..d1e60e6
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/atanh.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ *
+ * Function code for the complex atanh() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic tangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse hyperbolic tangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\atanh')) {
+ function atanh($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal()) {
+ $real = $complex->getReal();
+ if ($real >= -1.0 && $real <= 1.0) {
+ return new Complex(\atanh($real));
+ } else {
+ return new Complex(\atanh(1 / $real), (($real < 0.0) ? M_PI_2 : -1 * M_PI_2));
+ }
+ }
+
+ $iComplex = clone $complex;
+ $iComplex = $iComplex->invertImaginary()
+ ->reverse();
+ return atan($iComplex)
+ ->invertReal()
+ ->reverse();
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/conjugate.php b/vendor/markbaker/complex/classes/src/functions/conjugate.php
new file mode 100644
index 0000000..d394ab5
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/conjugate.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ *
+ * Function code for the complex conjugate() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the complex conjugate of a complex number
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The conjugate of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\conjugate')) {
+ function conjugate($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ return new Complex(
+ $complex->getReal(),
+ -1 * $complex->getImaginary(),
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/cos.php b/vendor/markbaker/complex/classes/src/functions/cos.php
new file mode 100644
index 0000000..84fd51f
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/cos.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ *
+ * Function code for the complex cos() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the cosine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The cosine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\cos')) {
+ function cos($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal()) {
+ return new Complex(\cos($complex->getReal()));
+ }
+
+ return conjugate(
+ new Complex(
+ \cos($complex->getReal()) * \cosh($complex->getImaginary()),
+ \sin($complex->getReal()) * \sinh($complex->getImaginary()),
+ $complex->getSuffix()
+ )
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/cosh.php b/vendor/markbaker/complex/classes/src/functions/cosh.php
new file mode 100644
index 0000000..531ae52
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/cosh.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex cosh() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic cosine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The hyperbolic cosine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\cosh')) {
+ function cosh($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal()) {
+ return new Complex(\cosh($complex->getReal()));
+ }
+
+ return new Complex(
+ \cosh($complex->getReal()) * \cos($complex->getImaginary()),
+ \sinh($complex->getReal()) * \sin($complex->getImaginary()),
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/cot.php b/vendor/markbaker/complex/classes/src/functions/cot.php
new file mode 100644
index 0000000..b775458
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/cot.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex cot() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the cotangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The cotangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\cot')) {
+ function cot($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ return new Complex(INF);
+ }
+
+ return inverse(tan($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/coth.php b/vendor/markbaker/complex/classes/src/functions/coth.php
new file mode 100644
index 0000000..6944d77
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/coth.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the complex coth() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic cotangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The hyperbolic cotangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\coth')) {
+ function coth($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+ return inverse(tanh($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/csc.php b/vendor/markbaker/complex/classes/src/functions/csc.php
new file mode 100644
index 0000000..a2782a8
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/csc.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex csc() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the cosecant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The cosecant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\csc')) {
+ function csc($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ return new Complex(INF);
+ }
+
+ return inverse(sin($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/csch.php b/vendor/markbaker/complex/classes/src/functions/csch.php
new file mode 100644
index 0000000..e714caa
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/csch.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex csch() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic cosecant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The hyperbolic cosecant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\csch')) {
+ function csch($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ return new Complex(INF);
+ }
+
+ return inverse(sinh($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/exp.php b/vendor/markbaker/complex/classes/src/functions/exp.php
new file mode 100644
index 0000000..cbc37e5
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/exp.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ *
+ * Function code for the complex exp() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the exponential of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The exponential of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\exp')) {
+ function exp($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if (($complex->getReal() == 0.0) && (\abs($complex->getImaginary()) == M_PI)) {
+ return new Complex(-1.0, 0.0);
+ }
+
+ $rho = \exp($complex->getReal());
+
+ return new Complex(
+ $rho * \cos($complex->getImaginary()),
+ $rho * \sin($complex->getImaginary()),
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/inverse.php b/vendor/markbaker/complex/classes/src/functions/inverse.php
new file mode 100644
index 0000000..9e879e7
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/inverse.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex inverse() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The inverse of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\inverse')) {
+ function inverse($complex): Complex
+ {
+ $complex = clone Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ throw new \InvalidArgumentException('Division by zero');
+ }
+
+ return $complex->divideInto(1.0);
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/ln.php b/vendor/markbaker/complex/classes/src/functions/ln.php
new file mode 100644
index 0000000..e011519
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/ln.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ *
+ * Function code for the complex ln() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the natural logarithm of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The natural logarithm of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If the real and the imaginary parts are both zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\ln')) {
+ function ln($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
+ throw new \InvalidArgumentException();
+ }
+
+ return new Complex(
+ \log(rho($complex)),
+ theta($complex),
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/log10.php b/vendor/markbaker/complex/classes/src/functions/log10.php
new file mode 100644
index 0000000..2efdc30
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/log10.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex log10() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the common logarithm (base 10) of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The common logarithm (base 10) of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If the real and the imaginary parts are both zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\log10')) {
+ function log10($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
+ throw new \InvalidArgumentException();
+ } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
+ return new Complex(\log10($complex->getReal()), 0.0, $complex->getSuffix());
+ }
+
+ return ln($complex)
+ ->multiply(\log10(Complex::EULER));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/log2.php b/vendor/markbaker/complex/classes/src/functions/log2.php
new file mode 100644
index 0000000..1b114bc
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/log2.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex log2() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the base-2 logarithm of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The base-2 logarithm of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If the real and the imaginary parts are both zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\log2')) {
+ function log2($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
+ throw new \InvalidArgumentException();
+ } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
+ return new Complex(\log($complex->getReal(), 2), 0.0, $complex->getSuffix());
+ }
+
+ return ln($complex)
+ ->multiply(\log(Complex::EULER, 2));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/negative.php b/vendor/markbaker/complex/classes/src/functions/negative.php
new file mode 100644
index 0000000..24e3ad7
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/negative.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ *
+ * Function code for the complex negative() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the negative of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The negative value of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ *
+ * @see rho
+ *
+ */
+if (!function_exists(__NAMESPACE__ . '\\negative')) {
+ function negative($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ return new Complex(
+ -1 * $complex->getReal(),
+ -1 * $complex->getImaginary(),
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/pow.php b/vendor/markbaker/complex/classes/src/functions/pow.php
new file mode 100644
index 0000000..326a41c
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/pow.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ *
+ * Function code for the complex pow() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns a complex number raised to a power.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @param float|integer $power The power to raise this value to
+ * @return Complex The complex argument raised to the real power.
+ * @throws Exception If the power argument isn't a valid real
+ */
+if (!function_exists(__NAMESPACE__ . '\\pow')) {
+ function pow($complex, $power): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if (!is_numeric($power)) {
+ throw new Exception('Power argument must be a real number');
+ }
+
+ if ($complex->getImaginary() == 0.0 && $complex->getReal() >= 0.0) {
+ return new Complex(\pow($complex->getReal(), $power));
+ }
+
+ $rValue = \sqrt(($complex->getReal() * $complex->getReal()) + ($complex->getImaginary() * $complex->getImaginary()));
+ $rPower = \pow($rValue, $power);
+ $theta = $complex->argument() * $power;
+ if ($theta == 0) {
+ return new Complex(1);
+ }
+
+ return new Complex($rPower * \cos($theta), $rPower * \sin($theta), $complex->getSuffix());
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/rho.php b/vendor/markbaker/complex/classes/src/functions/rho.php
new file mode 100644
index 0000000..dfc4049
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/rho.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ *
+ * Function code for the complex rho() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the rho of a complex number.
+ * This is the distance/radius from the centrepoint to the representation of the number in polar coordinates.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return float The rho value of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\rho')) {
+ function rho($complex): float
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ return \sqrt(
+ ($complex->getReal() * $complex->getReal()) +
+ ($complex->getImaginary() * $complex->getImaginary())
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/sec.php b/vendor/markbaker/complex/classes/src/functions/sec.php
new file mode 100644
index 0000000..e1a0b13
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/sec.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sec() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the secant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The secant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\sec')) {
+ function sec($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ return inverse(cos($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/sech.php b/vendor/markbaker/complex/classes/src/functions/sech.php
new file mode 100644
index 0000000..ae98514
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/sech.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sech() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic secant of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The hyperbolic secant of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\sech')) {
+ function sech($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ return inverse(cosh($complex));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/sin.php b/vendor/markbaker/complex/classes/src/functions/sin.php
new file mode 100644
index 0000000..6b8ec2f
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/sin.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sin() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the sine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The sine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\sin')) {
+ function sin($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal()) {
+ return new Complex(\sin($complex->getReal()));
+ }
+
+ return new Complex(
+ \sin($complex->getReal()) * \cosh($complex->getImaginary()),
+ \cos($complex->getReal()) * \sinh($complex->getImaginary()),
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/sinh.php b/vendor/markbaker/complex/classes/src/functions/sinh.php
new file mode 100644
index 0000000..6563422
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/sinh.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sinh() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic sine of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The hyperbolic sine of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\sinh')) {
+ function sinh($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal()) {
+ return new Complex(\sinh($complex->getReal()));
+ }
+
+ return new Complex(
+ \sinh($complex->getReal()) * \cos($complex->getImaginary()),
+ \cosh($complex->getReal()) * \sin($complex->getImaginary()),
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/sqrt.php b/vendor/markbaker/complex/classes/src/functions/sqrt.php
new file mode 100644
index 0000000..5753a86
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/sqrt.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sqrt() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the square root of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The Square root of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\sqrt')) {
+ function sqrt($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ $theta = theta($complex);
+ $delta1 = \cos($theta / 2);
+ $delta2 = \sin($theta / 2);
+ $rho = \sqrt(rho($complex));
+
+ return new Complex($delta1 * $rho, $delta2 * $rho, $complex->getSuffix());
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/tan.php b/vendor/markbaker/complex/classes/src/functions/tan.php
new file mode 100644
index 0000000..a6f9610
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/tan.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ *
+ * Function code for the complex tan() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the tangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The tangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\tan')) {
+ function tan($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->isReal()) {
+ return new Complex(\tan($complex->getReal()));
+ }
+
+ $real = $complex->getReal();
+ $imaginary = $complex->getImaginary();
+ $divisor = 1 + \pow(\tan($real), 2) * \pow(\tanh($imaginary), 2);
+ if ($divisor == 0.0) {
+ throw new \InvalidArgumentException('Division by zero');
+ }
+
+ return new Complex(
+ \pow(sech($imaginary)->getReal(), 2) * \tan($real) / $divisor,
+ \pow(sec($real)->getReal(), 2) * \tanh($imaginary) / $divisor,
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/tanh.php b/vendor/markbaker/complex/classes/src/functions/tanh.php
new file mode 100644
index 0000000..8a8ccdc
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/tanh.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ *
+ * Function code for the complex tanh() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic tangent of a complex number.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return Complex The hyperbolic tangent of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ * @throws \InvalidArgumentException If function would result in a division by zero
+ */
+if (!function_exists(__NAMESPACE__ . '\\tanh')) {
+ function tanh($complex): Complex
+ {
+ $complex = Complex::validateComplexArgument($complex);
+ $real = $complex->getReal();
+ $imaginary = $complex->getImaginary();
+ $divisor = \cos($imaginary) * \cos($imaginary) + \sinh($real) * \sinh($real);
+ if ($divisor == 0.0) {
+ throw new \InvalidArgumentException('Division by zero');
+ }
+
+ return new Complex(
+ \sinh($real) * \cosh($real) / $divisor,
+ 0.5 * \sin(2 * $imaginary) / $divisor,
+ $complex->getSuffix()
+ );
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/functions/theta.php b/vendor/markbaker/complex/classes/src/functions/theta.php
new file mode 100644
index 0000000..cdba45e
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/functions/theta.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ *
+ * Function code for the complex theta() function
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the theta of a complex number.
+ * This is the angle in radians from the real axis to the representation of the number in polar coordinates.
+ *
+ * @param Complex|mixed $complex Complex number or a numeric value.
+ * @return float The theta value of the complex argument.
+ * @throws Exception If argument isn't a valid real or complex number.
+ */
+if (!function_exists(__NAMESPACE__ . '\\theta')) {
+ function theta($complex): float
+ {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($complex->getReal() == 0.0) {
+ if ($complex->isReal()) {
+ return 0.0;
+ } elseif ($complex->getImaginary() < 0.0) {
+ return M_PI / -2;
+ }
+ return M_PI / 2;
+ } elseif ($complex->getReal() > 0.0) {
+ return \atan($complex->getImaginary() / $complex->getReal());
+ } elseif ($complex->getImaginary() < 0.0) {
+ return -(M_PI - \atan(\abs($complex->getImaginary()) / \abs($complex->getReal())));
+ }
+
+ return M_PI - \atan($complex->getImaginary() / \abs($complex->getReal()));
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/operations/add.php b/vendor/markbaker/complex/classes/src/operations/add.php
new file mode 100644
index 0000000..1c726be
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/operations/add.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ *
+ * Function code for the complex addition operation
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Adds two or more complex numbers
+ *
+ * @param array of string|integer|float|Complex $complexValues The numbers to add
+ * @return Complex
+ */
+if (!function_exists(__NAMESPACE__ . '\\add')) {
+ function add(...$complexValues): Complex
+ {
+ if (count($complexValues) < 2) {
+ throw new \Exception('This function requires at least 2 arguments');
+ }
+
+ $base = array_shift($complexValues);
+ $result = clone Complex::validateComplexArgument($base);
+
+ foreach ($complexValues as $complex) {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($result->isComplex() && $complex->isComplex() &&
+ $result->getSuffix() !== $complex->getSuffix()) {
+ throw new Exception('Suffix Mismatch');
+ }
+
+ $real = $result->getReal() + $complex->getReal();
+ $imaginary = $result->getImaginary() + $complex->getImaginary();
+
+ $result = new Complex(
+ $real,
+ $imaginary,
+ ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/operations/divideby.php b/vendor/markbaker/complex/classes/src/operations/divideby.php
new file mode 100644
index 0000000..8c84a88
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/operations/divideby.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ *
+ * Function code for the complex division operation
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Divides two or more complex numbers
+ *
+ * @param array of string|integer|float|Complex $complexValues The numbers to divide
+ * @return Complex
+ */
+if (!function_exists(__NAMESPACE__ . '\\divideby')) {
+ function divideby(...$complexValues): Complex
+ {
+ if (count($complexValues) < 2) {
+ throw new \Exception('This function requires at least 2 arguments');
+ }
+
+ $base = array_shift($complexValues);
+ $result = clone Complex::validateComplexArgument($base);
+
+ foreach ($complexValues as $complex) {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($result->isComplex() && $complex->isComplex() &&
+ $result->getSuffix() !== $complex->getSuffix()) {
+ throw new Exception('Suffix Mismatch');
+ }
+ if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+ throw new \InvalidArgumentException('Division by zero');
+ }
+
+ $delta1 = ($result->getReal() * $complex->getReal()) +
+ ($result->getImaginary() * $complex->getImaginary());
+ $delta2 = ($result->getImaginary() * $complex->getReal()) -
+ ($result->getReal() * $complex->getImaginary());
+ $delta3 = ($complex->getReal() * $complex->getReal()) +
+ ($complex->getImaginary() * $complex->getImaginary());
+
+ $real = $delta1 / $delta3;
+ $imaginary = $delta2 / $delta3;
+
+ $result = new Complex(
+ $real,
+ $imaginary,
+ ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/operations/divideinto.php b/vendor/markbaker/complex/classes/src/operations/divideinto.php
new file mode 100644
index 0000000..dff2174
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/operations/divideinto.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ *
+ * Function code for the complex division operation
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Divides two or more complex numbers
+ *
+ * @param array of string|integer|float|Complex $complexValues The numbers to divide
+ * @return Complex
+ */
+if (!function_exists(__NAMESPACE__ . '\\divideinto')) {
+ function divideinto(...$complexValues): Complex
+ {
+ if (count($complexValues) < 2) {
+ throw new \Exception('This function requires at least 2 arguments');
+ }
+
+ $base = array_shift($complexValues);
+ $result = clone Complex::validateComplexArgument($base);
+
+ foreach ($complexValues as $complex) {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($result->isComplex() && $complex->isComplex() &&
+ $result->getSuffix() !== $complex->getSuffix()) {
+ throw new Exception('Suffix Mismatch');
+ }
+ if ($result->getReal() == 0.0 && $result->getImaginary() == 0.0) {
+ throw new \InvalidArgumentException('Division by zero');
+ }
+
+ $delta1 = ($complex->getReal() * $result->getReal()) +
+ ($complex->getImaginary() * $result->getImaginary());
+ $delta2 = ($complex->getImaginary() * $result->getReal()) -
+ ($complex->getReal() * $result->getImaginary());
+ $delta3 = ($result->getReal() * $result->getReal()) +
+ ($result->getImaginary() * $result->getImaginary());
+
+ $real = $delta1 / $delta3;
+ $imaginary = $delta2 / $delta3;
+
+ $result = new Complex(
+ $real,
+ $imaginary,
+ ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/operations/multiply.php b/vendor/markbaker/complex/classes/src/operations/multiply.php
new file mode 100644
index 0000000..60de4ce
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/operations/multiply.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ *
+ * Function code for the complex multiplication operation
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Multiplies two or more complex numbers
+ *
+ * @param array of string|integer|float|Complex $complexValues The numbers to multiply
+ * @return Complex
+ */
+if (!function_exists(__NAMESPACE__ . '\\multiply')) {
+ function multiply(...$complexValues): Complex
+ {
+ if (count($complexValues) < 2) {
+ throw new \Exception('This function requires at least 2 arguments');
+ }
+
+ $base = array_shift($complexValues);
+ $result = clone Complex::validateComplexArgument($base);
+
+ foreach ($complexValues as $complex) {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($result->isComplex() && $complex->isComplex() &&
+ $result->getSuffix() !== $complex->getSuffix()) {
+ throw new Exception('Suffix Mismatch');
+ }
+
+ $real = ($result->getReal() * $complex->getReal()) -
+ ($result->getImaginary() * $complex->getImaginary());
+ $imaginary = ($result->getReal() * $complex->getImaginary()) +
+ ($result->getImaginary() * $complex->getReal());
+
+ $result = new Complex(
+ $real,
+ $imaginary,
+ ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/markbaker/complex/classes/src/operations/subtract.php b/vendor/markbaker/complex/classes/src/operations/subtract.php
new file mode 100644
index 0000000..79427b5
--- /dev/null
+++ b/vendor/markbaker/complex/classes/src/operations/subtract.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ *
+ * Function code for the complex subtraction operation
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Complex;
+
+/**
+ * Subtracts two or more complex numbers
+ *
+ * @param array of string|integer|float|Complex $complexValues The numbers to subtract
+ * @return Complex
+ */
+if (!function_exists(__NAMESPACE__ . '\\subtract')) {
+ function subtract(...$complexValues): Complex
+ {
+ if (count($complexValues) < 2) {
+ throw new \Exception('This function requires at least 2 arguments');
+ }
+
+ $base = array_shift($complexValues);
+ $result = clone Complex::validateComplexArgument($base);
+
+ foreach ($complexValues as $complex) {
+ $complex = Complex::validateComplexArgument($complex);
+
+ if ($result->isComplex() && $complex->isComplex() &&
+ $result->getSuffix() !== $complex->getSuffix()) {
+ throw new Exception('Suffix Mismatch');
+ }
+
+ $real = $result->getReal() - $complex->getReal();
+ $imaginary = $result->getImaginary() - $complex->getImaginary();
+
+ $result = new Complex(
+ $real,
+ $imaginary,
+ ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/markbaker/complex/composer.json b/vendor/markbaker/complex/composer.json
new file mode 100644
index 0000000..adc24dc
--- /dev/null
+++ b/vendor/markbaker/complex/composer.json
@@ -0,0 +1,77 @@
+{
+ "name": "markbaker/complex",
+ "type": "library",
+ "description": "PHP Class for working with complex numbers",
+ "keywords": ["complex", "mathematics"],
+ "homepage": "https://github.com/MarkBaker/PHPComplex",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Mark Baker",
+ "email": "mark@lange.demon.co.uk"
+ }
+ ],
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
+ "squizlabs/php_codesniffer": "^3.4",
+ "phpcompatibility/php-compatibility": "^9.0",
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Complex\\": "classes/src/"
+ },
+ "files": [
+ "classes/src/functions/abs.php",
+ "classes/src/functions/acos.php",
+ "classes/src/functions/acosh.php",
+ "classes/src/functions/acot.php",
+ "classes/src/functions/acoth.php",
+ "classes/src/functions/acsc.php",
+ "classes/src/functions/acsch.php",
+ "classes/src/functions/argument.php",
+ "classes/src/functions/asec.php",
+ "classes/src/functions/asech.php",
+ "classes/src/functions/asin.php",
+ "classes/src/functions/asinh.php",
+ "classes/src/functions/atan.php",
+ "classes/src/functions/atanh.php",
+ "classes/src/functions/conjugate.php",
+ "classes/src/functions/cos.php",
+ "classes/src/functions/cosh.php",
+ "classes/src/functions/cot.php",
+ "classes/src/functions/coth.php",
+ "classes/src/functions/csc.php",
+ "classes/src/functions/csch.php",
+ "classes/src/functions/exp.php",
+ "classes/src/functions/inverse.php",
+ "classes/src/functions/ln.php",
+ "classes/src/functions/log2.php",
+ "classes/src/functions/log10.php",
+ "classes/src/functions/negative.php",
+ "classes/src/functions/pow.php",
+ "classes/src/functions/rho.php",
+ "classes/src/functions/sec.php",
+ "classes/src/functions/sech.php",
+ "classes/src/functions/sin.php",
+ "classes/src/functions/sinh.php",
+ "classes/src/functions/sqrt.php",
+ "classes/src/functions/tan.php",
+ "classes/src/functions/tanh.php",
+ "classes/src/functions/theta.php",
+ "classes/src/operations/add.php",
+ "classes/src/operations/subtract.php",
+ "classes/src/operations/multiply.php",
+ "classes/src/operations/divideby.php",
+ "classes/src/operations/divideinto.php"
+ ]
+ },
+ "scripts": {
+ "style": "phpcs --report-width=200 --standard=PSR2 --report=summary,full classes/src/ unitTests/classes/src -n",
+ "versions": "phpcs --report-width=200 --standard=PHPCompatibility --report=summary,full classes/src/ --runtime-set testVersion 7.2- -n"
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/markbaker/complex/examples/complexTest.php b/vendor/markbaker/complex/examples/complexTest.php
new file mode 100644
index 0000000..d8aed62
--- /dev/null
+++ b/vendor/markbaker/complex/examples/complexTest.php
@@ -0,0 +1,154 @@
+<?php
+
+use Complex\Complex as Complex;
+
+include('../classes/Bootstrap.php');
+
+echo 'Create', PHP_EOL;
+
+$x = new Complex(123);
+echo $x, PHP_EOL;
+
+$x = new Complex(123, 456);
+echo $x, PHP_EOL;
+
+$x = new Complex(array(123,456,'j'));
+echo $x, PHP_EOL;
+
+$x = new Complex('1.23e-4--2.34e-5i');
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Add', PHP_EOL;
+
+$x = new Complex(123);
+$x->add(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->add(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->add(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->add(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->add(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->add(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Subtract', PHP_EOL;
+
+$x = new Complex(123);
+$x->subtract(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->subtract(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->subtract(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->subtract(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->subtract(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->subtract(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Multiply', PHP_EOL;
+
+$x = new Complex(123);
+$x->multiply(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->multiply(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->multiply(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->multiply(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->multiply(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->multiply(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Divide By', PHP_EOL;
+
+$x = new Complex(123);
+$x->divideBy(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->divideBy(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideBy(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideBy(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideBy(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideBy(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Divide Into', PHP_EOL;
+
+$x = new Complex(123);
+$x->divideInto(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->divideInto(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideInto(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideInto(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideInto(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideInto(new Complex(0, -1));
+echo $x, PHP_EOL;
diff --git a/vendor/markbaker/complex/examples/testFunctions.php b/vendor/markbaker/complex/examples/testFunctions.php
new file mode 100644
index 0000000..69cc7dc
--- /dev/null
+++ b/vendor/markbaker/complex/examples/testFunctions.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Complex;
+
+include('../classes/Bootstrap.php');
+
+echo 'Function Examples', PHP_EOL;
+
+$functions = array(
+ 'abs',
+ 'acos',
+ 'acosh',
+ 'acsc',
+ 'acsch',
+ 'argument',
+ 'asec',
+ 'asech',
+ 'asin',
+ 'asinh',
+ 'conjugate',
+ 'cos',
+ 'cosh',
+ 'csc',
+ 'csch',
+ 'exp',
+ 'inverse',
+ 'ln',
+ 'log2',
+ 'log10',
+ 'rho',
+ 'sec',
+ 'sech',
+ 'sin',
+ 'sinh',
+ 'sqrt',
+ 'theta'
+);
+
+for ($real = -3.5; $real <= 3.5; $real += 0.5) {
+ for ($imaginary = -3.5; $imaginary <= 3.5; $imaginary += 0.5) {
+ foreach ($functions as $function) {
+ $complexFunction = __NAMESPACE__ . '\\' . $function;
+ $complex = new Complex($real, $imaginary);
+ try {
+ echo $function, '(', $complex, ') = ', $complexFunction($complex), PHP_EOL;
+ } catch (\Exception $e) {
+ echo $function, '(', $complex, ') ERROR: ', $e->getMessage(), PHP_EOL;
+ }
+ }
+ echo PHP_EOL;
+ }
+}
diff --git a/vendor/markbaker/complex/examples/testOperations.php b/vendor/markbaker/complex/examples/testOperations.php
new file mode 100644
index 0000000..ee5699d
--- /dev/null
+++ b/vendor/markbaker/complex/examples/testOperations.php
@@ -0,0 +1,34 @@
+<?php
+
+use Complex\Complex as Complex;
+
+include('../classes/Bootstrap.php');
+
+$values = [
+ new Complex(123),
+ new Complex(456, 123),
+ new Complex(0.0, 456),
+];
+
+foreach ($values as $value) {
+ echo $value, PHP_EOL;
+}
+
+echo 'Addition', PHP_EOL;
+
+$result = \Complex\add(...$values);
+echo '=> ', $result, PHP_EOL;
+
+echo PHP_EOL;
+
+echo 'Subtraction', PHP_EOL;
+
+$result = \Complex\subtract(...$values);
+echo '=> ', $result, PHP_EOL;
+
+echo PHP_EOL;
+
+echo 'Multiplication', PHP_EOL;
+
+$result = \Complex\multiply(...$values);
+echo '=> ', $result, PHP_EOL;
diff --git a/vendor/markbaker/complex/license.md b/vendor/markbaker/complex/license.md
new file mode 100644
index 0000000..e123c90
--- /dev/null
+++ b/vendor/markbaker/complex/license.md
@@ -0,0 +1,25 @@
+The MIT License (MIT)
+=====================
+
+Copyright © `2017` `Mark Baker`
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the “Software”), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/markbaker/matrix/.github/workflows/main.yaml b/vendor/markbaker/matrix/.github/workflows/main.yaml
new file mode 100644
index 0000000..229fe04
--- /dev/null
+++ b/vendor/markbaker/matrix/.github/workflows/main.yaml
@@ -0,0 +1,124 @@
+name: main
+on: [ push, pull_request ]
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ php-version:
+ - '7.1'
+ - '7.2'
+ - '7.3'
+ - '7.4'
+ - '8.0'
+ - '8.1'
+ - '8.2'
+
+ include:
+ - php-version: 'nightly'
+ experimental: true
+
+ name: PHP ${{ matrix.php-version }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-version }}
+ extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
+ coverage: none
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v3
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Delete composer lock file
+ id: composer-lock
+ if: ${{ matrix.php-version == '8.0' || matrix.php-version == '8.1' || matrix.php-version == '8.2' || matrix.php-version == 'nightly' }}
+ run: |
+ rm composer.lock
+ echo "::set-output name=flags::--ignore-platform-reqs"
+
+ - name: Install dependencies
+ run: composer update --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }}
+
+ - name: Setup problem matchers for PHP
+ run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
+
+ - name: Setup problem matchers for PHPUnit
+ run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
+
+ - name: Test with PHPUnit
+ run: ./vendor/bin/phpunit
+
+ phpcs:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
+ coverage: none
+ tools: cs2pr
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v3
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --no-progress --prefer-dist --optimize-autoloader
+
+ - name: Code style with PHP_CodeSniffer
+ run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr --graceful-warnings --colorize
+
+ coverage:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
+ coverage: pcov
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v3
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --no-progress --prefer-dist --optimize-autoloader
+
+ - name: Coverage
+ run: |
+ ./vendor/bin/phpunit --coverage-text
diff --git a/vendor/markbaker/matrix/README.md b/vendor/markbaker/matrix/README.md
new file mode 100644
index 0000000..50f3580
--- /dev/null
+++ b/vendor/markbaker/matrix/README.md
@@ -0,0 +1,207 @@
+PHPMatrix
+==========
+
+---
+
+PHP Class for handling Matrices
+
+[![Build Status](https://travis-ci.org/MarkBaker/PHPMatrix.png?branch=2.0)](http://travis-ci.org/MarkBaker/PHPMatrix)
+
+[![Matrix Transform](https://imgs.xkcd.com/comics/matrix_transform.png)](https://xkcd.com/184/)
+
+Matrix Transform
+
+---
+
+This library currently provides the following operations:
+
+ - addition
+ - direct sum
+ - subtraction
+ - multiplication
+ - division (using [A].[B]<sup>-1</sup>)
+ - division by
+ - division into
+
+together with functions for
+
+ - adjoint
+ - antidiagonal
+ - cofactors
+ - determinant
+ - diagonal
+ - identity
+ - inverse
+ - minors
+ - trace
+ - transpose
+ - solve
+
+ Given Matrices A and B, calculate X for A.X = B
+
+and classes for
+
+ - Decomposition
+ - LU Decomposition with partial row pivoting,
+
+ such that [P].[A] = [L].[U] and [A] = [P]<sup>|</sup>.[L].[U]
+ - QR Decomposition
+
+ such that [A] = [Q].[R]
+
+## TO DO
+
+ - power() function
+ - Decomposition
+ - Cholesky Decomposition
+ - EigenValue Decomposition
+ - EigenValues
+ - EigenVectors
+
+---
+
+# Usage
+
+To create a new Matrix object, provide an array as the constructor argument
+
+```php
+$grid = [
+ [16, 3, 2, 13],
+ [ 5, 10, 11, 8],
+ [ 9, 6, 7, 12],
+ [ 4, 15, 14, 1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+```
+The `Builder` class provides helper methods for creating specific matrices, specifically an identity matrix of a specified size; or a matrix of a specified dimensions, with every cell containing a set value.
+```php
+$matrix = Matrix\Builder::createFilledMatrix(1, 5, 3);
+```
+Will create a matrix of 5 rows and 3 columns, filled with a `1` in every cell; while
+```php
+$matrix = Matrix\Builder::createIdentityMatrix(3);
+```
+will create a 3x3 identity matrix.
+
+
+Matrix objects are immutable: whenever you call a method or pass a grid to a function that returns a matrix value, a new Matrix object will be returned, and the original will remain unchanged. This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Matrix result).
+
+## Performing Mathematical Operations
+
+To perform mathematical operations with Matrices, you can call the appropriate method against a matrix value, passing other values as arguments
+
+```php
+$matrix1 = new Matrix\Matrix([
+ [2, 7, 6],
+ [9, 5, 1],
+ [4, 3, 8],
+]);
+$matrix2 = new Matrix\Matrix([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+]);
+
+var_dump($matrix1->multiply($matrix2)->toArray());
+```
+or pass all values to the appropriate function
+```php
+$matrix1 = new Matrix\Matrix([
+ [2, 7, 6],
+ [9, 5, 1],
+ [4, 3, 8],
+]);
+$matrix2 = new Matrix\Matrix([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+]);
+
+var_dump(Matrix\multiply($matrix1, $matrix2)->toArray());
+```
+You can pass in the arguments as Matrix objects, or as arrays.
+
+If you want to perform the same operation against multiple values (e.g. to add three or more matrices), then you can pass multiple arguments to any of the operations.
+
+## Using functions
+
+When calling any of the available functions for a matrix value, you can either call the relevant method for the Matrix object
+```php
+$grid = [
+ [16, 3, 2, 13],
+ [ 5, 10, 11, 8],
+ [ 9, 6, 7, 12],
+ [ 4, 15, 14, 1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+
+echo $matrix->trace();
+```
+or you can call the function as you would in procedural code, passing the Matrix object as an argument
+```php
+$grid = [
+ [16, 3, 2, 13],
+ [ 5, 10, 11, 8],
+ [ 9, 6, 7, 12],
+ [ 4, 15, 14, 1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+echo Matrix\trace($matrix);
+```
+When called procedurally using the function, you can pass in the argument as a Matrix object, or as an array.
+```php
+$grid = [
+ [16, 3, 2, 13],
+ [ 5, 10, 11, 8],
+ [ 9, 6, 7, 12],
+ [ 4, 15, 14, 1],
+];
+
+echo Matrix\trace($grid);
+```
+As an alternative, it is also possible to call the method directly from the `Functions` class.
+```php
+$grid = [
+ [16, 3, 2, 13],
+ [ 5, 10, 11, 8],
+ [ 9, 6, 7, 12],
+ [ 4, 15, 14, 1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+echo Matrix\Functions::trace($matrix);
+```
+Used this way, methods must be called statically, and the argument must be the Matrix object, and cannot be an array.
+
+## Decomposition
+
+The library also provides classes for matrix decomposition. You can access these using
+```php
+$grid = [
+ [1, 2],
+ [3, 4],
+];
+
+$matrix = new Matrix\Matrix($grid);
+
+$decomposition = new Matrix\Decomposition\QR($matrix);
+$Q = $decomposition->getQ();
+$R = $decomposition->getR();
+```
+
+or alternatively us the `Decomposition` factory, identifying which form of decomposition you want to use
+```php
+$grid = [
+ [1, 2],
+ [3, 4],
+];
+
+$matrix = new Matrix\Matrix($grid);
+
+$decomposition = Matrix\Decomposition\Decomposition::decomposition(Matrix\Decomposition\Decomposition::QR, $matrix);
+$Q = $decomposition->getQ();
+$R = $decomposition->getR();
+```
diff --git a/vendor/markbaker/matrix/buildPhar.php b/vendor/markbaker/matrix/buildPhar.php
new file mode 100644
index 0000000..8bec8be
--- /dev/null
+++ b/vendor/markbaker/matrix/buildPhar.php
@@ -0,0 +1,62 @@
+<?php
+
+# required: PHP 5.3+ and zlib extension
+
+// ini option check
+if (ini_get('phar.readonly')) {
+ echo "php.ini: set the 'phar.readonly' option to 0 to enable phar creation\n";
+ exit(1);
+}
+
+// output name
+$pharName = 'Matrix.phar';
+
+// target folder
+$sourceDir = __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;
+
+// default meta information
+$metaData = array(
+ 'Author' => 'Mark Baker <mark@lange.demon.co.uk>',
+ 'Description' => 'PHP Class for working with Matrix numbers',
+ 'Copyright' => 'Mark Baker (c) 2013-' . date('Y'),
+ 'Timestamp' => time(),
+ 'Version' => '0.1.0',
+ 'Date' => date('Y-m-d')
+);
+
+// cleanup
+if (file_exists($pharName)) {
+ echo "Removed: {$pharName}\n";
+ unlink($pharName);
+}
+
+echo "Building phar file...\n";
+
+// the phar object
+$phar = new Phar($pharName, null, 'Matrix');
+$phar->buildFromDirectory($sourceDir);
+$phar->setStub(
+<<<'EOT'
+<?php
+ spl_autoload_register(function ($className) {
+ include 'phar://' . $className . '.php';
+ });
+
+ try {
+ Phar::mapPhar();
+ } catch (PharException $e) {
+ error_log($e->getMessage());
+ exit(1);
+ }
+
+ include 'phar://functions/sqrt.php';
+
+ __HALT_COMPILER();
+EOT
+);
+$phar->setMetadata($metaData);
+$phar->compressFiles(Phar::GZ);
+
+echo "Complete.\n";
+
+exit();
diff --git a/vendor/markbaker/matrix/classes/src/Builder.php b/vendor/markbaker/matrix/classes/src/Builder.php
new file mode 100644
index 0000000..d075479
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Builder.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ *
+ * Class for the creating "special" Matrices
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Matrix Builder class.
+ *
+ * @package Matrix
+ */
+class Builder
+{
+ /**
+ * Create a new matrix of specified dimensions, and filled with a specified value
+ * If the column argument isn't provided, then a square matrix will be created
+ *
+ * @param mixed $fillValue
+ * @param int $rows
+ * @param int|null $columns
+ * @return Matrix
+ * @throws Exception
+ */
+ public static function createFilledMatrix($fillValue, $rows, $columns = null)
+ {
+ if ($columns === null) {
+ $columns = $rows;
+ }
+
+ $rows = Matrix::validateRow($rows);
+ $columns = Matrix::validateColumn($columns);
+
+ return new Matrix(
+ array_fill(
+ 0,
+ $rows,
+ array_fill(
+ 0,
+ $columns,
+ $fillValue
+ )
+ )
+ );
+ }
+
+ /**
+ * Create a new identity matrix of specified dimensions
+ * This will always be a square matrix, with the number of rows and columns matching the provided dimension
+ *
+ * @param int $dimensions
+ * @return Matrix
+ * @throws Exception
+ */
+ public static function createIdentityMatrix($dimensions, $fillValue = null)
+ {
+ $grid = static::createFilledMatrix($fillValue, $dimensions)->toArray();
+
+ for ($x = 0; $x < $dimensions; ++$x) {
+ $grid[$x][$x] = 1;
+ }
+
+ return new Matrix($grid);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php b/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php
new file mode 100644
index 0000000..d4e76f9
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Matrix\Decomposition;
+
+use Matrix\Exception;
+use Matrix\Matrix;
+
+class Decomposition
+{
+ const LU = 'LU';
+ const QR = 'QR';
+
+ /**
+ * @throws Exception
+ */
+ public static function decomposition($type, Matrix $matrix)
+ {
+ switch (strtoupper($type)) {
+ case self::LU:
+ return new LU($matrix);
+ case self::QR:
+ return new QR($matrix);
+ default:
+ throw new Exception('Invalid Decomposition');
+ }
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Decomposition/LU.php b/vendor/markbaker/matrix/classes/src/Decomposition/LU.php
new file mode 100644
index 0000000..0a92ed0
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Decomposition/LU.php
@@ -0,0 +1,260 @@
+<?php
+
+namespace Matrix\Decomposition;
+
+use Matrix\Exception;
+use Matrix\Matrix;
+
+class LU
+{
+ private $luMatrix;
+ private $rows;
+ private $columns;
+
+ private $pivot = [];
+
+ public function __construct(Matrix $matrix)
+ {
+ $this->luMatrix = $matrix->toArray();
+ $this->rows = $matrix->rows;
+ $this->columns = $matrix->columns;
+
+ $this->buildPivot();
+ }
+
+ /**
+ * Get lower triangular factor.
+ *
+ * @return Matrix Lower triangular factor
+ */
+ public function getL(): Matrix
+ {
+ $lower = [];
+
+ $columns = min($this->rows, $this->columns);
+ for ($row = 0; $row < $this->rows; ++$row) {
+ for ($column = 0; $column < $columns; ++$column) {
+ if ($row > $column) {
+ $lower[$row][$column] = $this->luMatrix[$row][$column];
+ } elseif ($row === $column) {
+ $lower[$row][$column] = 1.0;
+ } else {
+ $lower[$row][$column] = 0.0;
+ }
+ }
+ }
+
+ return new Matrix($lower);
+ }
+
+ /**
+ * Get upper triangular factor.
+ *
+ * @return Matrix Upper triangular factor
+ */
+ public function getU(): Matrix
+ {
+ $upper = [];
+
+ $rows = min($this->rows, $this->columns);
+ for ($row = 0; $row < $rows; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ if ($row <= $column) {
+ $upper[$row][$column] = $this->luMatrix[$row][$column];
+ } else {
+ $upper[$row][$column] = 0.0;
+ }
+ }
+ }
+
+ return new Matrix($upper);
+ }
+
+ /**
+ * Return pivot permutation vector.
+ *
+ * @return Matrix Pivot matrix
+ */
+ public function getP(): Matrix
+ {
+ $pMatrix = [];
+
+ $pivots = $this->pivot;
+ $pivotCount = count($pivots);
+ foreach ($pivots as $row => $pivot) {
+ $pMatrix[$row] = array_fill(0, $pivotCount, 0);
+ $pMatrix[$row][$pivot] = 1;
+ }
+
+ return new Matrix($pMatrix);
+ }
+
+ /**
+ * Return pivot permutation vector.
+ *
+ * @return array Pivot vector
+ */
+ public function getPivot(): array
+ {
+ return $this->pivot;
+ }
+
+ /**
+ * Is the matrix nonsingular?
+ *
+ * @return bool true if U, and hence A, is nonsingular
+ */
+ public function isNonsingular(): bool
+ {
+ for ($diagonal = 0; $diagonal < $this->columns; ++$diagonal) {
+ if ($this->luMatrix[$diagonal][$diagonal] === 0.0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private function buildPivot(): void
+ {
+ for ($row = 0; $row < $this->rows; ++$row) {
+ $this->pivot[$row] = $row;
+ }
+
+ for ($column = 0; $column < $this->columns; ++$column) {
+ $luColumn = $this->localisedReferenceColumn($column);
+
+ $this->applyTransformations($column, $luColumn);
+
+ $pivot = $this->findPivot($column, $luColumn);
+ if ($pivot !== $column) {
+ $this->pivotExchange($pivot, $column);
+ }
+
+ $this->computeMultipliers($column);
+
+ unset($luColumn);
+ }
+ }
+
+ private function localisedReferenceColumn($column): array
+ {
+ $luColumn = [];
+
+ for ($row = 0; $row < $this->rows; ++$row) {
+ $luColumn[$row] = &$this->luMatrix[$row][$column];
+ }
+
+ return $luColumn;
+ }
+
+ private function applyTransformations($column, array $luColumn): void
+ {
+ for ($row = 0; $row < $this->rows; ++$row) {
+ $luRow = $this->luMatrix[$row];
+ // Most of the time is spent in the following dot product.
+ $kmax = min($row, $column);
+ $sValue = 0.0;
+ for ($kValue = 0; $kValue < $kmax; ++$kValue) {
+ $sValue += $luRow[$kValue] * $luColumn[$kValue];
+ }
+ $luRow[$column] = $luColumn[$row] -= $sValue;
+ }
+ }
+
+ private function findPivot($column, array $luColumn): int
+ {
+ $pivot = $column;
+ for ($row = $column + 1; $row < $this->rows; ++$row) {
+ if (abs($luColumn[$row]) > abs($luColumn[$pivot])) {
+ $pivot = $row;
+ }
+ }
+
+ return $pivot;
+ }
+
+ private function pivotExchange($pivot, $column): void
+ {
+ for ($kValue = 0; $kValue < $this->columns; ++$kValue) {
+ $tValue = $this->luMatrix[$pivot][$kValue];
+ $this->luMatrix[$pivot][$kValue] = $this->luMatrix[$column][$kValue];
+ $this->luMatrix[$column][$kValue] = $tValue;
+ }
+
+ $lValue = $this->pivot[$pivot];
+ $this->pivot[$pivot] = $this->pivot[$column];
+ $this->pivot[$column] = $lValue;
+ }
+
+ private function computeMultipliers($diagonal): void
+ {
+ if (($diagonal < $this->rows) && ($this->luMatrix[$diagonal][$diagonal] != 0.0)) {
+ for ($row = $diagonal + 1; $row < $this->rows; ++$row) {
+ $this->luMatrix[$row][$diagonal] /= $this->luMatrix[$diagonal][$diagonal];
+ }
+ }
+ }
+
+ private function pivotB(Matrix $B): array
+ {
+ $X = [];
+ foreach ($this->pivot as $rowId) {
+ $row = $B->getRows($rowId + 1)->toArray();
+ $X[] = array_pop($row);
+ }
+
+ return $X;
+ }
+
+ /**
+ * Solve A*X = B.
+ *
+ * @param Matrix $B a Matrix with as many rows as A and any number of columns
+ *
+ * @throws Exception
+ *
+ * @return Matrix X so that L*U*X = B(piv,:)
+ */
+ public function solve(Matrix $B): Matrix
+ {
+ if ($B->rows !== $this->rows) {
+ throw new Exception('Matrix row dimensions are not equal');
+ }
+
+ if ($this->rows !== $this->columns) {
+ throw new Exception('LU solve() only works on square matrices');
+ }
+
+ if (!$this->isNonsingular()) {
+ throw new Exception('Can only perform operation on singular matrix');
+ }
+
+ // Copy right hand side with pivoting
+ $nx = $B->columns;
+ $X = $this->pivotB($B);
+
+ // Solve L*Y = B(piv,:)
+ for ($k = 0; $k < $this->columns; ++$k) {
+ for ($i = $k + 1; $i < $this->columns; ++$i) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k];
+ }
+ }
+ }
+
+ // Solve U*X = Y;
+ for ($k = $this->columns - 1; $k >= 0; --$k) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$k][$j] /= $this->luMatrix[$k][$k];
+ }
+ for ($i = 0; $i < $k; ++$i) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k];
+ }
+ }
+ }
+
+ return new Matrix($X);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Decomposition/QR.php b/vendor/markbaker/matrix/classes/src/Decomposition/QR.php
new file mode 100644
index 0000000..93bf414
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Decomposition/QR.php
@@ -0,0 +1,191 @@
+<?php
+
+namespace Matrix\Decomposition;
+
+use Matrix\Exception;
+use Matrix\Matrix;
+
+class QR
+{
+ private $qrMatrix;
+ private $rows;
+ private $columns;
+
+ private $rDiagonal = [];
+
+ public function __construct(Matrix $matrix)
+ {
+ $this->qrMatrix = $matrix->toArray();
+ $this->rows = $matrix->rows;
+ $this->columns = $matrix->columns;
+
+ $this->decompose();
+ }
+
+ public function getHouseholdVectors(): Matrix
+ {
+ $householdVectors = [];
+ for ($row = 0; $row < $this->rows; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ if ($row >= $column) {
+ $householdVectors[$row][$column] = $this->qrMatrix[$row][$column];
+ } else {
+ $householdVectors[$row][$column] = 0.0;
+ }
+ }
+ }
+
+ return new Matrix($householdVectors);
+ }
+
+ public function getQ(): Matrix
+ {
+ $qGrid = [];
+
+ $rowCount = $this->rows;
+ for ($k = $this->columns - 1; $k >= 0; --$k) {
+ for ($i = 0; $i < $this->rows; ++$i) {
+ $qGrid[$i][$k] = 0.0;
+ }
+ $qGrid[$k][$k] = 1.0;
+ if ($this->columns > $this->rows) {
+ $qGrid = array_slice($qGrid, 0, $this->rows);
+ }
+
+ for ($j = $k; $j < $this->columns; ++$j) {
+ if (isset($this->qrMatrix[$k], $this->qrMatrix[$k][$k]) && $this->qrMatrix[$k][$k] != 0.0) {
+ $s = 0.0;
+ for ($i = $k; $i < $this->rows; ++$i) {
+ $s += $this->qrMatrix[$i][$k] * $qGrid[$i][$j];
+ }
+ $s = -$s / $this->qrMatrix[$k][$k];
+ for ($i = $k; $i < $this->rows; ++$i) {
+ $qGrid[$i][$j] += $s * $this->qrMatrix[$i][$k];
+ }
+ }
+ }
+ }
+
+ array_walk(
+ $qGrid,
+ function (&$row) use ($rowCount) {
+ $row = array_reverse($row);
+ $row = array_slice($row, 0, $rowCount);
+ }
+ );
+
+ return new Matrix($qGrid);
+ }
+
+ public function getR(): Matrix
+ {
+ $rGrid = [];
+
+ for ($row = 0; $row < $this->columns; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ if ($row < $column) {
+ $rGrid[$row][$column] = $this->qrMatrix[$row][$column] ?? 0.0;
+ } elseif ($row === $column) {
+ $rGrid[$row][$column] = $this->rDiagonal[$row] ?? 0.0;
+ } else {
+ $rGrid[$row][$column] = 0.0;
+ }
+ }
+ }
+
+ if ($this->columns > $this->rows) {
+ $rGrid = array_slice($rGrid, 0, $this->rows);
+ }
+
+ return new Matrix($rGrid);
+ }
+
+ private function hypo($a, $b): float
+ {
+ if (abs($a) > abs($b)) {
+ $r = $b / $a;
+ $r = abs($a) * sqrt(1 + $r * $r);
+ } elseif ($b != 0.0) {
+ $r = $a / $b;
+ $r = abs($b) * sqrt(1 + $r * $r);
+ } else {
+ $r = 0.0;
+ }
+
+ return $r;
+ }
+
+ /**
+ * QR Decomposition computed by Householder reflections.
+ */
+ private function decompose(): void
+ {
+ for ($k = 0; $k < $this->columns; ++$k) {
+ // Compute 2-norm of k-th column without under/overflow.
+ $norm = 0.0;
+ for ($i = $k; $i < $this->rows; ++$i) {
+ $norm = $this->hypo($norm, $this->qrMatrix[$i][$k]);
+ }
+ if ($norm != 0.0) {
+ // Form k-th Householder vector.
+ if ($this->qrMatrix[$k][$k] < 0.0) {
+ $norm = -$norm;
+ }
+ for ($i = $k; $i < $this->rows; ++$i) {
+ $this->qrMatrix[$i][$k] /= $norm;
+ }
+ $this->qrMatrix[$k][$k] += 1.0;
+ // Apply transformation to remaining columns.
+ for ($j = $k + 1; $j < $this->columns; ++$j) {
+ $s = 0.0;
+ for ($i = $k; $i < $this->rows; ++$i) {
+ $s += $this->qrMatrix[$i][$k] * $this->qrMatrix[$i][$j];
+ }
+ $s = -$s / $this->qrMatrix[$k][$k];
+ for ($i = $k; $i < $this->rows; ++$i) {
+ $this->qrMatrix[$i][$j] += $s * $this->qrMatrix[$i][$k];
+ }
+ }
+ }
+ $this->rDiagonal[$k] = -$norm;
+ }
+ }
+
+ public function isFullRank(): bool
+ {
+ for ($j = 0; $j < $this->columns; ++$j) {
+ if ($this->rDiagonal[$j] == 0.0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Least squares solution of A*X = B.
+ *
+ * @param Matrix $B a Matrix with as many rows as A and any number of columns
+ *
+ * @throws Exception
+ *
+ * @return Matrix matrix that minimizes the two norm of Q*R*X-B
+ */
+ public function solve(Matrix $B): Matrix
+ {
+ if ($B->rows !== $this->rows) {
+ throw new Exception('Matrix row dimensions are not equal');
+ }
+
+ if (!$this->isFullRank()) {
+ throw new Exception('Can only perform this operation on a full-rank matrix');
+ }
+
+ // Compute Y = transpose(Q)*B
+ $Y = $this->getQ()->transpose()
+ ->multiply($B);
+ // Solve R*X = Y;
+ return $this->getR()->inverse()
+ ->multiply($Y);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Div0Exception.php b/vendor/markbaker/matrix/classes/src/Div0Exception.php
new file mode 100644
index 0000000..4cb51d6
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Div0Exception.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * Exception.
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Matrix;
+
+class Div0Exception extends Exception
+{
+}
diff --git a/vendor/markbaker/matrix/classes/src/Exception.php b/vendor/markbaker/matrix/classes/src/Exception.php
new file mode 100644
index 0000000..da684b3
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Exception.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * Exception.
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Matrix;
+
+class Exception extends \Exception
+{
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions.php b/vendor/markbaker/matrix/classes/src/Functions.php
new file mode 100644
index 0000000..fe7d11c
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions.php
@@ -0,0 +1,337 @@
+<?php
+
+namespace Matrix;
+
+class Functions
+{
+ /**
+ * Calculate the adjoint of the matrix
+ *
+ * @param Matrix $matrix The matrix whose adjoint we wish to calculate
+ * @return Matrix
+ *
+ * @throws Exception
+ */
+ private static function getAdjoint(Matrix $matrix)
+ {
+ return self::transpose(
+ self::getCofactors($matrix)
+ );
+ }
+
+ /**
+ * Return the adjoint of this matrix
+ * The adjugate, classical adjoint, or adjunct of a square matrix is the transpose of its cofactor matrix.
+ * The adjugate has sometimes been called the "adjoint", but today the "adjoint" of a matrix normally refers
+ * to its corresponding adjoint operator, which is its conjugate transpose.
+ *
+ * @param Matrix $matrix The matrix whose adjoint we wish to calculate
+ * @return Matrix
+ * @throws Exception
+ **/
+ public static function adjoint(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Adjoint can only be calculated for a square matrix');
+ }
+
+ return self::getAdjoint($matrix);
+ }
+
+ /**
+ * Calculate the cofactors of the matrix
+ *
+ * @param Matrix $matrix The matrix whose cofactors we wish to calculate
+ * @return Matrix
+ *
+ * @throws Exception
+ */
+ private static function getCofactors(Matrix $matrix)
+ {
+ $cofactors = self::getMinors($matrix);
+ $dimensions = $matrix->rows;
+
+ $cof = 1;
+ for ($i = 0; $i < $dimensions; ++$i) {
+ $cofs = $cof;
+ for ($j = 0; $j < $dimensions; ++$j) {
+ $cofactors[$i][$j] *= $cofs;
+ $cofs = -$cofs;
+ }
+ $cof = -$cof;
+ }
+
+ return new Matrix($cofactors);
+ }
+
+ /**
+ * Return the cofactors of this matrix
+ *
+ * @param Matrix $matrix The matrix whose cofactors we wish to calculate
+ * @return Matrix
+ *
+ * @throws Exception
+ */
+ public static function cofactors(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Cofactors can only be calculated for a square matrix');
+ }
+
+ return self::getCofactors($matrix);
+ }
+
+ /**
+ * @param Matrix $matrix
+ * @param int $row
+ * @param int $column
+ * @return float
+ * @throws Exception
+ */
+ private static function getDeterminantSegment(Matrix $matrix, $row, $column)
+ {
+ $tmpMatrix = $matrix->toArray();
+ unset($tmpMatrix[$row]);
+ array_walk(
+ $tmpMatrix,
+ function (&$row) use ($column) {
+ unset($row[$column]);
+ }
+ );
+
+ return self::getDeterminant(new Matrix($tmpMatrix));
+ }
+
+ /**
+ * Calculate the determinant of the matrix
+ *
+ * @param Matrix $matrix The matrix whose determinant we wish to calculate
+ * @return float
+ *
+ * @throws Exception
+ */
+ private static function getDeterminant(Matrix $matrix)
+ {
+ $dimensions = $matrix->rows;
+ $determinant = 0;
+
+ switch ($dimensions) {
+ case 1:
+ $determinant = $matrix->getValue(1, 1);
+ break;
+ case 2:
+ $determinant = $matrix->getValue(1, 1) * $matrix->getValue(2, 2) -
+ $matrix->getValue(1, 2) * $matrix->getValue(2, 1);
+ break;
+ default:
+ for ($i = 1; $i <= $dimensions; ++$i) {
+ $det = $matrix->getValue(1, $i) * self::getDeterminantSegment($matrix, 0, $i - 1);
+ if (($i % 2) == 0) {
+ $determinant -= $det;
+ } else {
+ $determinant += $det;
+ }
+ }
+ break;
+ }
+
+ return $determinant;
+ }
+
+ /**
+ * Return the determinant of this matrix
+ *
+ * @param Matrix $matrix The matrix whose determinant we wish to calculate
+ * @return float
+ * @throws Exception
+ **/
+ public static function determinant(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Determinant can only be calculated for a square matrix');
+ }
+
+ return self::getDeterminant($matrix);
+ }
+
+ /**
+ * Return the diagonal of this matrix
+ *
+ * @param Matrix $matrix The matrix whose diagonal we wish to calculate
+ * @return Matrix
+ * @throws Exception
+ **/
+ public static function diagonal(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Diagonal can only be extracted from a square matrix');
+ }
+
+ $dimensions = $matrix->rows;
+ $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
+ ->toArray();
+
+ for ($i = 0; $i < $dimensions; ++$i) {
+ $grid[$i][$i] = $matrix->getValue($i + 1, $i + 1);
+ }
+
+ return new Matrix($grid);
+ }
+
+ /**
+ * Return the antidiagonal of this matrix
+ *
+ * @param Matrix $matrix The matrix whose antidiagonal we wish to calculate
+ * @return Matrix
+ * @throws Exception
+ **/
+ public static function antidiagonal(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Anti-Diagonal can only be extracted from a square matrix');
+ }
+
+ $dimensions = $matrix->rows;
+ $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
+ ->toArray();
+
+ for ($i = 0; $i < $dimensions; ++$i) {
+ $grid[$i][$dimensions - $i - 1] = $matrix->getValue($i + 1, $dimensions - $i);
+ }
+
+ return new Matrix($grid);
+ }
+
+ /**
+ * Return the identity matrix
+ * The identity matrix, or sometimes ambiguously called a unit matrix, of size n is the n × n square matrix
+ * with ones on the main diagonal and zeros elsewhere
+ *
+ * @param Matrix $matrix The matrix whose identity we wish to calculate
+ * @return Matrix
+ * @throws Exception
+ **/
+ public static function identity(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Identity can only be created for a square matrix');
+ }
+
+ $dimensions = $matrix->rows;
+
+ return Builder::createIdentityMatrix($dimensions);
+ }
+
+ /**
+ * Return the inverse of this matrix
+ *
+ * @param Matrix $matrix The matrix whose inverse we wish to calculate
+ * @return Matrix
+ * @throws Exception
+ **/
+ public static function inverse(Matrix $matrix, string $type = 'inverse')
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception(ucfirst($type) . ' can only be calculated for a square matrix');
+ }
+
+ $determinant = self::getDeterminant($matrix);
+ if ($determinant == 0.0) {
+ throw new Div0Exception(ucfirst($type) . ' can only be calculated for a matrix with a non-zero determinant');
+ }
+
+ if ($matrix->rows == 1) {
+ return new Matrix([[1 / $matrix->getValue(1, 1)]]);
+ }
+
+ return self::getAdjoint($matrix)
+ ->multiply(1 / $determinant);
+ }
+
+ /**
+ * Calculate the minors of the matrix
+ *
+ * @param Matrix $matrix The matrix whose minors we wish to calculate
+ * @return array[]
+ *
+ * @throws Exception
+ */
+ protected static function getMinors(Matrix $matrix)
+ {
+ $minors = $matrix->toArray();
+ $dimensions = $matrix->rows;
+ if ($dimensions == 1) {
+ return $minors;
+ }
+
+ for ($i = 0; $i < $dimensions; ++$i) {
+ for ($j = 0; $j < $dimensions; ++$j) {
+ $minors[$i][$j] = self::getDeterminantSegment($matrix, $i, $j);
+ }
+ }
+
+ return $minors;
+ }
+
+ /**
+ * Return the minors of the matrix
+ * The minor of a matrix A is the determinant of some smaller square matrix, cut down from A by removing one or
+ * more of its rows or columns.
+ * Minors obtained by removing just one row and one column from square matrices (first minors) are required for
+ * calculating matrix cofactors, which in turn are useful for computing both the determinant and inverse of
+ * square matrices.
+ *
+ * @param Matrix $matrix The matrix whose minors we wish to calculate
+ * @return Matrix
+ * @throws Exception
+ **/
+ public static function minors(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Minors can only be calculated for a square matrix');
+ }
+
+ return new Matrix(self::getMinors($matrix));
+ }
+
+ /**
+ * Return the trace of this matrix
+ * The trace is defined as the sum of the elements on the main diagonal (the diagonal from the upper left to the lower right)
+ * of the matrix
+ *
+ * @param Matrix $matrix The matrix whose trace we wish to calculate
+ * @return float
+ * @throws Exception
+ **/
+ public static function trace(Matrix $matrix)
+ {
+ if (!$matrix->isSquare()) {
+ throw new Exception('Trace can only be extracted from a square matrix');
+ }
+
+ $dimensions = $matrix->rows;
+ $result = 0;
+ for ($i = 1; $i <= $dimensions; ++$i) {
+ $result += $matrix->getValue($i, $i);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Return the transpose of this matrix
+ *
+ * @param Matrix $matrix The matrix whose transpose we wish to calculate
+ * @return Matrix
+ **/
+ public static function transpose(Matrix $matrix)
+ {
+ $array = array_values(array_merge([null], $matrix->toArray()));
+ $grid = call_user_func_array(
+ 'array_map',
+ $array
+ );
+
+ return new Matrix($grid);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/adjoint.php b/vendor/markbaker/matrix/classes/src/Functions/adjoint.php
new file mode 100644
index 0000000..aafbb0f
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/adjoint.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix adjoint() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the adjoint of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The new matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\adjoint')) {
+ function adjoint($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::adjoint($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/antidiagonal.php b/vendor/markbaker/matrix/classes/src/Functions/antidiagonal.php
new file mode 100644
index 0000000..8904912
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/antidiagonal.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix antidiagonal() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the antidiagonal of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The new matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\antidiagonal')) {
+ function antidiagonal($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::antidiagonal($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/cofactors.php b/vendor/markbaker/matrix/classes/src/Functions/cofactors.php
new file mode 100644
index 0000000..c071e45
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/cofactors.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix cofactors() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the cofactors of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The new matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\cofactors')) {
+ function cofactors($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::cofactors($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/determinant.php b/vendor/markbaker/matrix/classes/src/Functions/determinant.php
new file mode 100644
index 0000000..d3573ab
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/determinant.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix determinant() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the determinant of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return float Matrix determinant
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\determinant')) {
+ function determinant($matrix): float
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::determinant($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/diagonal.php b/vendor/markbaker/matrix/classes/src/Functions/diagonal.php
new file mode 100644
index 0000000..8993db3
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/diagonal.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix diagonal() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the diagonal of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The new matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\diagonal')) {
+ function diagonal($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::diagonal($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/identity.php b/vendor/markbaker/matrix/classes/src/Functions/identity.php
new file mode 100644
index 0000000..7f870db
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/identity.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix identity() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the identity of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The identity matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\identity')) {
+ function identity($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::identity($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/inverse.php b/vendor/markbaker/matrix/classes/src/Functions/inverse.php
new file mode 100644
index 0000000..4bf08d0
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/inverse.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix inverse() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the inverse of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The new matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\inverse')) {
+ function inverse($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::inverse($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/minors.php b/vendor/markbaker/matrix/classes/src/Functions/minors.php
new file mode 100644
index 0000000..f34833b
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/minors.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix minors() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the minors of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The new matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\minors')) {
+ function minors($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::minors($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/trace.php b/vendor/markbaker/matrix/classes/src/Functions/trace.php
new file mode 100644
index 0000000..0c395f6
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/trace.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix trace() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the trace of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return float The trace of the matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\trace')) {
+ function trace($matrix): float
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::trace($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Functions/transpose.php b/vendor/markbaker/matrix/classes/src/Functions/transpose.php
new file mode 100644
index 0000000..8413634
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Functions/transpose.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix transpose() function
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+/**
+ * Returns the transpose of a matrix or an array.
+ *
+ * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
+ * @return Matrix The transposed matrix
+ * @throws Exception If argument isn't a valid matrix or array.
+ */
+if (!function_exists(__NAMESPACE__ . '\\transpose')) {
+ function transpose($matrix): Matrix
+ {
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Must be Matrix or array');
+ }
+
+ return Functions::transpose($matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Matrix.php b/vendor/markbaker/matrix/classes/src/Matrix.php
new file mode 100644
index 0000000..bb0a268
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Matrix.php
@@ -0,0 +1,423 @@
+<?php
+
+/**
+ *
+ * Class for the management of Matrices
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+use Generator;
+use Matrix\Decomposition\LU;
+use Matrix\Decomposition\QR;
+
+/**
+ * Matrix object.
+ *
+ * @package Matrix
+ *
+ * @property-read int $rows The number of rows in the matrix
+ * @property-read int $columns The number of columns in the matrix
+ * @method Matrix antidiagonal()
+ * @method Matrix adjoint()
+ * @method Matrix cofactors()
+ * @method float determinant()
+ * @method Matrix diagonal()
+ * @method Matrix identity()
+ * @method Matrix inverse()
+ * @method Matrix pseudoInverse()
+ * @method Matrix minors()
+ * @method float trace()
+ * @method Matrix transpose()
+ * @method Matrix add(...$matrices)
+ * @method Matrix subtract(...$matrices)
+ * @method Matrix multiply(...$matrices)
+ * @method Matrix divideby(...$matrices)
+ * @method Matrix divideinto(...$matrices)
+ * @method Matrix directsum(...$matrices)
+ */
+class Matrix
+{
+ protected $rows;
+ protected $columns;
+ protected $grid = [];
+
+ /*
+ * Create a new Matrix object from an array of values
+ *
+ * @param array $grid
+ */
+ final public function __construct(array $grid)
+ {
+ $this->buildFromArray(array_values($grid));
+ }
+
+ /*
+ * Create a new Matrix object from an array of values
+ *
+ * @param array $grid
+ */
+ protected function buildFromArray(array $grid): void
+ {
+ $this->rows = count($grid);
+ $columns = array_reduce(
+ $grid,
+ function ($carry, $value) {
+ return max($carry, is_array($value) ? count($value) : 1);
+ }
+ );
+ $this->columns = $columns;
+
+ array_walk(
+ $grid,
+ function (&$value) use ($columns) {
+ if (!is_array($value)) {
+ $value = [$value];
+ }
+ $value = array_pad(array_values($value), $columns, null);
+ }
+ );
+
+ $this->grid = $grid;
+ }
+
+ /**
+ * Validate that a row number is a positive integer
+ *
+ * @param int $row
+ * @return int
+ * @throws Exception
+ */
+ public static function validateRow(int $row): int
+ {
+ if ((!is_numeric($row)) || (intval($row) < 1)) {
+ throw new Exception('Invalid Row');
+ }
+
+ return (int)$row;
+ }
+
+ /**
+ * Validate that a column number is a positive integer
+ *
+ * @param int $column
+ * @return int
+ * @throws Exception
+ */
+ public static function validateColumn(int $column): int
+ {
+ if ((!is_numeric($column)) || (intval($column) < 1)) {
+ throw new Exception('Invalid Column');
+ }
+
+ return (int)$column;
+ }
+
+ /**
+ * Validate that a row number falls within the set of rows for this matrix
+ *
+ * @param int $row
+ * @return int
+ * @throws Exception
+ */
+ protected function validateRowInRange(int $row): int
+ {
+ $row = static::validateRow($row);
+ if ($row > $this->rows) {
+ throw new Exception('Requested Row exceeds matrix size');
+ }
+
+ return $row;
+ }
+
+ /**
+ * Validate that a column number falls within the set of columns for this matrix
+ *
+ * @param int $column
+ * @return int
+ * @throws Exception
+ */
+ protected function validateColumnInRange(int $column): int
+ {
+ $column = static::validateColumn($column);
+ if ($column > $this->columns) {
+ throw new Exception('Requested Column exceeds matrix size');
+ }
+
+ return $column;
+ }
+
+ /**
+ * Return a new matrix as a subset of rows from this matrix, starting at row number $row, and $rowCount rows
+ * A $rowCount value of 0 will return all rows of the matrix from $row
+ * A negative $rowCount value will return rows until that many rows from the end of the matrix
+ *
+ * Note that row numbers start from 1, not from 0
+ *
+ * @param int $row
+ * @param int $rowCount
+ * @return static
+ * @throws Exception
+ */
+ public function getRows(int $row, int $rowCount = 1): Matrix
+ {
+ $row = $this->validateRowInRange($row);
+ if ($rowCount === 0) {
+ $rowCount = $this->rows - $row + 1;
+ }
+
+ return new static(array_slice($this->grid, $row - 1, (int)$rowCount));
+ }
+
+ /**
+ * Return a new matrix as a subset of columns from this matrix, starting at column number $column, and $columnCount columns
+ * A $columnCount value of 0 will return all columns of the matrix from $column
+ * A negative $columnCount value will return columns until that many columns from the end of the matrix
+ *
+ * Note that column numbers start from 1, not from 0
+ *
+ * @param int $column
+ * @param int $columnCount
+ * @return Matrix
+ * @throws Exception
+ */
+ public function getColumns(int $column, int $columnCount = 1): Matrix
+ {
+ $column = $this->validateColumnInRange($column);
+ if ($columnCount < 1) {
+ $columnCount = $this->columns + $columnCount - $column + 1;
+ }
+
+ $grid = [];
+ for ($i = $column - 1; $i < $column + $columnCount - 1; ++$i) {
+ $grid[] = array_column($this->grid, $i);
+ }
+
+ return (new static($grid))->transpose();
+ }
+
+ /**
+ * Return a new matrix as a subset of rows from this matrix, dropping rows starting at row number $row,
+ * and $rowCount rows
+ * A negative $rowCount value will drop rows until that many rows from the end of the matrix
+ * A $rowCount value of 0 will remove all rows of the matrix from $row
+ *
+ * Note that row numbers start from 1, not from 0
+ *
+ * @param int $row
+ * @param int $rowCount
+ * @return static
+ * @throws Exception
+ */
+ public function dropRows(int $row, int $rowCount = 1): Matrix
+ {
+ $this->validateRowInRange($row);
+ if ($rowCount === 0) {
+ $rowCount = $this->rows - $row + 1;
+ }
+
+ $grid = $this->grid;
+ array_splice($grid, $row - 1, (int)$rowCount);
+
+ return new static($grid);
+ }
+
+ /**
+ * Return a new matrix as a subset of columns from this matrix, dropping columns starting at column number $column,
+ * and $columnCount columns
+ * A negative $columnCount value will drop columns until that many columns from the end of the matrix
+ * A $columnCount value of 0 will remove all columns of the matrix from $column
+ *
+ * Note that column numbers start from 1, not from 0
+ *
+ * @param int $column
+ * @param int $columnCount
+ * @return static
+ * @throws Exception
+ */
+ public function dropColumns(int $column, int $columnCount = 1): Matrix
+ {
+ $this->validateColumnInRange($column);
+ if ($columnCount < 1) {
+ $columnCount = $this->columns + $columnCount - $column + 1;
+ }
+
+ $grid = $this->grid;
+ array_walk(
+ $grid,
+ function (&$row) use ($column, $columnCount) {
+ array_splice($row, $column - 1, (int)$columnCount);
+ }
+ );
+
+ return new static($grid);
+ }
+
+ /**
+ * Return a value from this matrix, from the "cell" identified by the row and column numbers
+ * Note that row and column numbers start from 1, not from 0
+ *
+ * @param int $row
+ * @param int $column
+ * @return mixed
+ * @throws Exception
+ */
+ public function getValue(int $row, int $column)
+ {
+ $row = $this->validateRowInRange($row);
+ $column = $this->validateColumnInRange($column);
+
+ return $this->grid[$row - 1][$column - 1];
+ }
+
+ /**
+ * Returns a Generator that will yield each row of the matrix in turn as a vector matrix
+ * or the value of each cell if the matrix is a column vector
+ *
+ * @return Generator|Matrix[]|mixed[]
+ */
+ public function rows(): Generator
+ {
+ foreach ($this->grid as $i => $row) {
+ yield $i + 1 => ($this->columns == 1)
+ ? $row[0]
+ : new static([$row]);
+ }
+ }
+
+ /**
+ * Returns a Generator that will yield each column of the matrix in turn as a vector matrix
+ * or the value of each cell if the matrix is a row vector
+ *
+ * @return Generator|Matrix[]|mixed[]
+ */
+ public function columns(): Generator
+ {
+ for ($i = 0; $i < $this->columns; ++$i) {
+ yield $i + 1 => ($this->rows == 1)
+ ? $this->grid[0][$i]
+ : new static(array_column($this->grid, $i));
+ }
+ }
+
+ /**
+ * Identify if the row and column dimensions of this matrix are equal,
+ * i.e. if it is a "square" matrix
+ *
+ * @return bool
+ */
+ public function isSquare(): bool
+ {
+ return $this->rows === $this->columns;
+ }
+
+ /**
+ * Identify if this matrix is a vector
+ * i.e. if it comprises only a single row or a single column
+ *
+ * @return bool
+ */
+ public function isVector(): bool
+ {
+ return $this->rows === 1 || $this->columns === 1;
+ }
+
+ /**
+ * Return the matrix as a 2-dimensional array
+ *
+ * @return array
+ */
+ public function toArray(): array
+ {
+ return $this->grid;
+ }
+
+ /**
+ * Solve A*X = B.
+ *
+ * @param Matrix $B Right hand side
+ *
+ * @throws Exception
+ *
+ * @return Matrix ... Solution if A is square, least squares solution otherwise
+ */
+ public function solve(Matrix $B): Matrix
+ {
+ if ($this->columns === $this->rows) {
+ return (new LU($this))->solve($B);
+ }
+
+ return (new QR($this))->solve($B);
+ }
+
+ protected static $getters = [
+ 'rows',
+ 'columns',
+ ];
+
+ /**
+ * Access specific properties as read-only (no setters)
+ *
+ * @param string $propertyName
+ * @return mixed
+ * @throws Exception
+ */
+ public function __get(string $propertyName)
+ {
+ $propertyName = strtolower($propertyName);
+
+ // Test for function calls
+ if (in_array($propertyName, self::$getters)) {
+ return $this->$propertyName;
+ }
+
+ throw new Exception('Property does not exist');
+ }
+
+ protected static $functions = [
+ 'adjoint',
+ 'antidiagonal',
+ 'cofactors',
+ 'determinant',
+ 'diagonal',
+ 'identity',
+ 'inverse',
+ 'minors',
+ 'trace',
+ 'transpose',
+ ];
+
+ protected static $operations = [
+ 'add',
+ 'subtract',
+ 'multiply',
+ 'divideby',
+ 'divideinto',
+ 'directsum',
+ ];
+
+ /**
+ * Returns the result of the function call or operation
+ *
+ * @param string $functionName
+ * @param mixed[] $arguments
+ * @return Matrix|float
+ * @throws Exception
+ */
+ public function __call(string $functionName, $arguments)
+ {
+ $functionName = strtolower(str_replace('_', '', $functionName));
+
+ if (in_array($functionName, self::$functions, true) || in_array($functionName, self::$operations, true)) {
+ $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
+ if (is_callable($functionName)) {
+ $arguments = array_values(array_merge([$this], $arguments));
+ return call_user_func_array($functionName, $arguments);
+ }
+ }
+ throw new Exception('Function or Operation does not exist');
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operations/add.php b/vendor/markbaker/matrix/classes/src/Operations/add.php
new file mode 100644
index 0000000..5ac9a5e
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operations/add.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix addition operation
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+use Matrix\Operators\Addition;
+
+/**
+ * Adds two or more matrices
+ *
+ * @param array<int, mixed> $matrixValues The matrices to add
+ * @return Matrix
+ * @throws Exception
+ */
+if (!function_exists(__NAMESPACE__ . '\\add')) {
+ function add(...$matrixValues): Matrix
+ {
+ if (count($matrixValues) < 2) {
+ throw new Exception('Addition operation requires at least 2 arguments');
+ }
+
+ $matrix = array_shift($matrixValues);
+
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Addition arguments must be Matrix or array');
+ }
+
+ $result = new Addition($matrix);
+
+ foreach ($matrixValues as $matrix) {
+ $result->execute($matrix);
+ }
+
+ return $result->result();
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operations/directsum.php b/vendor/markbaker/matrix/classes/src/Operations/directsum.php
new file mode 100644
index 0000000..21c0c62
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operations/directsum.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix direct sum operation
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+use Matrix\Operators\DirectSum;
+
+/**
+ * Adds two or more matrices
+ *
+ * @param array<int, mixed> $matrixValues The matrices to add
+ * @return Matrix
+ * @throws Exception
+ */
+if (!function_exists(__NAMESPACE__ . '\\directsum')) {
+ function directsum(...$matrixValues): Matrix
+ {
+ if (count($matrixValues) < 2) {
+ throw new Exception('DirectSum operation requires at least 2 arguments');
+ }
+
+ $matrix = array_shift($matrixValues);
+
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('DirectSum arguments must be Matrix or array');
+ }
+
+ $result = new DirectSum($matrix);
+
+ foreach ($matrixValues as $matrix) {
+ $result->execute($matrix);
+ }
+
+ return $result->result();
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operations/divideby.php b/vendor/markbaker/matrix/classes/src/Operations/divideby.php
new file mode 100644
index 0000000..5dd0b19
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operations/divideby.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix division operation
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+use Matrix\Operators\Division;
+
+/**
+ * Divides two or more matrix numbers
+ *
+ * @param array<int, mixed> $matrixValues The matrices to divide
+ * @return Matrix
+ * @throws Exception
+ */
+if (!function_exists(__NAMESPACE__ . '\\divideby')) {
+ function divideby(...$matrixValues): Matrix
+ {
+ if (count($matrixValues) < 2) {
+ throw new Exception('Division operation requires at least 2 arguments');
+ }
+
+ $matrix = array_shift($matrixValues);
+
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Division arguments must be Matrix or array');
+ }
+
+ $result = new Division($matrix);
+
+ foreach ($matrixValues as $matrix) {
+ $result->execute($matrix);
+ }
+
+ return $result->result();
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operations/divideinto.php b/vendor/markbaker/matrix/classes/src/Operations/divideinto.php
new file mode 100644
index 0000000..dfbb2df
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operations/divideinto.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix division operation
+ *
+ * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+use Matrix\Operators\Division;
+
+/**
+ * Divides two or more matrix numbers
+ *
+ * @param array<int, mixed> $matrixValues The numbers to divide
+ * @return Matrix
+ * @throws Exception
+ */
+if (!function_exists(__NAMESPACE__ . '\\divideinto')) {
+ function divideinto(...$matrixValues): Matrix
+ {
+ if (count($matrixValues) < 2) {
+ throw new Exception('Division operation requires at least 2 arguments');
+ }
+
+ $matrix = array_pop($matrixValues);
+ $matrixValues = array_reverse($matrixValues);
+
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Division arguments must be Matrix or array');
+ }
+
+ $result = new Division($matrix);
+
+ foreach ($matrixValues as $matrix) {
+ $result->execute($matrix);
+ }
+
+ return $result->result();
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operations/multiply.php b/vendor/markbaker/matrix/classes/src/Operations/multiply.php
new file mode 100644
index 0000000..45ecc77
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operations/multiply.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix multiplication operation
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+use Matrix\Operators\Multiplication;
+
+/**
+ * Multiplies two or more matrices
+ *
+ * @param array<int, mixed> $matrixValues The matrices to multiply
+ * @return Matrix
+ * @throws Exception
+ */
+if (!function_exists(__NAMESPACE__ . '\\multiply')) {
+ function multiply(...$matrixValues): Matrix
+ {
+ if (count($matrixValues) < 2) {
+ throw new Exception('Multiplication operation requires at least 2 arguments');
+ }
+
+ $matrix = array_shift($matrixValues);
+
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Multiplication arguments must be Matrix or array');
+ }
+
+ $result = new Multiplication($matrix);
+
+ foreach ($matrixValues as $matrix) {
+ $result->execute($matrix);
+ }
+
+ return $result->result();
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operations/subtract.php b/vendor/markbaker/matrix/classes/src/Operations/subtract.php
new file mode 100644
index 0000000..72759b7
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operations/subtract.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix subtraction operation
+ *
+ * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license https://opensource.org/licenses/MIT MIT
+ */
+
+namespace Matrix;
+
+use Matrix\Operators\Subtraction;
+
+/**
+ * Subtracts two or more matrices
+ *
+ * @param array<int, mixed> $matrixValues The matrices to subtract
+ * @return Matrix
+ * @throws Exception
+ */
+if (!function_exists(__NAMESPACE__ . '\\subtract')) {
+ function subtract(...$matrixValues): Matrix
+ {
+ if (count($matrixValues) < 2) {
+ throw new Exception('Subtraction operation requires at least 2 arguments');
+ }
+
+ $matrix = array_shift($matrixValues);
+
+ if (is_array($matrix)) {
+ $matrix = new Matrix($matrix);
+ }
+ if (!$matrix instanceof Matrix) {
+ throw new Exception('Subtraction arguments must be Matrix or array');
+ }
+
+ $result = new Subtraction($matrix);
+
+ foreach ($matrixValues as $matrix) {
+ $result->execute($matrix);
+ }
+
+ return $result->result();
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operators/Addition.php b/vendor/markbaker/matrix/classes/src/Operators/Addition.php
new file mode 100644
index 0000000..87bd342
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operators/Addition.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+class Addition extends Operator
+{
+ /**
+ * Execute the addition
+ *
+ * @param mixed $value The matrix or numeric value to add to the current base value
+ * @throws Exception If the provided argument is not appropriate for the operation
+ * @return $this The operation object, allowing multiple additions to be chained
+ **/
+ public function execute($value): Operator
+ {
+ if (is_array($value)) {
+ $value = new Matrix($value);
+ }
+
+ if (is_object($value) && ($value instanceof Matrix)) {
+ return $this->addMatrix($value);
+ } elseif (is_numeric($value)) {
+ return $this->addScalar($value);
+ }
+
+ throw new Exception('Invalid argument for addition');
+ }
+
+ /**
+ * Execute the addition for a scalar
+ *
+ * @param mixed $value The numeric value to add to the current base value
+ * @return $this The operation object, allowing multiple additions to be chained
+ **/
+ protected function addScalar($value): Operator
+ {
+ for ($row = 0; $row < $this->rows; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ $this->matrix[$row][$column] += $value;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Execute the addition for a matrix
+ *
+ * @param Matrix $value The numeric value to add to the current base value
+ * @return $this The operation object, allowing multiple additions to be chained
+ * @throws Exception If the provided argument is not appropriate for the operation
+ **/
+ protected function addMatrix(Matrix $value): Operator
+ {
+ $this->validateMatchingDimensions($value);
+
+ for ($row = 0; $row < $this->rows; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ $this->matrix[$row][$column] += $value->getValue($row + 1, $column + 1);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php b/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php
new file mode 100644
index 0000000..e729a43
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+class DirectSum extends Operator
+{
+ /**
+ * Execute the addition
+ *
+ * @param mixed $value The matrix or numeric value to add to the current base value
+ * @return $this The operation object, allowing multiple additions to be chained
+ * @throws Exception If the provided argument is not appropriate for the operation
+ */
+ public function execute($value): Operator
+ {
+ if (is_array($value)) {
+ $value = new Matrix($value);
+ }
+
+ if ($value instanceof Matrix) {
+ return $this->directSumMatrix($value);
+ }
+
+ throw new Exception('Invalid argument for addition');
+ }
+
+ /**
+ * Execute the direct sum for a matrix
+ *
+ * @param Matrix $value The numeric value to concatenate/direct sum with the current base value
+ * @return $this The operation object, allowing multiple additions to be chained
+ **/
+ private function directSumMatrix($value): Operator
+ {
+ $originalColumnCount = count($this->matrix[0]);
+ $originalRowCount = count($this->matrix);
+ $valColumnCount = $value->columns;
+ $valRowCount = $value->rows;
+ $value = $value->toArray();
+
+ for ($row = 0; $row < $this->rows; ++$row) {
+ $this->matrix[$row] = array_merge($this->matrix[$row], array_fill(0, $valColumnCount, 0));
+ }
+
+ $this->matrix = array_merge(
+ $this->matrix,
+ array_fill(0, $valRowCount, array_fill(0, $originalColumnCount, 0))
+ );
+
+ for ($row = $originalRowCount; $row < $originalRowCount + $valRowCount; ++$row) {
+ array_splice(
+ $this->matrix[$row],
+ $originalColumnCount,
+ $valColumnCount,
+ $value[$row - $originalRowCount]
+ );
+ }
+
+ return $this;
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operators/Division.php b/vendor/markbaker/matrix/classes/src/Operators/Division.php
new file mode 100644
index 0000000..3cdedfb
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operators/Division.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Div0Exception;
+use Matrix\Exception;
+use \Matrix\Matrix;
+use \Matrix\Functions;
+
+class Division extends Multiplication
+{
+ /**
+ * Execute the division
+ *
+ * @param mixed $value The matrix or numeric value to divide the current base value by
+ * @throws Exception If the provided argument is not appropriate for the operation
+ * @return $this The operation object, allowing multiple divisions to be chained
+ **/
+ public function execute($value, string $type = 'division'): Operator
+ {
+ if (is_array($value)) {
+ $value = new Matrix($value);
+ }
+
+ if (is_object($value) && ($value instanceof Matrix)) {
+ $value = Functions::inverse($value, $type);
+
+ return $this->multiplyMatrix($value, $type);
+ } elseif (is_numeric($value)) {
+ return $this->multiplyScalar(1 / $value, $type);
+ }
+
+ throw new Exception('Invalid argument for division');
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php b/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php
new file mode 100644
index 0000000..13d14f0
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use \Matrix\Builder;
+use Matrix\Exception;
+use Throwable;
+
+class Multiplication extends Operator
+{
+ /**
+ * Execute the multiplication
+ *
+ * @param mixed $value The matrix or numeric value to multiply the current base value by
+ * @throws Exception If the provided argument is not appropriate for the operation
+ * @return $this The operation object, allowing multiple multiplications to be chained
+ **/
+ public function execute($value, string $type = 'multiplication'): Operator
+ {
+ if (is_array($value)) {
+ $value = new Matrix($value);
+ }
+
+ if (is_object($value) && ($value instanceof Matrix)) {
+ return $this->multiplyMatrix($value, $type);
+ } elseif (is_numeric($value)) {
+ return $this->multiplyScalar($value, $type);
+ }
+
+ throw new Exception("Invalid argument for $type");
+ }
+
+ /**
+ * Execute the multiplication for a scalar
+ *
+ * @param mixed $value The numeric value to multiply with the current base value
+ * @return $this The operation object, allowing multiple mutiplications to be chained
+ **/
+ protected function multiplyScalar($value, string $type = 'multiplication'): Operator
+ {
+ try {
+ for ($row = 0; $row < $this->rows; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ $this->matrix[$row][$column] *= $value;
+ }
+ }
+ } catch (Throwable $e) {
+ throw new Exception("Invalid argument for $type");
+ }
+
+ return $this;
+ }
+
+ /**
+ * Execute the multiplication for a matrix
+ *
+ * @param Matrix $value The numeric value to multiply with the current base value
+ * @return $this The operation object, allowing multiple mutiplications to be chained
+ * @throws Exception If the provided argument is not appropriate for the operation
+ **/
+ protected function multiplyMatrix(Matrix $value, string $type = 'multiplication'): Operator
+ {
+ $this->validateReflectingDimensions($value);
+
+ $newRows = $this->rows;
+ $newColumns = $value->columns;
+ $matrix = Builder::createFilledMatrix(0, $newRows, $newColumns)
+ ->toArray();
+ try {
+ for ($row = 0; $row < $newRows; ++$row) {
+ for ($column = 0; $column < $newColumns; ++$column) {
+ $columnData = $value->getColumns($column + 1)->toArray();
+ foreach ($this->matrix[$row] as $key => $valueData) {
+ $matrix[$row][$column] += $valueData * $columnData[$key][0];
+ }
+ }
+ }
+ } catch (Throwable $e) {
+ throw new Exception("Invalid argument for $type");
+ }
+ $this->matrix = $matrix;
+
+ return $this;
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operators/Operator.php b/vendor/markbaker/matrix/classes/src/Operators/Operator.php
new file mode 100644
index 0000000..b7f4025
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operators/Operator.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+abstract class Operator
+{
+ /**
+ * Stored internally as a 2-dimension array of values
+ *
+ * @property mixed[][] $matrix
+ **/
+ protected $matrix;
+
+ /**
+ * Number of rows in the matrix
+ *
+ * @property integer $rows
+ **/
+ protected $rows;
+
+ /**
+ * Number of columns in the matrix
+ *
+ * @property integer $columns
+ **/
+ protected $columns;
+
+ /**
+ * Create an new handler object for the operation
+ *
+ * @param Matrix $matrix The base Matrix object on which the operation will be performed
+ */
+ public function __construct(Matrix $matrix)
+ {
+ $this->rows = $matrix->rows;
+ $this->columns = $matrix->columns;
+ $this->matrix = $matrix->toArray();
+ }
+
+ /**
+ * Compare the dimensions of the matrices being operated on to see if they are valid for addition/subtraction
+ *
+ * @param Matrix $matrix The second Matrix object on which the operation will be performed
+ * @throws Exception
+ */
+ protected function validateMatchingDimensions(Matrix $matrix): void
+ {
+ if (($this->rows != $matrix->rows) || ($this->columns != $matrix->columns)) {
+ throw new Exception('Matrices have mismatched dimensions');
+ }
+ }
+
+ /**
+ * Compare the dimensions of the matrices being operated on to see if they are valid for multiplication/division
+ *
+ * @param Matrix $matrix The second Matrix object on which the operation will be performed
+ * @throws Exception
+ */
+ protected function validateReflectingDimensions(Matrix $matrix): void
+ {
+ if ($this->columns != $matrix->rows) {
+ throw new Exception('Matrices have mismatched dimensions');
+ }
+ }
+
+ /**
+ * Return the result of the operation
+ *
+ * @return Matrix
+ */
+ public function result(): Matrix
+ {
+ return new Matrix($this->matrix);
+ }
+}
diff --git a/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php b/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php
new file mode 100644
index 0000000..14b3541
--- /dev/null
+++ b/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+class Subtraction extends Operator
+{
+ /**
+ * Execute the subtraction
+ *
+ * @param mixed $value The matrix or numeric value to subtract from the current base value
+ * @throws Exception If the provided argument is not appropriate for the operation
+ * @return $this The operation object, allowing multiple subtractions to be chained
+ **/
+ public function execute($value): Operator
+ {
+ if (is_array($value)) {
+ $value = new Matrix($value);
+ }
+
+ if (is_object($value) && ($value instanceof Matrix)) {
+ return $this->subtractMatrix($value);
+ } elseif (is_numeric($value)) {
+ return $this->subtractScalar($value);
+ }
+
+ throw new Exception('Invalid argument for subtraction');
+ }
+
+ /**
+ * Execute the subtraction for a scalar
+ *
+ * @param mixed $value The numeric value to subtracted from the current base value
+ * @return $this The operation object, allowing multiple additions to be chained
+ **/
+ protected function subtractScalar($value): Operator
+ {
+ for ($row = 0; $row < $this->rows; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ $this->matrix[$row][$column] -= $value;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Execute the subtraction for a matrix
+ *
+ * @param Matrix $value The numeric value to subtract from the current base value
+ * @return $this The operation object, allowing multiple subtractions to be chained
+ * @throws Exception If the provided argument is not appropriate for the operation
+ **/
+ protected function subtractMatrix(Matrix $value): Operator
+ {
+ $this->validateMatchingDimensions($value);
+
+ for ($row = 0; $row < $this->rows; ++$row) {
+ for ($column = 0; $column < $this->columns; ++$column) {
+ $this->matrix[$row][$column] -= $value->getValue($row + 1, $column + 1);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/vendor/markbaker/matrix/composer.json b/vendor/markbaker/matrix/composer.json
new file mode 100644
index 0000000..22c9be5
--- /dev/null
+++ b/vendor/markbaker/matrix/composer.json
@@ -0,0 +1,89 @@
+{
+ "name": "markbaker/matrix",
+ "type": "library",
+ "description": "PHP Class for working with matrices",
+ "keywords": ["matrix", "vector", "mathematics"],
+ "homepage": "https://github.com/MarkBaker/PHPMatrix",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Mark Baker",
+ "email": "mark@demon-angel.eu"
+ }
+ ],
+ "config": {
+ "sort-packages": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
+ "phpdocumentor/phpdocumentor": "2.*",
+ "phpmd/phpmd": "2.*",
+ "sebastian/phpcpd": "^4.0",
+ "phploc/phploc": "^4.0",
+ "squizlabs/php_codesniffer": "^3.7",
+ "phpcompatibility/php-compatibility": "^9.3",
+ "dealerdirect/phpcodesniffer-composer-installer": "dev-master"
+ },
+ "autoload": {
+ "psr-4": {
+ "Matrix\\": "classes/src/"
+ },
+ "files": [
+ "classes/src/Functions/adjoint.php",
+ "classes/src/Functions/antidiagonal.php",
+ "classes/src/Functions/cofactors.php",
+ "classes/src/Functions/determinant.php",
+ "classes/src/Functions/diagonal.php",
+ "classes/src/Functions/identity.php",
+ "classes/src/Functions/inverse.php",
+ "classes/src/Functions/minors.php",
+ "classes/src/Functions/trace.php",
+ "classes/src/Functions/transpose.php",
+ "classes/src/Operations/add.php",
+ "classes/src/Operations/directsum.php",
+ "classes/src/Operations/subtract.php",
+ "classes/src/Operations/multiply.php",
+ "classes/src/Operations/divideby.php",
+ "classes/src/Operations/divideinto.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "MatrixTest\\": "unitTests/classes/src/"
+ },
+ "files": [
+ "classes/src/Functions/adjoint.php",
+ "classes/src/Functions/antidiagonal.php",
+ "classes/src/Functions/cofactors.php",
+ "classes/src/Functions/determinant.php",
+ "classes/src/Functions/diagonal.php",
+ "classes/src/Functions/identity.php",
+ "classes/src/Functions/inverse.php",
+ "classes/src/Functions/minors.php",
+ "classes/src/Functions/trace.php",
+ "classes/src/Functions/transpose.php",
+ "classes/src/Operations/add.php",
+ "classes/src/Operations/directsum.php",
+ "classes/src/Operations/subtract.php",
+ "classes/src/Operations/multiply.php",
+ "classes/src/Operations/divideby.php",
+ "classes/src/Operations/divideinto.php"
+ ]
+ },
+ "scripts": {
+ "style": "phpcs --report-width=200 --standard=PSR2 --report=summary,full classes/src/ unitTests/classes/src -n",
+ "test": "phpunit -c phpunit.xml.dist",
+ "mess": "phpmd classes/src/ xml codesize,unusedcode,design,naming -n",
+ "lines": "phploc classes/src/ -n",
+ "cpd": "phpcpd classes/src/ -n",
+ "versions": "phpcs --report-width=200 --standard=PHPCompatibility --report=summary,full classes/src/ --runtime-set testVersion 7.2- -n",
+ "coverage": "phpunit -c phpunit.xml.dist --coverage-text --coverage-html ./build/coverage"
+ },
+ "minimum-stability": "dev"
+} \ No newline at end of file
diff --git a/vendor/markbaker/matrix/examples/test.php b/vendor/markbaker/matrix/examples/test.php
new file mode 100644
index 0000000..001f9c6
--- /dev/null
+++ b/vendor/markbaker/matrix/examples/test.php
@@ -0,0 +1,33 @@
+<?php
+
+use Matrix\Matrix;
+use Matrix\Decomposition\QR;
+
+include __DIR__ . '/../vendor/autoload.php';
+
+$grid = [
+ [1, 2],
+ [3, 4],
+];
+
+$targetGrid = [
+ [-1],
+ [-2],
+];
+
+$matrix = new Matrix($grid);
+$target = new Matrix($targetGrid);
+
+$decomposition = new QR($matrix);
+
+$X = $decomposition->solve($target);
+
+echo 'X', PHP_EOL;
+var_export($X->toArray());
+echo PHP_EOL;
+
+$resolve = $matrix->multiply($X);
+
+echo 'Resolve', PHP_EOL;
+var_export($resolve->toArray());
+echo PHP_EOL;
diff --git a/vendor/markbaker/matrix/infection.json.dist b/vendor/markbaker/matrix/infection.json.dist
new file mode 100644
index 0000000..ec3b645
--- /dev/null
+++ b/vendor/markbaker/matrix/infection.json.dist
@@ -0,0 +1,17 @@
+{
+ "timeout": 1,
+ "source": {
+ "directories": [
+ "classes\/src"
+ ]
+ },
+ "logs": {
+ "text": "build/infection/text.log",
+ "summary": "build/infection/summary.log",
+ "debug": "build/infection/debug.log",
+ "perMutator": "build/infection/perMutator.md"
+ },
+ "mutators": {
+ "@default": true
+ }
+}
diff --git a/vendor/markbaker/matrix/license.md b/vendor/markbaker/matrix/license.md
new file mode 100644
index 0000000..491b1cc
--- /dev/null
+++ b/vendor/markbaker/matrix/license.md
@@ -0,0 +1,25 @@
+The MIT License (MIT)
+=====================
+
+Copyright © `2018` `Mark Baker`
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the “Software”), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/markbaker/matrix/phpstan.neon b/vendor/markbaker/matrix/phpstan.neon
new file mode 100644
index 0000000..8e254ef
--- /dev/null
+++ b/vendor/markbaker/matrix/phpstan.neon
@@ -0,0 +1,6 @@
+parameters:
+ ignoreErrors:
+ - '#Property [A-Za-z\\]+::\$[A-Za-z]+ has no typehint specified#'
+ - '#Method [A-Za-z\\]+::[A-Za-z]+\(\) has no return typehint specified#'
+ - '#Method [A-Za-z\\]+::[A-Za-z]+\(\) has parameter \$[A-Za-z0-9]+ with no typehint specified#'
+ checkMissingIterableValueType: false