/home/mip/www/vendor/laravel-filemanager/files/folder-1/821668/matrix.zip
PK �@]�BU U
license.mdnu �[��� 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.PK �@]�f�>� � .github/workflows/main.yamlnu �[��� 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
PK �@]D8��J J phpstan.neonnu �[��� 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
PK �@]v��}� �
composer.jsonnu �[��� {
"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"
}
],
"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/"
}
},
"autoload-dev": {
"psr-4": {
"MatrixTest\\": "unitTests/classes/src/"
}
},
"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",
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
PK �@] ȩc c README.mdnu �[��� PHPMatrix
==========
---
PHP Class for handling Matrices
[](https://github.com/MarkBaker/PHPMatrix/actions)
[](https://packagist.org/packages/markbaker/matrix)
[](https://packagist.org/packages/markbaker/matrix)
[](https://packagist.org/packages/markbaker/matrix)
[](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
---
# Installation
```shell
composer require markbaker/matrix:^3.0
```
# Important BC Note
If you've previously been using procedural calls to functions and operations using this library, then from version 3.0 you should use [MarkBaker/PHPMatrixFunctions](https://github.com/MarkBaker/PHPMatrixFunctions) instead (available on packagist as [markbaker/matrix-functions](https://packagist.org/packages/markbaker/matrix-functions)).
You'll need to replace `markbaker/matrix`in your `composer.json` file with the new library, but otherwise there should be no difference in the namespacing, or in the way that you have called the Matrix functions in the past, so no actual code changes are required.
```shell
composer require markbaker/matrix-functions:^1.0
```
You should not reference this library (`markbaker/matrix`) in your `composer.json`, composer wil take care of that for you.
# 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 static method
```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\Operations::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 static method, passing the Matrix object or array 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\Functions::trace($matrix);
```
```php
$grid = [
[16, 3, 2, 13],
[ 5, 10, 11, 8],
[ 9, 6, 7, 12],
[ 4, 15, 14, 1],
];
echo Matrix\Functions::trace($grid);
```
## 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();
```
PK �@]t��W W
buildPhar.phpnu �[��� <?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();
PK �@]��p�� � classes/src/Builder.phpnu �[��� <?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);
}
}
PK �@]Ƶ�N N classes/src/Operations.phpnu �[��� <?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();
}
}
PK �@]&��� � classes/src/Div0Exception.phpnu �[��� <?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
{
}
PK �@]2��S�* �* classes/src/Functions.phpnu �[��� <?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);
}
}
PK �@]���d� � classes/src/Decomposition/QR.phpnu �[��� <?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);
}
}
PK �@]/��y + classes/src/Decomposition/Decomposition.phpnu �[��� <?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');
}
}
}
PK �@]�a?�9 9 classes/src/Decomposition/LU.phpnu �[��� <?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);
}
}
PK �@]x!ӱ� � classes/src/Exception.phpnu �[��� <?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
{
}
PK �@]/F�G # classes/src/Operators/DirectSum.phpnu �[��� <?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;
}
}
PK �@]�=�%d d ( classes/src/Operators/Multiplication.phpnu �[��� <?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;
}
}
PK �@]g�j "