Skip to content

Commit c0eb9ab

Browse files
committed
Code and documentation cleanup.
1 parent 6dcdcef commit c0eb9ab

File tree

4 files changed

+311
-328
lines changed

4 files changed

+311
-328
lines changed

src/LUDecomposition.php

Lines changed: 98 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,52 @@
44

55
/**
66
* Creates an LU Decomposition using Crout's Method and provides methods for using it.
7-
*
7+
*
88
* LU Decomposition references:
99
* @reference: Numerical Recipes, 3rd edition (section 2.3) http://nrbook.com
1010
* @reference: http://www.cs.rpi.edu/~flaherje/pdf/lin6.pdf
11-
*
11+
*
1212
* Crout's Method reference:
1313
* @reference: http://www.physics.utah.edu/~detar/phys6720/handouts/crout.txt
14-
*
14+
*
1515
* Code reference:
1616
* @reference: http://rosettacode.org/wiki/LU_decomposition
1717
*/
18-
19-
20-
class LUDecomposition extends Matrix {
21-
18+
final class LUDecomposition extends Matrix
19+
{
2220
protected $parity = 1; // 1 if the number of row interchanges is even, -1 if it is odd. (used for determinants)
23-
protected $permutations; // Stores a vector representation of the row permutations performed on this matrix.
21+
protected $permutations = []; // Stores a vector representation of the row permutations performed on this matrix.
2422

2523
/**
26-
* Constructor
27-
*
28-
* Copies the matrix, then performs the LU Decomposition.
29-
*
30-
* @param \mcordingley\LinearAlgebra\Matrix The matrix to decompose.
24+
* @param Matrix $matrix The matrix to decompose.
25+
* @throws MatrixException
3126
*/
32-
public function __construct(\mcordingley\LinearAlgebra\Matrix $matrix) {
27+
public function __construct(Matrix $matrix)
28+
{
3329
// Copy the matrix
34-
$matrix->map(function($element, $i, $j, $matrix){
30+
$matrix->map(function ($element, $i, $j) {
3531
$this->internal[$i][$j] = $element;
3632
});
33+
3734
$this->rowCount = $matrix->rows;
3835
$this->columnCount = $matrix->columns;
3936

40-
if( ! $this->isSquare()) throw new MatrixException("Matrix is not square.");
37+
if (!$this->isSquare()) {
38+
throw new MatrixException("Matrix is not square.");
39+
}
4140

4241
$this->LUDecomp();
4342
}
4443

4544
/**
4645
* Performs the LU Decomposition.
47-
*
46+
*
4847
* This uses Crout's method with partial (row) pivoting and implicit scaling
49-
* to perform the decomposition in-place on a copy of the original matrix.
48+
* to perform the decomposition in-place on a copy of the original matrix.
5049
*/
51-
private function LUDecomp() {
52-
$scaling = array();
50+
private function LUDecomp()
51+
{
52+
$scaling = [];
5353
$this->parity = 1; // start parity at +1 (parity is "even" for zero row interchanges)
5454
$n = $this->rows;
5555
$p =& $this->permutations;
@@ -61,169 +61,169 @@ private function LUDecomp() {
6161
$temp = abs($this->internal[$i][$j]);
6262
$biggest = max($temp, $biggest);
6363
}
64-
if ($biggest == 0) throw new MatrixException("Matrix is singular.");
64+
if ($biggest == 0) {
65+
throw new MatrixException("Matrix is singular.");
66+
}
6567
$scaling[$i] = 1 / $biggest;
6668
$p[$i] = $i; // Initialize permutations vector
6769
}
6870

6971
// Now we find the LU decomposition. This is the outer loop over diagonal elements.
70-
for($k = 0; $k < $n; ++$k) {
71-
72+
for ($k = 0; $k < $n; ++$k) {
7273
// Search for the best (biggest) pivot element
7374
$biggest = 0;
7475
$max_row_index = $k;
75-
for($i = $k; $i < $n; ++$i) {
76+
for ($i = $k; $i < $n; ++$i) {
7677
$temp = $scaling[$i] * abs($this->internal[$i][$k]);
77-
if($temp > $biggest) {
78+
if ($temp > $biggest) {
7879
$biggest = $temp;
7980
$max_row_index = $i;
80-
}
81+
}
8182
}
82-
83+
8384
// Perform the row pivot and store in the permuations vector
84-
if($k != $max_row_index) {
85+
if ($k != $max_row_index) {
8586
$this->rowPivot($k, $max_row_index);
86-
$temp = $p[$k];
87-
$p[$k] = $p[$max_row_index];
88-
$p[$max_row_index] = $temp;
89-
$this->parity = -$this->parity; // flip parity
87+
$temp = $p[$k];
88+
$p[$k] = $p[$max_row_index];
89+
$p[$max_row_index] = $temp;
90+
$this->parity = -$this->parity; // flip parity
9091
}
9192

92-
if ($this->internal[$k][$k] == 0) throw new MatrixException("Matrix is singular.");
93+
if ($this->internal[$k][$k] == 0) {
94+
throw new MatrixException("Matrix is singular.");
95+
}
9396

9497
// Crout's algorithm
9598
for ($i = $k + 1; $i < $n; ++$i) {
96-
99+
97100
// Divide by the pivot element
98101
$this->internal[$i][$k] = $this->internal[$i][$k] / $this->internal[$k][$k];
99-
102+
100103
// Subtract from each element in the sub-matrix
101104
for ($j = $k + 1; $j < $n; ++$j) {
102105
$this->internal[$i][$j] = $this->internal[$i][$j] - $this->internal[$i][$k] * $this->internal[$k][$j];
103106
}
104107
}
105108
}
106109
}
107-
110+
108111
/**
109112
* Returns the determinant of the LU decomposition
110-
*
111-
* @see \mcordingley\LinearAlgebra\Matrix::determinant()
112-
* @return double
113+
*
114+
* @return float
113115
*/
114-
public function determinant() {
116+
public function determinant()
117+
{
115118
$n = $this->rows;
116119
$determinant = $this->parity; // Start with +1 for an even # of row swaps, -1 for an odd #
117-
120+
118121
// The determinant is simply the product of the diagonal elements, with sign given
119122
// by the number of row permutations (-1 for odd, +1 for even)
120-
for($i = 0; $i < $n; ++$i) {
123+
for ($i = 0; $i < $n; ++$i) {
121124
$determinant *= $this->get($i, $i);
122125
}
126+
123127
return $determinant;
124128
}
125-
129+
126130
/**
127131
* Swaps $thisRow for $thatRow
128-
*
132+
*
129133
* @param int $thisRow
130134
* @param int $thatRow
131135
*/
132-
private function rowPivot($thisRow, $thatRow) {
133-
$temp = $this->internal[$thisRow];
134-
$this->internal[$thisRow]= $this->internal[$thatRow];
135-
$this->internal[$thatRow] = $temp;
136+
private function rowPivot($thisRow, $thatRow)
137+
{
138+
$temp = $this->internal[$thisRow];
139+
$this->internal[$thisRow] = $this->internal[$thatRow];
140+
$this->internal[$thatRow] = $temp;
136141
}
137-
142+
138143
/**
139144
* Solves a linear set of equations in the form A * x = b for x, where A
140145
* is the decomposed matrix of coefficients (now P*L*U), $x is the vector
141146
* of unknowns, and $b is the vector of knowns.
142-
*
143-
* @param array $b - vector of knowns
144-
* @return array $x - the solution vector
147+
*
148+
* @param array $b vector of knowns
149+
* @return array $x The solution vector
150+
* @throws MatrixException
145151
*/
146-
public function solve(array $b) {
152+
public function solve(array $b)
153+
{
147154
$n = $this->rows;
148-
if(count($b) !== $n) {
149-
throw new MatrixException ('The knowns vector must be the same size as the coefficient matrix.');
155+
156+
if (count($b) !== $n) {
157+
throw new MatrixException('The knowns vector must be the same size as the coefficient matrix.');
150158
}
151159

152-
$y = array(); // L*y = b
153-
$x = array(); // U*x = y
154-
$skip = TRUE;
160+
$y = []; // L*y = b
161+
$x = []; // U*x = y
162+
163+
$skip = true;
155164

156165
// Solve L * y = b for y (forward substitution)
157-
for($i = 0; $i < $n; ++$i) {
166+
for ($i = 0; $i < $n; ++$i) {
158167
$this_b = $b[$this->permutations[$i]]; // Unscramble the permutations
159-
if($skip && $this_b == 0) { // Leading zeroes in b give zeroes in y.
168+
if ($skip && $this_b == 0) { // Leading zeroes in b give zeroes in y.
160169
$y[$i] = 0;
161170
} else {
162-
if($skip) $skip = FALSE; // We found a non-zero element, so don't skip any more.
163-
$y[$i] = $this_b;
164-
for($j = 0; $j < $i; ++$j) {
165-
$y[$i] = $y[$i] - $this->get($i, $j) * $y[$j];
171+
if ($skip) {
172+
// We found a non-zero element, so don't skip any more.
173+
$skip = false;
174+
}
175+
176+
$y[$i] = $this_b;
177+
178+
for ($j = 0; $j < $i; ++$j) {
179+
$y[$i] = $y[$i] - $this->get($i, $j) * $y[$j];
166180
}
167-
168181
}
169182
}
170183

171184
// Solve U * x = y for x (backward substitution)
172-
for($i = $n - 1; $i >= 0; --$i) {
185+
for ($i = $n - 1; $i >= 0; --$i) {
173186
$x[$i] = $y[$i];
174-
for($j = $i + 1; $j < $n; ++$j) {
175-
$x[$i] = $x[$i] - $this->get($i, $j) * $x[$j];
187+
188+
for ($j = $i + 1; $j < $n; ++$j) {
189+
$x[$i] = $x[$i] - $this->get($i, $j) * $x[$j];
176190
}
191+
177192
$x[$i] = $x[$i] / $this->get($i, $i); // Keep division out of the inner loop
178193
}
179194

180195
return $x;
181196
}
182-
197+
183198
/**
184199
* Finds the inverse matrix using the LU decomposition.
185-
*
186-
* Workes by solving LUX = B for X where X is the inverse matrix of same rank and order as LU,
200+
*
201+
* Works by solving LUX = B for X where X is the inverse matrix of same rank and order as LU,
187202
* and B is an identity matrix, also of the same rank and order.
188-
*
189-
* overrides \mcordingley\LinearAlgebra\Matrix::inverse()
190-
*
191-
* @return \mcordingley\LinearAlgebra\Matrix - The inverse matrix
203+
*
204+
* @return Matrix
192205
*/
193-
public function inverse() {
194-
$inverse = array();
195-
206+
public function inverse()
207+
{
208+
$inverse = [];
209+
196210
// Get size of matrix
197211
$n = $this->rows;
198212
$b = array_fill(0, $n, 0); // initialize empty vector
199-
213+
200214
// For each j from 0 to n-1
201-
for($j = 0; $j < $n; ++$j) {
215+
for ($j = 0; $j < $n; ++$j) {
202216
// this is the jth column of the identity matrix
203217
$b[$j] = 1;
204-
218+
205219
// get the solution vector and copy to the jth column of the inverse matrix
206220
$x = $this->solve($b);
207-
for($i = 0; $i < $n; ++$i) {
221+
for ($i = 0; $i < $n; ++$i) {
208222
$inverse[$i][$j] = $x[$i];
209223
}
210224
$b[$j] = 0; // Get the vector ready for the next column.
211225
}
226+
212227
return new Matrix($inverse);
213228
}
214-
215-
/**
216-
* Utility method for debugging - echos the
217-
* matrix in easy-to-read format.
218-
*/
219-
private function printMatrix(array $matrix)
220-
{
221-
$n = count($matrix);
222-
foreach($matrix as $row) {
223-
foreach($row as $column){
224-
echo $column.', ';
225-
}
226-
echo "\n";
227-
}
228-
}
229-
}
229+
}

0 commit comments

Comments
 (0)