Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 400] [Versions 310 and 401]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Shared\JAMA;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException;
   6  
   7  /**
   8   *    Cholesky decomposition class.
   9   *
  10   *    For a symmetric, positive definite matrix A, the Cholesky decomposition
  11   *    is an lower triangular matrix L so that A = L*L'.
  12   *
  13   *    If the matrix is not symmetric or positive definite, the constructor
  14   *    returns a partial decomposition and sets an internal flag that may
  15   *    be queried by the isSPD() method.
  16   *
  17   *    @author Paul Meagher
  18   *    @author Michael Bommarito
  19   *
  20   *    @version 1.2
  21   */
  22  class CholeskyDecomposition
  23  {
  24      /**
  25       * Decomposition storage.
  26       *
  27       * @var array
  28       */
  29      private $L = [];
  30  
  31      /**
  32       * Matrix row and column dimension.
  33       *
  34       * @var int
  35       */
  36      private $m;
  37  
  38      /**
  39       * Symmetric positive definite flag.
  40       *
  41       * @var bool
  42       */
  43      private $isspd = true;
  44  
  45      /**
  46       * CholeskyDecomposition.
  47       *
  48       *    Class constructor - decomposes symmetric positive definite matrix
  49       *
  50       * @param Matrix $A Matrix square symmetric positive definite matrix
  51       */
  52      public function __construct(Matrix $A)
  53      {
  54          $this->L = $A->getArray();
  55          $this->m = $A->getRowDimension();
  56  
  57          for ($i = 0; $i < $this->m; ++$i) {
  58              for ($j = $i; $j < $this->m; ++$j) {
  59                  for ($sum = $this->L[$i][$j], $k = $i - 1; $k >= 0; --$k) {
  60                      $sum -= $this->L[$i][$k] * $this->L[$j][$k];
  61                  }
  62                  if ($i == $j) {
  63                      if ($sum >= 0) {
  64                          $this->L[$i][$i] = sqrt($sum);
  65                      } else {
  66                          $this->isspd = false;
  67                      }
  68                  } else {
  69                      if ($this->L[$i][$i] != 0) {
  70                          $this->L[$j][$i] = $sum / $this->L[$i][$i];
  71                      }
  72                  }
  73              }
  74  
  75              for ($k = $i + 1; $k < $this->m; ++$k) {
  76                  $this->L[$i][$k] = 0.0;
  77              }
  78          }
  79      }
  80  
  81      /**
  82       *    Is the matrix symmetric and positive definite?
  83       *
  84       * @return bool
  85       */
  86      public function isSPD()
  87      {
  88          return $this->isspd;
  89      }
  90  
  91      /**
  92       * getL.
  93       *
  94       * Return triangular factor.
  95       *
  96       * @return Matrix Lower triangular matrix
  97       */
  98      public function getL()
  99      {
 100          return new Matrix($this->L);
 101      }
 102  
 103      /**
 104       * Solve A*X = B.
 105       *
 106       * @param $B Row-equal matrix
 107       *
 108       * @return Matrix L * L' * X = B
 109       */
 110      public function solve(Matrix $B)
 111      {
 112          if ($B->getRowDimension() == $this->m) {
 113              if ($this->isspd) {
 114                  $X = $B->getArrayCopy();
 115                  $nx = $B->getColumnDimension();
 116  
 117                  for ($k = 0; $k < $this->m; ++$k) {
 118                      for ($i = $k + 1; $i < $this->m; ++$i) {
 119                          for ($j = 0; $j < $nx; ++$j) {
 120                              $X[$i][$j] -= $X[$k][$j] * $this->L[$i][$k];
 121                          }
 122                      }
 123                      for ($j = 0; $j < $nx; ++$j) {
 124                          $X[$k][$j] /= $this->L[$k][$k];
 125                      }
 126                  }
 127  
 128                  for ($k = $this->m - 1; $k >= 0; --$k) {
 129                      for ($j = 0; $j < $nx; ++$j) {
 130                          $X[$k][$j] /= $this->L[$k][$k];
 131                      }
 132                      for ($i = 0; $i < $k; ++$i) {
 133                          for ($j = 0; $j < $nx; ++$j) {
 134                              $X[$i][$j] -= $X[$k][$j] * $this->L[$k][$i];
 135                          }
 136                      }
 137                  }
 138  
 139                  return new Matrix($X, $this->m, $nx);
 140              }
 141  
 142              throw new CalculationException(Matrix::MATRIX_SPD_EXCEPTION);
 143          }
 144  
 145          throw new CalculationException(Matrix::MATRIX_DIMENSION_EXCEPTION);
 146      }
 147  }