/**
  * Calculates lower triangular matrix L of given symmetric positive definite matrix
  *
  * @param  NumArray $squareMatrix symmetric positive definite matrix
  *
  * @return NumArray
  *
  * @throws InvalidArgumentException   will be thrown, when `$squareMatrix` is not positive definite
  * @throws NoSquareMatrixException    will be thrown, when `$squareMatrix` is not square
  * @throws NoSymmetricMatrixException will be thrown, when `$squareMatrix` is not symmetric
  *
  * @since 1.0.2
  */
 public static function cholesky(NumArray $squareMatrix)
 {
     if (!Helper::isSquareMatrix($squareMatrix)) {
         throw new NoSquareMatrixException(sprintf("Matrix with shape (%s) given, matrix has to be square", implode(', ', $squareMatrix->getShape())));
     }
     $shape = $squareMatrix->getShape();
     $size = $shape[0];
     $aMatrix = clone $squareMatrix;
     $lMatrix = NumPHP::zerosLike($aMatrix);
     for ($k = 0; $k < $size; $k++) {
         $diaElem = $aMatrix->get($k, $k)->getData();
         if ($diaElem <= 0) {
             throw new InvalidArgumentException("Matrix is not positive definite");
         }
         $diaElem = sqrt($diaElem);
         $lMatrix->set($k, $k, $diaElem);
         for ($i = $k + 1; $i < $size; $i++) {
             if ($squareMatrix->get($i, $k) != $squareMatrix->get($k, $i)) {
                 throw new NoSymmetricMatrixException("Matrix is not symmetric");
             }
             $lMatrix->set($i, $k, $aMatrix->get($i, $k)->div($diaElem));
             for ($j = $k + 1; $j <= $i; $j++) {
                 $aMatrix->set($i, $j, $aMatrix->get($i, $j)->sub($lMatrix->get($i, $k)->mult($lMatrix->get($j, $k))));
             }
         }
     }
     return $lMatrix;
 }
 /**
  * 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)];
 }
Exemple #3
0
 /**
  * Calculates the inverse of a not singular square matrix
  *
  * @param mixed $squareMatrix not singular matrix
  *
  * @throws SingularMatrixException will be thrown, when `$squareMatrix` is singular
  *
  * @api
  * @since 1.0.0
  *
  * @return NumArray
  */
 public static function inv($squareMatrix)
 {
     if (!$squareMatrix instanceof NumArray) {
         $squareMatrix = new NumArray($squareMatrix);
     } elseif ($squareMatrix->inCache(self::CACHE_KEY_INVERSE)) {
         return $squareMatrix->getCache(self::CACHE_KEY_INVERSE);
     }
     if (!Helper::isNotSingularMatrix($squareMatrix)) {
         throw new SingularMatrixException("Matrix is singular");
     }
     $shape = $squareMatrix->getShape();
     $inv = self::solve($squareMatrix, NumPHP::identity($shape[0]));
     $squareMatrix->setCache(self::CACHE_KEY_INVERSE, $inv);
     return self::inv($squareMatrix);
 }
Exemple #4
0
 /**
  * Tests if Helper::isNotSingularMatrix works with invalid not singular matrix
  */
 public function testCheckNotSingularMatrixInvalid()
 {
     $numArray = NumPHP::identity(4);
     $numArray->set(2, 2, 0);
     $this->assertFalse(Helper::isNotSingularMatrix($numArray));
 }
Exemple #5
0
 /**
  * Back Substitution solves a linear system with a upper triangular matrix of
  * size n*n and a vector of size n or a matrix of size n*m
  *
  * @param NumArray $uMatrix   upper triangular matrix of size n*n
  * @param NumArray $numArray  vector of size n or matrix of size n*m
  *
  * @return NumArray
  *
  * @since 1.0.0
  */
 protected static function backSubstitution(NumArray $uMatrix, NumArray $numArray)
 {
     $shape = $numArray->getShape();
     if (Helper::isVector($numArray)) {
         $xVector = NumPHP::zerosLike($numArray);
         for ($i = $shape[0] - 1; $i >= 0; $i--) {
             $slice = sprintf("%d:%d", $i + 1, $shape[0]);
             $sum = $uMatrix->get($i, $slice)->dot($xVector->get($slice));
             $xVector->set($i, $numArray->get($i)->sub($sum)->div($uMatrix->get($i, $i)));
         }
         return $xVector;
     }
     // $numArray is a matrix
     $copy = clone $numArray;
     for ($i = 0; $i < $shape[1]; $i++) {
         $copy->set(':', $i, self::backSubstitution($uMatrix, $copy->get(':', $i)));
     }
     return $copy;
 }