chippyash/math-matrix

矩阵数学包

2.1.0 2018-07-04 22:52 UTC

This package is auto-updated.

Last update: 2024-09-22 22:44:33 UTC


README

质量

PHP 5.6 PHP 7 Build Status Test Coverage Code Climate

上述徽章代表当前的开发分支。一般来说,除非测试、覆盖率和可用性都令人满意,否则我不会向GitHub推送。在假期、需要为其他下游项目编写代码等短时间内可能不是这样。如果您需要稳定的代码,请使用标记版本。阅读'进一步文档'和'安装'。

查看测试合同(526个测试,820个断言)

查看API文档获取更多信息

请注意,从本库的2.0.0版本开始,已撤回对PHP 5.4和5.5的开发商支持。如果您需要PHP 5.4或5.5的支持,请使用版本>=1,<2

是什么?

从我了解的情况来看,自从JAMA库以来,没有库允许PHP开发者将算术矩阵功能简单地在应用程序中集成。

如果您使用的是合理大小的矩阵,那么编译外部基于Fortran或C的库的复杂性是可以避免的。即使您这样做,PHP绑定的功能也是有限的。

您需要速度——PHP永远不会在大型矩阵上做到这一点,开始编译。对于其他所有事情,试试这个。

鉴于以下情况,这个库旨在以尽可能有效的方式使用PHP提供算术矩阵功能:

  • 一切都有测试用例
  • 它是PHP 5.5+

本库根据GNU GPL V3或更高版本许可发布

为什么?

这为Chippyash/Matrix库添加了数学功能,使您能够创建和操作包含数字(浮点数、整数、有理数和复数)值的矩阵。

当前库涵盖了基本的矩阵数学。它是一个正在进行中的工作,并有一些局限性。加法、减法和乘法是直接的,应该适用于任何大小的矩阵。除法依赖于求逆,目前依赖于确定矩阵行列式的功能。库支持两种查找行列式的策略——拉普拉斯展开和LU。这为可以操作矩阵的大小设定了实际限制。请参阅examples/example-laplace-bounds.php和examples/example-lu-determinant-bounds.php脚本来理解原因。当使用自动模式下的行列式导数时,限制为20x20矩阵。这个限制是任意的,基于在我的笔记本电脑上大约一秒内可以计算的内容。其他品牌的机器可能不同。

未来可能会改变,因为我重构以提高性能或结合更高效的计算逆和行列式的策略。如果您擅长数学计算,这实际上是一个您可以真正帮助的领域。

如果您需要更多,请提出建议,或者更好的是,分叉它并提供一个pull request。

查看chippyash/Matrix以获取底层矩阵操作

查看 chippyash/Logical-Matrix 进行逻辑矩阵运算

查看 ZF4 Packages 获取更多包

如何

本库当前版本使用PHP原生数字强类型作为计算器,因为它目前只能处理这些类型。一旦计算器提供了GMP支持,GMP支持也将纳入路线图。您可以通过以下调用强制执行其设置来确保这一点:

use Chippyash\Type\RequiredType;
RequiredType::getInstance()->set(RequiredType::TYPE_NATIVE);

在任何矩阵操作之前。

编码基础

在PHP中,矩阵是一个数组的数组,即二维的

  • [[]]

与其他任何TDD应用程序一样,测试告诉您有关SUT(系统单元)所需知道的一切。阅读它们!然而,对于性情急躁的我们来说,关键点是

该库扩展了Chippyash/Matrix库,因此您可以在数值矩阵上执行任何在基本矩阵上可以执行的操作。该库利用Chippyash/Strong-Type强类型。

提供了三种基本矩阵类型

  • NumericMatrix:包含int、float、IntType、WholeIntType、NaturalIntType、FloatType、RationalType和ComplexType数据项
  • RationalMatrix:仅包含RationalType数据项
  • ComplexMatrix:仅包含ComplexType数据项

NumericMatrix适用于一般用途,但不适用于证明M的逆(M) * M = 单位矩阵。为此,您需要RationalMatrix,它在算术上更稳定。这也是将从Chippyash/Strong-Type库中受益的矩阵,该库将支持PHP的各种数学扩展库。

ComplexMatrix完全支持Chippyash\Type\Numeric\Complex\ComplexType。

RationalMatrix和ComplexMatrix都扩展了NumericMatrix。

创建数值类型矩阵很简单

    use Chippyash\Math\Matrix\NumericMatrix;
    use Chippyash\Math\Matrix\RationalMatrix;
    use Chippyash\Math\Matrix\ComplexMatrix;
    //create empty matrices
    $mA = new NumericMatrix([]);
    $mB = new RationalMatrix([]);
    $mC = new ComplexMatrix([]);

向矩阵构造函数提供数据将根据以下规则在矩阵内创建数据项

  • NumericMatrix:项目以可能最低的NumericTypeInterface创建。从低到高的顺序是IntType、FloatType、RationalType、ComplexType
  • RationalMatrix:项目以RationalType创建
  • ComplexMatrix项目以ComplexType创建。如果您提供非复杂数据项,则创建实复杂数据项,即虚部等于零

请注意,在NumericMatrix上的操作可能会产生具有不同数据类型条目的结果。考虑到基于计算机的算术的限制,这是不可避免的。如果任何操作需要将项目向上转换,那么它不太可能再次向下转换。

提供了一些辅助工具

MatrixFactory

提供静态方法

  • MatrixFactory::create(string $type, array $data)。$type是numeric、rational或complex之一
  • MatrixFactory::createComplex(array $data)
  • MatrixFactory::createRational(array $data)
  • MatrixFactory::createNumeric(array $data)
  • MatrixFactory::createFromFunction(callable $fn, IntType $rows, IntType $cols, $type = 'numeric')
  • MatrixFactory::createFromComplex(ComplexType $c)

FunctionMatrix

[已弃用 - 使用SpecialMatrix::create('functional', int:rows, int:cols, \Closure:f(int:rows, int:cols))]代替

创建一个函数应用的结果的数值矩阵。

    $f = function($row, $col) {return TypeFactory::createInt($row * $col);};
    $mA = new FunctionMatrix($f, TypeFactory::createInt(3), TypeFactory::createInt(4));

IdentityMatrix

[已弃用 - 使用SpecialMatrix::create('identity',int:size)代替]

创建一个NumericMatrix单位矩阵

    //create 4x4 identity matrix with integer entries
    $mA = new IdentityMatrix(TypeFactory::createInt(4));
    //or more usually, use the factory method
    $mA - IdentityMatrix::numericIdentity(TypeFactory::createInt(4));

使用工厂方法创建有理数和复数单位矩阵

    $mR = IdentityMatrix::rationalIdentity(TypeFactory::createInt(4));
    $mC = IdentityMatrix::complexIdentity(TypeFactory::createInt(4));

ZeroMatrix

[已弃用 - 使用SpecialMatrix::create('zeros', int:rows[, int:cols])]代替

创建一个所有条目都设置为零的NumericMatrix

    //create 2 x 4 zero matrix
    $mZ = new ZeroMatrix(TypeFactory::createInt(2), TypeFactory::createInt(4));

ShiftMatrix

创建一个移位矩阵

	$mA - IdentityMatrix::numericIdentity(TypeFactory::createInt(5));
	
	//create 5 x 5 shift matrices
	$mSupper = new ShiftMatrix(new IntType(5), new StringType(ShiftMatrix::SM_TYPE_UPPER);
	$mSlower = new ShiftMatrix(new IntType(5), new StringType(ShiftMatrix::SM_TYPE_LOWER);
	//optionally specify the matrix content type
	$mSupper = new ShiftMatrix(new IntType(5), new StringType(ShiftMatrix::SM_TYPE_UPPER, new IntType(IdentityMatrix::IDM_TYPE_COMPLEX));
	
	$mC = $mA('Mul\Matrix', $mSupper);
	$mD = $mLower('Mul\Matrix', $mA);

SpecialMatrix

提供许多特殊矩阵

采用Octave Gallery Matrices中的想法

//inline creation if your version of PHP allows it
use Chippyash\Math\Matrix\SpecialMatrix;
$mS = (new SpecialMatrix())->create(new StringType('NameOfMatrix')[, $arg1, $arg2]);

//or as an invokable class
$factory = new SpecialMatrix();
$mS = $factory(new StringType('nameOfMatrix')[, $arg1, $arg2]);
//or
$mS = $factory('NameOfMatrix'[, $arg1, $arg2]);

提供的矩阵

  • 单位矩阵/向量:create('ones', int:rows) 或 create ('ones', int:rows, int:cols)
  • 柯西矩阵:create('cauchy', int:x) 或 create('cauchy', vector:x, vector:y)
  • 单位矩阵:create('identity', int:size)
  • 函数矩阵:create('functional', int:rows, int:cols, \Closure: f(int:rows, int:cols))
  • 零矩阵/向量:create('zeros', int:rows) 或 create ('zeros', int:rows, int:cols)

所有返回的矩阵都是NumericMatrices。

非常重要:我们并不是自己完成这些操作。所以请阅读测试,并阅读源文件,在那里你会找到比我更聪明的人的归属。我只是尝试将其翻译成PHP世界。

Numeric矩阵有额外的属性

  • IsComplex: boolean - 是否是ComplexMatrix实例?
  • IsIdentity: boolean - 是否是单位矩阵?
  • IsNonsingular: boolean - 是否是非奇异的矩阵?
  • IsNumeric: boolean - 是否是NumericMatrix实例?
  • IsRational: boolean - 是否是RationalMatrix实例?
  • IsMarkov: boolean - 矩阵是否符合马尔可夫链矩阵的要求?

记住,你可以使用is()方法来测试矩阵上的属性。

矩阵可以进行计算

  • 计算始终返回一个矩阵。
  • 原始矩阵不受影响
  • 你可以使用魔法__invoke功能
  • 计算实现了Chippyash\Math\Matrix\Interfaces\ComputationInterface接口
  • 计算可以与标量值或其他矩阵一起工作。非标量值将抛出异常

总的来说,计算可以与任何标量一起工作,但是

所有矩阵计算都遵循自然法则

  • 你不能除以零
  • 除以一个非可逆矩阵就像1/0 - 哎呀!
  • 使用float,int和rational数据项可以一起工作
  • 使用复数数据项:所有项都必须是复数

以下提供了以下计算(使用魔法调用接口方法)

  • 'Add\Scalar' : 将标量值添加到矩阵中
  • 'Add\Matrix' : 将矩阵添加到矩阵中
  • 'Sub\Scalar' : 从矩阵中减去标量值
  • 'Sub\Matrix' : 从矩阵中减去矩阵
  • 'Mul\Scalar' : 将矩阵乘以标量值
  • 'Mul\Matrix' : 使用常规矩阵乘积方法乘以另一个矩阵
  • 'Mul\Entrywise' : 使用Hadamard或Schur乘积方法乘以另一个矩阵
  • 'Div\Scalar' : 将矩阵除以标量值
  • 'Div\Matrix' : 将矩阵除以另一个矩阵 - 请参阅本说明头部注释
  • 'Div\Entrywise' : 使用逐项方法将矩阵除以另一个矩阵。在特定顶点处,除以零将得到零。这是一种防御策略,没有正确答案。最好的防御是确保你除以的矩阵不包含零
    $mC = $mA('Mul\Matrix', $mB);
    //same as
    $fMul = new Chippyash\Math\Matrix\Computation\Mul\Matrix();
    $mC = $mA->compute($fMul, $mB)
    //same as
    $mC = $fMul->compute($mA, $mB);

你可以从矩阵中推导出其他信息

  • 导数始终返回一个数值结果
  • 原始矩阵不受影响
  • 你可以使用魔法__invoke功能
  • 导数实现了Chippyash\Math\Matrix\Interfaces\DerivativeInterface接口

目前提供了四种导数。

  • 行列式
    $det = $mA("Determinant");
    //same as
    $fDet = new Chippyash\Math\Matrix\Derivative\Determinant();
    $det = $mA->derive($fDet);
    //same as
    $det = $fDet($mA);

如上所述,行列式导数目前仅支持20x20矩阵的自动模式。如果你提供一个比这更大的矩阵,它将崩溃。这对于大多数用途来说都是可以的。如果你愿意等待一段时间来计算大矩阵的行列式,可以通过构造(上面第二种方法)创建行列式,并将Determinant::METHOD_LU指定为构造参数。Determinant::METHOD_LAPLACE保留为历史原因,因为你几乎不太可能想使用它!

  • 迹。返回方阵的迹
    $tr = $mA('Trace');
    //or other variations as with Determinant
  • 求和。简单地将矩阵中所有顶点相加并返回结果
    $sum = $mA('Sum');
    //or other variations as with Determinant
  • MarkovWeightedRandom。使用马尔可夫链矩阵上的随机加权方法返回下一步
    $mA = new NumericMatrix(
        [
            [0,2,0,8]  //row 1
            [1,0,0,0]  //row 2
            [0,0,5,5]  //row 3
            [0,1,6,3]  //row 4
        ]
    )
    
    $next = $mA('MarkovWeightedRandom', TypeFactory::createInt(3));
    //will return IntType(3) or IntType(4) with 50% chance of either being returned
    

如果提供的矩阵不符合IsMarkov属性,将抛出NotMarkovException异常。请注意,虽然您可以提供浮点数矩阵,但用于生成下一个数字的mt_rand()函数的性质意味着,目前,您应该提供整数值。只要您提供每行行和相同的正方形矩阵,您就可以用矩阵表达马尔可夫链。

支持由数字矩阵进行的额外转换

  • 求逆 - 返回逆矩阵或如果不可能则抛出异常。当前的求逆方法依赖于行列式,并且如前所述,目前这仅适用于20x20以下的矩阵
    try {
        $mI = $mA('Invert');
        //same as
        $fInvert = new Chippyash\Math\Matrix\Transformation\Invert();
        $mI = $mA->transform($fInvert);
        //same as
        $mI = $fInvert($mA);
    } catch (Chippyash\Math\Matrix\Exceptions\ComputationException $e) {
        //cannot invert
    }

如果您想突破20x20的限制,可以这样做

    $det = new Chippyash\Math\Matrix\Derivative\Determinant();
    $det->tune('luLimit', 40); //or whatever you are prepared to put up with
    $mI = $mA('Invert');
  • MarkovRandomWalk - 给定一个表示为数字矩阵的马尔可夫链,从起始行随机走到目标行,返回一个整型数字矩阵的行向量
    $det = new Chippyash\Math\Matrix\Derivative\MarkovRandomWalk();
    $res = $det->transform(
        $mA, 
        array(
            'start'=>TypeFactory::createInt(2), 
            'target'=>TypeFactory::createInt(4)
        )
    );

您可以提供一个可选的第三个参数,limit,以限制可采取的步骤数。默认设置为100。

    $res = $mA(
        'MarkovRandomWalk', 
        array(
            'start'=>TypeFactory::createInt(2), 
            'target'=>TypeFactory::createInt(4),
            'limit'=>TypeFactory::createInt(10)
        )
    );

矩阵可以被分解

  • 原始矩阵不受影响
  • 你可以使用魔法__invoke功能
  • 分解返回一个分解对象,您可以通过该对象访问分解的各个部分。
  • 分解实现了Chippyash\Math\Matrix\Interfaces\DecompositionInterface

库目前支持

  • LU分解
  • 高斯-约当消元法

LU

    $lu = $mA('Lu');
    //same as
    $fLu = new Chippyash\Math\Matrix\Decomposition\Lu()
    $lu = $mA->decompose($fLu);
    //same as
    $lu = $fLu($mA);

LU的乘积是

  • LU : NumericMatrix - 完整的LU分解矩阵
  • L : NumericMatrix - 下三角
  • U : NumericMatrix - 上三角
  • PivotVector : NumericMatrix - 分解的主元向量
  • PermutationMatrix : NumericMatrix - 置换矩阵
  • Det : NumericTypeInterface|Null - 行列式或如果矩阵不是正方形则为null

通过product()方法或更简单地作为分解的属性来访问乘积

    $pv = $lu->product('PivotVector');
    //same as
    $pv = $lu->PivotVector;

注意。任何分解的乘积名称都是大小写敏感的

高斯-约当消元法

    $mA = new NumericMatrix(
                [[1, 1, 1],
                 [2, 3, 5],
                 [4, 0, 5]]
                );
    $mB = new NumericMatrix(
            [[5],
             [8],
             [2]]
            );
    $elim = $mA('GaussJordonElimination', $mB);
    //same as
    $fElim = new Chippyash\Math\Matrix\Decomposition\GaussJordonElimination()
    $elim = $mA->decompose($fElim, $mB);
    //same as
    $elim = $fElim($mA, $mB);

乘积是

  • left 消元后的左矩阵
  • right 消元后的右矩阵

使用上面的例子,$elim->left 应等于单位矩阵,$elim->right 应等于 [[3],[4],[-2]],因为我们刚刚解出

    x + y + z = 5
    2x + 3y + 5z = 8
    4x + 5z = 2
where
    x = 3, y = 4, z = -2

数字显示的格式化

库支持额外的显示格式化程序

\Chippyash\Math\Matrix\Formatter\AsciiNumeric

它扩展了 \Chippyash\Matrix\Formatter\Ascii。提供了一个额外的选项 'outputType',它应该取以下值之一

    AsciiNumeric::TP_NONE      //behave as base formatter - default behaviour
    AsciiNumeric::TP_INT       //convert all entries to int.  This will floor() if possible
    AsciiNumeric::TP_FLOAT     //convert all entries to float if possible
    AsciiNumeric::TP_RATIONAL  //convert all entries to rational if possible
    AsciiNumeric::TP_COMPLEX   //convert all entries to complex (always possible)

请注意,尽管您指示转换为特定的数字类型,但实际显示可能如果可能的话会以更简单的形式出现。

示例

    echo $mA->setFormatter(new AsciiNumeric())
        ->display(['outputType' => AsciiNumeric::TP_FLOAT]);

有向图的格式化

要使用此功能,您需要在您的composer requires部分包含

    "clue/graph": "^0.9",
    "graphp/graphviz": "0.2.*"

并运行composer update。

这会将使用GraphViz套件程序从描述图的NumericMatrix创建图像文件的功能添加到功能中。

渲染器最简单的使用方法是简单地提供一个NumericMatrix

$mA = new NumericMatrix([[0,0,1],[0,1,0],[1,0,0]]);
$dot = $mA->setFormatter(new DirectedGraph())->display();

将生成一个GraphViz .dot文件内容字符串,如下所示

digraph G {
  0 -> 2 [label=1]
  1 -> 1 [label=1 dir="none"]
  2 -> 0 [label=1]
}

然而,通常您会希望为您的顶点赋予一些意义。为此,您可以通过传递一个包含VertexDescription对象的Monad.Collection。例如

use Monad\Collection;
use Chippyash\Math\Matrix\Formatter\DirectedGraph\VertexDescription;

$attribs = new Collection(
    [
        new VertexDescription(new StringType('A')),
        new VertexDescription(new StringType('B')),
        new VertexDescription(new StringType('C')),
    ]
);
$dot = $mA->setFormatter(new DirectedGraph())->display(['attribs' => $attribs]);

给出

'digraph G {
  "A" -> "C" [label=1]
  "B" -> "B" [label=1 dir="none"]
  "C" -> "A" [label=1]
}

您还可以通过VertexDescription设置颜色和形状等。请参阅测试。

如果您想在生成GraphViz之前进行一些额外的处理,可以传递一个可选的参数

$graph = $mA->setFormatter(new DirectedGraph())->display(['output' => 'object']);

将返回一个Fhaculty\Graph\Graph对象,您可以在将其发送到Graphp\GraphViz\GraphViz之前对其进行进一步处理。您可能还希望获取一个图,以便通过Graphp\Algorithms库进行一些图处理。

最后,使用DirectedGraph渲染器,您可以提供一个可选的可调用函数,该函数将被应用于边的值。这通常非常有用,可以以某种方式重新格式化值。例如

$mA = new NumericMatrix([[0,50,50],[33,33,33],[100,0,0]]);
$func = function($origValue) {return \round($origValue / 100, 2);};
$dot = $mA->setFormatter(new DirectedGraph())->display(['edgeFunc' => $func]);

将生成

digraph G {
  0 -> 1 [label=0.5]
  0 -> 2 [label=0.5]
  1 -> 0 [label=0.33]
  1 -> 1 [label=0.33 dir="none"]
  1 -> 2 [label=0.33]
  2 -> 0 [label=1]
}

异常处理

由于矩阵数学可能会出现问题,尤其是在求逆或分解时,总是将您正在做的事情包裹在try-catch块中是一个好主意。库支持以下异常。它们都扩展自Chippyash\Matrix\Exceptions\MatrixException。基本命名空间是Chippyash\Math\Matrix\Exceptions

  MathMatrixException
  ComputationException
  NoInverseException
  SingularMatrixException
  UndefinedComputationException
  NotMarkovException

更改库

  1. 分叉它
  2. 编写测试
  3. 修改它
  4. 发起拉取请求

发现了一个无法解决的错误吗?

  1. 分叉它
  2. 编写测试
  3. 发起拉取请求

注意。在您的拉取请求之前,请确保将代码回退到HEAD

在哪里?

库托管在Github。它作为Composable模块在Packagist.org上可用

安装

安装[Composer] (https://getcomposer.org.cn/)

对于生产环境

将以下内容添加到您的composer.json "requires"部分:

    "chippyash/math-matrix": ">=2,<3"

对于开发

克隆此存储库,然后在本地存储库根目录中运行Composer以拉取依赖项

    git clone git@github.com:chippyash/Math-Matrix.git Math-Matrix
    cd Math-Matrix
    composer install

要运行测试

    cd Math-Matrix
    vendor/bin/phpunit -c test/phpunit.xml test/

许可证

此软件库在BSD 3 Clause license下发布

此软件库的版权为(c) 2014-2018,Ashley Kitson,英国

历史

V1.0.0 初始版本 - 开发2年后 - 欢呼!

V1.1.0 更新依赖项

V1.2.0 添加逐项计算

V1.2.1 根除对普通数值强类型的调用 - 使用工厂

V1.2.2 修复AsciiNumeric格式化器 - 不要格式化字符串

V1.2.3 添加对包的链接

V1.3.0 添加从矩阵渲染的定向图

V1.4.0 添加ShiftMatrix

V1.5.0 添加特殊矩阵

Deprecation notice: IdentityMatrix, ZeroMatrix, FunctionMatrix are
deprecated, Use the SpecialMatrix instead to create these.  I found a
problem in some of the auto conversion algorithms used in the Matrix calculator
that depended on class names.  The new convention ensures that these matrix types
are all returned as NumericMatrix objects which is more conformant with their
intended use.  I will shortly deprecate ShiftMatrix in favour of a SpecialMatrix
type instead, but as it's brand new, it probably won't effect too many.

SpecialMatrix allows for arbitrary inclusion of all sorts of matrices and the idea
comes from the Octave/Matlab world. I probably won't get round to including all those
that are provided by Octave/Matlab, but it is certainly an opportunity for others
to implement the other types provided by those libraries as required.

In due course, the version number for this library will be bumped at which
point the old classes will disappear.

V1.5.1 依赖项更新

V1.5.2 依赖项更新

V1.5.3 构建脚本更新

V1.5.4 更新Composer - 由Packagist composer.json格式更改强制

V2.0.0 兼容性中断。撤回对旧PHP版本的支持

V2.1.0 许可证从GPL V3更改为BSD 3 Clause