root / tmp / org.txm.analec.rcp / src / JamaPlus / LUDecomposition.java @ 2019
Historique | Voir | Annoter | Télécharger (8,29 ko)
1 | 481 | mdecorde | package JamaPlus; |
---|---|---|---|
2 | 481 | mdecorde | |
3 | 481 | mdecorde | /** LU Decomposition.
|
4 | 481 | mdecorde | <P>
|
5 | 481 | mdecorde | For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
|
6 | 481 | mdecorde | unit lower triangular matrix L, an n-by-n upper triangular matrix U,
|
7 | 481 | mdecorde | and a permutation vector piv of length m so that A(piv,:) = L*U.
|
8 | 481 | mdecorde | If m < n, then L is m-by-m and U is m-by-n.
|
9 | 481 | mdecorde | <P>
|
10 | 481 | mdecorde | The LU decompostion with pivoting always exists, even if the matrix is
|
11 | 481 | mdecorde | singular, so the constructor will never fail. The primary use of the
|
12 | 481 | mdecorde | LU decomposition is in the solution of square systems of simultaneous
|
13 | 481 | mdecorde | linear equations. This will fail if isNonsingular() returns false.
|
14 | 481 | mdecorde | */
|
15 | 481 | mdecorde | |
16 | 481 | mdecorde | public class LUDecomposition implements java.io.Serializable { |
17 | 481 | mdecorde | |
18 | 481 | mdecorde | /* ------------------------
|
19 | 481 | mdecorde | Class variables
|
20 | 481 | mdecorde | * ------------------------ */
|
21 | 481 | mdecorde | |
22 | 481 | mdecorde | /** Array for internal storage of decomposition.
|
23 | 481 | mdecorde | @serial internal array storage.
|
24 | 481 | mdecorde | */
|
25 | 481 | mdecorde | private double[][] LU; |
26 | 481 | mdecorde | |
27 | 481 | mdecorde | /** Row and column dimensions, and pivot sign.
|
28 | 481 | mdecorde | @serial column dimension.
|
29 | 481 | mdecorde | @serial row dimension.
|
30 | 481 | mdecorde | @serial pivot sign.
|
31 | 481 | mdecorde | */
|
32 | 481 | mdecorde | private int m, n, pivsign; |
33 | 481 | mdecorde | |
34 | 481 | mdecorde | /** Internal storage of pivot vector.
|
35 | 481 | mdecorde | @serial pivot vector.
|
36 | 481 | mdecorde | */
|
37 | 481 | mdecorde | private int[] piv; |
38 | 481 | mdecorde | |
39 | 481 | mdecorde | /* ------------------------
|
40 | 481 | mdecorde | Constructor
|
41 | 481 | mdecorde | * ------------------------ */
|
42 | 481 | mdecorde | |
43 | 481 | mdecorde | /** LU Decomposition
|
44 | 481 | mdecorde | @param A Rectangular matrix
|
45 | 481 | mdecorde | @return Structure to access L, U and piv.
|
46 | 481 | mdecorde | */
|
47 | 481 | mdecorde | |
48 | 481 | mdecorde | public LUDecomposition (Matrix A) {
|
49 | 481 | mdecorde | |
50 | 481 | mdecorde | // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
|
51 | 481 | mdecorde | |
52 | 481 | mdecorde | LU = A.getArrayCopy(); |
53 | 481 | mdecorde | m = A.getRowDimension(); |
54 | 481 | mdecorde | n = A.getColumnDimension(); |
55 | 481 | mdecorde | piv = new int[m]; |
56 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
57 | 481 | mdecorde | piv[i] = i; |
58 | 481 | mdecorde | } |
59 | 481 | mdecorde | pivsign = 1;
|
60 | 481 | mdecorde | double[] LUrowi; |
61 | 481 | mdecorde | double[] LUcolj = new double[m]; |
62 | 481 | mdecorde | |
63 | 481 | mdecorde | // Outer loop.
|
64 | 481 | mdecorde | |
65 | 481 | mdecorde | for (int j = 0; j < n; j++) { |
66 | 481 | mdecorde | |
67 | 481 | mdecorde | // Make a copy of the j-th column to localize references.
|
68 | 481 | mdecorde | |
69 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
70 | 481 | mdecorde | LUcolj[i] = LU[i][j]; |
71 | 481 | mdecorde | } |
72 | 481 | mdecorde | |
73 | 481 | mdecorde | // Apply previous transformations.
|
74 | 481 | mdecorde | |
75 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
76 | 481 | mdecorde | LUrowi = LU[i]; |
77 | 481 | mdecorde | |
78 | 481 | mdecorde | // Most of the time is spent in the following dot product.
|
79 | 481 | mdecorde | |
80 | 481 | mdecorde | int kmax = Math.min(i,j); |
81 | 481 | mdecorde | double s = 0.0; |
82 | 481 | mdecorde | for (int k = 0; k < kmax; k++) { |
83 | 481 | mdecorde | s += LUrowi[k]*LUcolj[k]; |
84 | 481 | mdecorde | } |
85 | 481 | mdecorde | |
86 | 481 | mdecorde | LUrowi[j] = LUcolj[i] -= s; |
87 | 481 | mdecorde | } |
88 | 481 | mdecorde | |
89 | 481 | mdecorde | // Find pivot and exchange if necessary.
|
90 | 481 | mdecorde | |
91 | 481 | mdecorde | int p = j;
|
92 | 481 | mdecorde | for (int i = j+1; i < m; i++) { |
93 | 481 | mdecorde | if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) { |
94 | 481 | mdecorde | p = i; |
95 | 481 | mdecorde | } |
96 | 481 | mdecorde | } |
97 | 481 | mdecorde | if (p != j) {
|
98 | 481 | mdecorde | for (int k = 0; k < n; k++) { |
99 | 481 | mdecorde | double t = LU[p][k]; LU[p][k] = LU[j][k]; LU[j][k] = t;
|
100 | 481 | mdecorde | } |
101 | 481 | mdecorde | int k = piv[p]; piv[p] = piv[j]; piv[j] = k;
|
102 | 481 | mdecorde | pivsign = -pivsign; |
103 | 481 | mdecorde | } |
104 | 481 | mdecorde | |
105 | 481 | mdecorde | // Compute multipliers.
|
106 | 481 | mdecorde | |
107 | 481 | mdecorde | if (j < m & LU[j][j] != 0.0) { |
108 | 481 | mdecorde | for (int i = j+1; i < m; i++) { |
109 | 481 | mdecorde | LU[i][j] /= LU[j][j]; |
110 | 481 | mdecorde | } |
111 | 481 | mdecorde | } |
112 | 481 | mdecorde | } |
113 | 481 | mdecorde | } |
114 | 481 | mdecorde | |
115 | 481 | mdecorde | /* ------------------------
|
116 | 481 | mdecorde | Temporary, experimental code.
|
117 | 481 | mdecorde | ------------------------ *\
|
118 | 481 | mdecorde | |
119 | 481 | mdecorde | \** LU Decomposition, computed by Gaussian elimination.
|
120 | 481 | mdecorde | <P>
|
121 | 481 | mdecorde | This constructor computes L and U with the "daxpy"-based elimination
|
122 | 481 | mdecorde | algorithm used in LINPACK and MATLAB. In Java, we suspect the dot-product,
|
123 | 481 | mdecorde | Crout algorithm will be faster. We have temporarily included this
|
124 | 481 | mdecorde | constructor until timing experiments confirm this suspicion.
|
125 | 481 | mdecorde | <P>
|
126 | 481 | mdecorde | @param A Rectangular matrix
|
127 | 481 | mdecorde | @param linpackflag Use Gaussian elimination. Actual value ignored.
|
128 | 481 | mdecorde | @return Structure to access L, U and piv.
|
129 | 481 | mdecorde | *\
|
130 | 481 | mdecorde | |
131 | 481 | mdecorde | public LUDecomposition (Matrix A, int linpackflag) {
|
132 | 481 | mdecorde | // Initialize.
|
133 | 481 | mdecorde | LU = A.getArrayCopy();
|
134 | 481 | mdecorde | m = A.getRowDimension();
|
135 | 481 | mdecorde | n = A.getColumnDimension();
|
136 | 481 | mdecorde | piv = new int[m];
|
137 | 481 | mdecorde | for (int i = 0; i < m; i++) {
|
138 | 481 | mdecorde | piv[i] = i;
|
139 | 481 | mdecorde | }
|
140 | 481 | mdecorde | pivsign = 1;
|
141 | 481 | mdecorde | // Main loop.
|
142 | 481 | mdecorde | for (int k = 0; k < n; k++) {
|
143 | 481 | mdecorde | // Find pivot.
|
144 | 481 | mdecorde | int p = k;
|
145 | 481 | mdecorde | for (int i = k+1; i < m; i++) {
|
146 | 481 | mdecorde | if (Math.abs(LU[i][k]) > Math.abs(LU[p][k])) {
|
147 | 481 | mdecorde | p = i;
|
148 | 481 | mdecorde | }
|
149 | 481 | mdecorde | }
|
150 | 481 | mdecorde | // Exchange if necessary.
|
151 | 481 | mdecorde | if (p != k) {
|
152 | 481 | mdecorde | for (int j = 0; j < n; j++) {
|
153 | 481 | mdecorde | double t = LU[p][j]; LU[p][j] = LU[k][j]; LU[k][j] = t;
|
154 | 481 | mdecorde | }
|
155 | 481 | mdecorde | int t = piv[p]; piv[p] = piv[k]; piv[k] = t;
|
156 | 481 | mdecorde | pivsign = -pivsign;
|
157 | 481 | mdecorde | }
|
158 | 481 | mdecorde | // Compute multipliers and eliminate k-th column.
|
159 | 481 | mdecorde | if (LU[k][k] != 0.0) {
|
160 | 481 | mdecorde | for (int i = k+1; i < m; i++) {
|
161 | 481 | mdecorde | LU[i][k] /= LU[k][k];
|
162 | 481 | mdecorde | for (int j = k+1; j < n; j++) {
|
163 | 481 | mdecorde | LU[i][j] -= LU[i][k]*LU[k][j];
|
164 | 481 | mdecorde | }
|
165 | 481 | mdecorde | }
|
166 | 481 | mdecorde | }
|
167 | 481 | mdecorde | }
|
168 | 481 | mdecorde | }
|
169 | 481 | mdecorde | |
170 | 481 | mdecorde | \* ------------------------
|
171 | 481 | mdecorde | End of temporary code.
|
172 | 481 | mdecorde | * ------------------------ */
|
173 | 481 | mdecorde | |
174 | 481 | mdecorde | /* ------------------------
|
175 | 481 | mdecorde | Public Methods
|
176 | 481 | mdecorde | * ------------------------ */
|
177 | 481 | mdecorde | |
178 | 481 | mdecorde | /** Is the matrix nonsingular?
|
179 | 481 | mdecorde | @return true if U, and hence A, is nonsingular.
|
180 | 481 | mdecorde | */
|
181 | 481 | mdecorde | |
182 | 481 | mdecorde | public boolean isNonsingular () { |
183 | 481 | mdecorde | for (int j = 0; j < n; j++) { |
184 | 481 | mdecorde | if (LU[j][j] == 0) |
185 | 481 | mdecorde | return false; |
186 | 481 | mdecorde | } |
187 | 481 | mdecorde | return true; |
188 | 481 | mdecorde | } |
189 | 481 | mdecorde | |
190 | 481 | mdecorde | /** Return lower triangular factor
|
191 | 481 | mdecorde | @return L
|
192 | 481 | mdecorde | */
|
193 | 481 | mdecorde | |
194 | 481 | mdecorde | public Matrix getL () {
|
195 | 481 | mdecorde | Matrix X = new Matrix(m,n);
|
196 | 481 | mdecorde | double[][] L = X.getArray(); |
197 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
198 | 481 | mdecorde | for (int j = 0; j < n; j++) { |
199 | 481 | mdecorde | if (i > j) {
|
200 | 481 | mdecorde | L[i][j] = LU[i][j]; |
201 | 481 | mdecorde | } else if (i == j) { |
202 | 481 | mdecorde | L[i][j] = 1.0;
|
203 | 481 | mdecorde | } else {
|
204 | 481 | mdecorde | L[i][j] = 0.0;
|
205 | 481 | mdecorde | } |
206 | 481 | mdecorde | } |
207 | 481 | mdecorde | } |
208 | 481 | mdecorde | return X;
|
209 | 481 | mdecorde | } |
210 | 481 | mdecorde | |
211 | 481 | mdecorde | /** Return upper triangular factor
|
212 | 481 | mdecorde | @return U
|
213 | 481 | mdecorde | */
|
214 | 481 | mdecorde | |
215 | 481 | mdecorde | public Matrix getU () {
|
216 | 481 | mdecorde | Matrix X = new Matrix(n,n);
|
217 | 481 | mdecorde | double[][] U = X.getArray(); |
218 | 481 | mdecorde | for (int i = 0; i < n; i++) { |
219 | 481 | mdecorde | for (int j = 0; j < n; j++) { |
220 | 481 | mdecorde | if (i <= j) {
|
221 | 481 | mdecorde | U[i][j] = LU[i][j]; |
222 | 481 | mdecorde | } else {
|
223 | 481 | mdecorde | U[i][j] = 0.0;
|
224 | 481 | mdecorde | } |
225 | 481 | mdecorde | } |
226 | 481 | mdecorde | } |
227 | 481 | mdecorde | return X;
|
228 | 481 | mdecorde | } |
229 | 481 | mdecorde | |
230 | 481 | mdecorde | /** Return pivot permutation vector
|
231 | 481 | mdecorde | @return piv
|
232 | 481 | mdecorde | */
|
233 | 481 | mdecorde | |
234 | 481 | mdecorde | public int[] getPivot () { |
235 | 481 | mdecorde | int[] p = new int[m]; |
236 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
237 | 481 | mdecorde | p[i] = piv[i]; |
238 | 481 | mdecorde | } |
239 | 481 | mdecorde | return p;
|
240 | 481 | mdecorde | } |
241 | 481 | mdecorde | |
242 | 481 | mdecorde | /** Return pivot permutation vector as a one-dimensional double array
|
243 | 481 | mdecorde | @return (double) piv
|
244 | 481 | mdecorde | */
|
245 | 481 | mdecorde | |
246 | 481 | mdecorde | public double[] getDoublePivot () { |
247 | 481 | mdecorde | double[] vals = new double[m]; |
248 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
249 | 481 | mdecorde | vals[i] = (double) piv[i];
|
250 | 481 | mdecorde | } |
251 | 481 | mdecorde | return vals;
|
252 | 481 | mdecorde | } |
253 | 481 | mdecorde | |
254 | 481 | mdecorde | /** Determinant
|
255 | 481 | mdecorde | @return det(A)
|
256 | 481 | mdecorde | @exception IllegalArgumentException Matrix must be square
|
257 | 481 | mdecorde | */
|
258 | 481 | mdecorde | |
259 | 481 | mdecorde | public double det () { |
260 | 481 | mdecorde | if (m != n) {
|
261 | 481 | mdecorde | throw new IllegalArgumentException("Matrix must be square."); |
262 | 481 | mdecorde | } |
263 | 481 | mdecorde | double d = (double) pivsign; |
264 | 481 | mdecorde | for (int j = 0; j < n; j++) { |
265 | 481 | mdecorde | d *= LU[j][j]; |
266 | 481 | mdecorde | } |
267 | 481 | mdecorde | return d;
|
268 | 481 | mdecorde | } |
269 | 481 | mdecorde | |
270 | 481 | mdecorde | /** Solve A*X = B
|
271 | 481 | mdecorde | @param B A Matrix with as many rows as A and any number of columns.
|
272 | 481 | mdecorde | @return X so that L*U*X = B(piv,:)
|
273 | 481 | mdecorde | @exception IllegalArgumentException Matrix row dimensions must agree.
|
274 | 481 | mdecorde | @exception RuntimeException Matrix is singular.
|
275 | 481 | mdecorde | */
|
276 | 481 | mdecorde | |
277 | 481 | mdecorde | public Matrix solve (Matrix B) {
|
278 | 481 | mdecorde | if (B.getRowDimension() != m) {
|
279 | 481 | mdecorde | throw new IllegalArgumentException("Matrix row dimensions must agree."); |
280 | 481 | mdecorde | } |
281 | 481 | mdecorde | if (!this.isNonsingular()) { |
282 | 481 | mdecorde | throw new RuntimeException("Matrix is singular."); |
283 | 481 | mdecorde | } |
284 | 481 | mdecorde | |
285 | 481 | mdecorde | // Copy right hand side with pivoting
|
286 | 481 | mdecorde | int nx = B.getColumnDimension();
|
287 | 481 | mdecorde | Matrix Xmat = B.getMatrix(piv,0,nx-1); |
288 | 481 | mdecorde | double[][] X = Xmat.getArray(); |
289 | 481 | mdecorde | |
290 | 481 | mdecorde | // Solve L*Y = B(piv,:)
|
291 | 481 | mdecorde | for (int k = 0; k < n; k++) { |
292 | 481 | mdecorde | for (int i = k+1; i < n; i++) { |
293 | 481 | mdecorde | for (int j = 0; j < nx; j++) { |
294 | 481 | mdecorde | X[i][j] -= X[k][j]*LU[i][k]; |
295 | 481 | mdecorde | } |
296 | 481 | mdecorde | } |
297 | 481 | mdecorde | } |
298 | 481 | mdecorde | // Solve U*X = Y;
|
299 | 481 | mdecorde | for (int k = n-1; k >= 0; k--) { |
300 | 481 | mdecorde | for (int j = 0; j < nx; j++) { |
301 | 481 | mdecorde | X[k][j] /= LU[k][k]; |
302 | 481 | mdecorde | } |
303 | 481 | mdecorde | for (int i = 0; i < k; i++) { |
304 | 481 | mdecorde | for (int j = 0; j < nx; j++) { |
305 | 481 | mdecorde | X[i][j] -= X[k][j]*LU[i][k]; |
306 | 481 | mdecorde | } |
307 | 481 | mdecorde | } |
308 | 481 | mdecorde | } |
309 | 481 | mdecorde | return Xmat;
|
310 | 481 | mdecorde | } |
311 | 481 | mdecorde | } |