Release of v4.1.1-alpha1
Move all banners to GitHub. Adds library phpspreadsheet to JCB. Add import item example to demo component. Updates the Superpower class with the GetRemote class in the plugin. Ensures the super power autoloader triggers the correct repositories.
This commit is contained in:
70
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Builder.php
vendored
Normal file
70
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Builder.php
vendored
Normal file
@@ -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);
|
||||
}
|
||||
}
|
27
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php
vendored
Normal file
27
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php
vendored
Normal file
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
260
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Decomposition/LU.php
vendored
Normal file
260
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Decomposition/LU.php
vendored
Normal file
@@ -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);
|
||||
}
|
||||
}
|
191
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Decomposition/QR.php
vendored
Normal file
191
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Decomposition/QR.php
vendored
Normal file
@@ -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);
|
||||
}
|
||||
}
|
13
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Div0Exception.php
vendored
Normal file
13
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Div0Exception.php
vendored
Normal file
@@ -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
|
||||
{
|
||||
}
|
13
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Exception.php
vendored
Normal file
13
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Exception.php
vendored
Normal file
@@ -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
|
||||
{
|
||||
}
|
376
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Functions.php
vendored
Normal file
376
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Functions.php
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
class Functions
|
||||
{
|
||||
/**
|
||||
* Validates an array of matrix, converting an array to a matrix if required.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
private static function validateMatrix($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return $matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|array $matrix The matrix whose adjoint we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function adjoint($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|array $matrix The matrix whose cofactors we wish to calculate
|
||||
* @return Matrix
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function cofactors($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|array $matrix The matrix whose determinant we wish to calculate
|
||||
* @return float
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function determinant($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|array $matrix The matrix whose diagonal we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function diagonal($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|array $matrix The matrix whose antidiagonal we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function antidiagonal($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|array $matrix The matrix whose identity we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function identity($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|array $matrix The matrix whose inverse we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function inverse($matrix, string $type = 'inverse')
|
||||
{
|
||||
$matrix = self::validateMatrix($matrix);
|
||||
|
||||
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|array $matrix The matrix whose minors we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function minors($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|array $matrix The matrix whose trace we wish to calculate
|
||||
* @return float
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function trace($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($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|\a $matrix The matrix whose transpose we wish to calculate
|
||||
* @return Matrix
|
||||
**/
|
||||
public static function transpose($matrix)
|
||||
{
|
||||
$matrix = self::validateMatrix($matrix);
|
||||
|
||||
$array = array_values(array_merge([null], $matrix->toArray()));
|
||||
$grid = call_user_func_array(
|
||||
'array_map',
|
||||
$array
|
||||
);
|
||||
|
||||
return new Matrix($grid);
|
||||
}
|
||||
}
|
423
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Matrix.php
vendored
Normal file
423
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Matrix.php
vendored
Normal file
@@ -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 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));
|
||||
|
||||
// Test for function calls
|
||||
if (in_array($functionName, self::$functions, true)) {
|
||||
return Functions::$functionName($this, ...$arguments);
|
||||
}
|
||||
// Test for operation calls
|
||||
if (in_array($functionName, self::$operations, true)) {
|
||||
return Operations::$functionName($this, ...$arguments);
|
||||
}
|
||||
throw new Exception('Function or Operation does not exist');
|
||||
}
|
||||
}
|
157
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operations.php
vendored
Normal file
157
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operations.php
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Matrix\Operators\Addition;
|
||||
use Matrix\Operators\DirectSum;
|
||||
use Matrix\Operators\Division;
|
||||
use Matrix\Operators\Multiplication;
|
||||
use Matrix\Operators\Subtraction;
|
||||
|
||||
class Operations
|
||||
{
|
||||
public static 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();
|
||||
}
|
||||
|
||||
public static 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();
|
||||
}
|
||||
|
||||
public static 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();
|
||||
}
|
||||
|
||||
public static 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();
|
||||
}
|
||||
|
||||
public static 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();
|
||||
}
|
||||
|
||||
public static 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();
|
||||
}
|
||||
}
|
68
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Addition.php
vendored
Normal file
68
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Addition.php
vendored
Normal file
@@ -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;
|
||||
}
|
||||
}
|
64
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php
vendored
Normal file
64
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php
vendored
Normal file
@@ -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;
|
||||
}
|
||||
}
|
35
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Division.php
vendored
Normal file
35
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Division.php
vendored
Normal file
@@ -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');
|
||||
}
|
||||
}
|
86
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php
vendored
Normal file
86
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php
vendored
Normal file
@@ -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;
|
||||
}
|
||||
}
|
78
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Operator.php
vendored
Normal file
78
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Operator.php
vendored
Normal file
@@ -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);
|
||||
}
|
||||
}
|
68
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php
vendored
Normal file
68
libraries/phpspreadsheet/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php
vendored
Normal file
@@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user