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