/** * Solves a linear system * * @param NumArray $squareMatrix matrix of size n*n * @param NumArray $numArray vector of size n or matrix of size n*m * * @throws \NumPHP\LinAlg\Exception\SingularMatrixException will be thrown, if * `$squareMatrix` is singular * @throws \NumPHP\LinAlg\Exception\InvalidArgumentException will be thrown, if * linear system of `$squareMatrix` and `$numArray` can not be solved * * @return NumArray * * @since 1.0.0 */ public static function solve(NumArray $squareMatrix, NumArray $numArray) { if (!Helper::isNotSingularMatrix($squareMatrix)) { throw new SingularMatrixException(sprintf("First Argument has to be a not singular square matrix")); } if (!Helper::isVector($numArray) && !Helper::isMatrix($numArray)) { throw new InvalidArgumentException(sprintf("Second argument has to be a vector or a matrix, NumArray with dimension %d given", $numArray->getNDim())); } $shape1 = $squareMatrix->getShape(); $shape2 = $numArray->getShape(); if ($shape1[0] !== $shape2[0]) { throw new InvalidArgumentException(sprintf("Can not solve a linear system with matrix (%s) and matrix (%s)", implode(', ', $shape1), implode(', ', $shape2))); } /** * The result of LinAlg::lud is a array with three NumArrays * * @var NumArray $pMatrix * @var NumArray $lMatrix * @var NumArray $uMatrix */ list($pMatrix, $lMatrix, $uMatrix) = LinAlg::lud($squareMatrix); $yNumArray = self::forwardSubstitution($lMatrix, $pMatrix->getTranspose()->dot($numArray)); $zNumArray = self::backSubstitution($uMatrix, $yNumArray); return $zNumArray; }
/** * Factors a matrix into a pivot matrix, a lower and upper triangular matrix * * @param NumArray $array matrix * * @throws NoMatrixException will be thrown, if `array` is no matrix * * @return array * * @since 1.0.0 */ public static function lud(NumArray $array) { if (!Helper::isMatrix($array)) { throw new NoMatrixException(sprintf("NumArray with dimension %d given, NumArray should have 2 dimensions", $array->getNDim())); } $numArray = clone $array; $shape = $numArray->getShape(); $mAxis = $shape[0]; $nAxis = $shape[1]; $size = min($mAxis, $nAxis); $pArray = range(0, $mAxis - 1); $lMatrix = NumPHP::zeros($mAxis, $size); for ($i = 0; $i < $size; $i++) { // pivoting $maxIndex = self::getPivotIndex($numArray, $i); if ($maxIndex !== $i) { $temp = $numArray->get($i); $numArray->set($i, $numArray->get($maxIndex)); $numArray->set($maxIndex, $temp); $temp = $lMatrix->get($i); $lMatrix->set($i, $lMatrix->get($maxIndex)); $lMatrix->set($maxIndex, $temp); $temp = $pArray[$i]; $pArray[$i] = $pArray[$maxIndex]; $pArray[$maxIndex] = $temp; } // elimination for ($j = $i + 1; $j < $mAxis; $j++) { $fac = 0; $facNumerator = $numArray->get($j, $i)->getData(); $facDenominator = $numArray->get($i, $i)->getData(); if ($facDenominator) { $fac = $facNumerator / $facDenominator; } $lMatrix->set($j, $i, $fac); $slice = sprintf("%d:", $i + 1); $numArray->set($j, $slice, $numArray->get($j, $slice)->sub($numArray->get($i, $slice)->mult($fac))); } } return [self::buildPivotMatrix($pArray), self::buildLMatrix($lMatrix), self::buildUMatrix($numArray)]; }
/** * Tests if Helper::isMatrix works with invalid matrix */ public function testCheckMatrixInvalid() { $numArray = NumPHP::ones(3); $this->assertFalse(Helper::isMatrix($numArray)); }