5
* For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
6
* unit lower triangular matrix L, an n-by-n upper triangular matrix U,
7
* and a permutation vector piv of length m so that A(piv,:) = L*U.
8
* If m < n, then L is m-by-m and U is m-by-n.
10
* The LU decompostion with pivoting always exists, even if the matrix is
11
* singular, so the constructor will never fail. The primary use of the
12
* LU decomposition is in the solution of square systems of simultaneous
13
* linear equations. This will fail if isNonsingular() returns false.
15
* @author Paul Meagher
16
* @author Bartosz Matosiuk
17
* @author Michael Bommarito
21
class PHPExcel_Shared_JAMA_LUDecomposition {
23
const MatrixSingularException = "Can only perform operation on singular matrix.";
24
const MatrixSquareException = "Mismatched Row dimension";
27
* Decomposition storage
30
private $LU = array();
51
* Internal storage of pivot vector.
54
private $piv = array();
58
* LU Decomposition constructor.
60
* @param $A Rectangular matrix
61
* @return Structure to access L, U and piv.
63
public function __construct($A) {
64
if ($A instanceof PHPExcel_Shared_JAMA_Matrix) {
65
// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
66
$this->LU = $A->getArray();
67
$this->m = $A->getRowDimension();
68
$this->n = $A->getColumnDimension();
69
for ($i = 0; $i < $this->m; ++$i) {
73
$LUrowi = $LUcolj = array();
76
for ($j = 0; $j < $this->n; ++$j) {
77
// Make a copy of the j-th column to localize references.
78
for ($i = 0; $i < $this->m; ++$i) {
79
$LUcolj[$i] = &$this->LU[$i][$j];
81
// Apply previous transformations.
82
for ($i = 0; $i < $this->m; ++$i) {
83
$LUrowi = $this->LU[$i];
84
// Most of the time is spent in the following dot product.
87
for ($k = 0; $k < $kmax; ++$k) {
88
$s += $LUrowi[$k] * $LUcolj[$k];
90
$LUrowi[$j] = $LUcolj[$i] -= $s;
92
// Find pivot and exchange if necessary.
94
for ($i = $j+1; $i < $this->m; ++$i) {
95
if (abs($LUcolj[$i]) > abs($LUcolj[$p])) {
100
for ($k = 0; $k < $this->n; ++$k) {
101
$t = $this->LU[$p][$k];
102
$this->LU[$p][$k] = $this->LU[$j][$k];
103
$this->LU[$j][$k] = $t;
106
$this->piv[$p] = $this->piv[$j];
108
$this->pivsign = $this->pivsign * -1;
110
// Compute multipliers.
111
if (($j < $this->m) && ($this->LU[$j][$j] != 0.0)) {
112
for ($i = $j+1; $i < $this->m; ++$i) {
113
$this->LU[$i][$j] /= $this->LU[$j][$j];
118
throw new Exception(PHPExcel_Shared_JAMA_Matrix::ArgumentTypeException);
120
} // function __construct()
124
* Get lower triangular factor.
126
* @return array Lower triangular factor
128
public function getL() {
129
for ($i = 0; $i < $this->m; ++$i) {
130
for ($j = 0; $j < $this->n; ++$j) {
132
$L[$i][$j] = $this->LU[$i][$j];
133
} elseif ($i == $j) {
140
return new PHPExcel_Shared_JAMA_Matrix($L);
145
* Get upper triangular factor.
147
* @return array Upper triangular factor
149
public function getU() {
150
for ($i = 0; $i < $this->n; ++$i) {
151
for ($j = 0; $j < $this->n; ++$j) {
153
$U[$i][$j] = $this->LU[$i][$j];
159
return new PHPExcel_Shared_JAMA_Matrix($U);
164
* Return pivot permutation vector.
166
* @return array Pivot vector
168
public function getPivot() {
170
} // function getPivot()
178
public function getDoublePivot() {
179
return $this->getPivot();
180
} // function getDoublePivot()
184
* Is the matrix nonsingular?
186
* @return true if U, and hence A, is nonsingular.
188
public function isNonsingular() {
189
for ($j = 0; $j < $this->n; ++$j) {
190
if ($this->LU[$j][$j] == 0) {
195
} // function isNonsingular()
201
* @return array d matrix deterninat
203
public function det() {
204
if ($this->m == $this->n) {
206
for ($j = 0; $j < $this->n; ++$j) {
207
$d *= $this->LU[$j][$j];
211
throw new Exception(PHPExcel_Shared_JAMA_Matrix::MatrixDimensionException);
219
* @param $B A Matrix with as many rows as A and any number of columns.
220
* @return X so that L*U*X = B(piv,:)
221
* @exception IllegalArgumentException Matrix row dimensions must agree.
222
* @exception RuntimeException Matrix is singular.
224
public function solve($B) {
225
if ($B->getRowDimension() == $this->m) {
226
if ($this->isNonsingular()) {
227
// Copy right hand side with pivoting
228
$nx = $B->getColumnDimension();
229
$X = $B->getMatrix($this->piv, 0, $nx-1);
230
// Solve L*Y = B(piv,:)
231
for ($k = 0; $k < $this->n; ++$k) {
232
for ($i = $k+1; $i < $this->n; ++$i) {
233
for ($j = 0; $j < $nx; ++$j) {
234
$X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
239
for ($k = $this->n-1; $k >= 0; --$k) {
240
for ($j = 0; $j < $nx; ++$j) {
241
$X->A[$k][$j] /= $this->LU[$k][$k];
243
for ($i = 0; $i < $k; ++$i) {
244
for ($j = 0; $j < $nx; ++$j) {
245
$X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
251
throw new Exception(self::MatrixSingularException);
254
throw new Exception(self::MatrixSquareException);
256
} // function solve()
258
} // class PHPExcel_Shared_JAMA_LUDecomposition