SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
DMatrix.java
1/*
2 * Class: DMatrix
3 * Description: Methods for matrix calculations with double numbers
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.util;
26
27import cern.colt.matrix.*;
28import cern.colt.matrix.impl.*;
29import cern.colt.matrix.linalg.*;
30import cern.jet.math.Functions;
31
38public class DMatrix {
39 private double[][] mat; // matrix of double's
40 private int r, c; // number of rows, columns
41
42 // [9/9] Pade numerator coefficients for exp(x);
43 private static double[] cPade = { 17643225600d, 8821612800d, 2075673600d, 302702400, 30270240, 2162160, 110880, 3960,
44 90, 1 };
45
46 // [7/7] Pade numerator coefficients for (exp(x) - 1) / x
47 private static double[] p_em1 = { 1.0, 1.0 / 30, 1.0 / 30, 1.0 / 936, 1.0 / 4680, 1.0 / 171600, 1.0 / 3603600,
48 1.0 / 259459200 };
49
50 // [7/7] Pade denominator coefficients for (exp(x) - 1) / x
51 private static double[] q_em1 = { 1.0, -(7.0 / 15), 1.0 / 10, -(1.0 / 78), 1.0 / 936, -(1.0 / 17160), 1.0 / 514800,
52 -(1.0 / 32432400) };
53
54 // ======================================================================
55
56 /*
57 * Matrix multiplication $C = AB$. All three matrices are square, banded, and
58 * upper triangular. $A$ has a non-zero diagonal, \texttt{sa} non-zero
59 * superdiagonals, and thus a bandwidth of \texttt{sa + 1}. The non-zero
60 * elements of $A_{ij}$ are those for which $j - s_a \le i \le j$. Similarly for
61 * $B$ which has a bandwidth of \texttt{sb + 1}. The resulting matrix $C$ has
62 * \texttt{sa + sb} non-zero superdiagonals, and a bandwidth of \texttt{sa + sb
63 * + 1}.
64 */
65 private static void innerMultBand(DoubleMatrix2D A0, int sa, DoubleMatrix2D B0, int sb, DoubleMatrix2D C) {
66 DoubleMatrix2D A, B;
67 if (A0 == C)
68 A = A0.copy();
69 else
70 A = A0;
71 if (B0 == C)
72 B = B0.copy();
73 else
74 B = B0;
75 C.assign(0.);
76 final int n = A.rows();
77 int kmin, kmax;
78 double x, y, z;
79 for (int i = 0; i < n; ++i) {
80 int jmax = Math.min(i + sa + sb, n - 1);
81 for (int j = i; j <= jmax; ++j) {
82 kmin = Math.max(i, j - sb);
83 kmax = Math.min(i + sa, j);
84 z = 0;
85 for (int k = kmin; k <= kmax; ++k) {
86 x = A.getQuick(i, k);
87 y = B.getQuick(k, j);
88 z += x * y;
89 }
90 C.setQuick(i, j, z);
91 }
92 }
93 }
94
95 // ======================================================================
96
97 private static int getScale(final DoubleMatrix2D A, double theta) {
98 // assumes A is an upper bidiagonal matrix
99 final double norm = norm1bidiag(A) / theta;
100 int s;
101 if (norm > 1)
102 s = (int) Math.ceil(Num.log2(norm));
103 else
104 s = 0;
105 return s;
106 }
107
108 // ======================================================================
109
110 private static DoubleMatrix2D m_taylor(final DoubleMatrix2D A) {
111 // Compute and returns (e^A - I), using the Taylor series around 0
112
113 final double EPS = 1.0e-12;
114 final int k = A.rows();
115 final int JMAX = 2 * k + 100;
116 DoubleMatrix2D Sum = A.copy();
117 DoubleMatrix2D Term = A.copy();
118
119 Functions F = Functions.functions; // alias F
120 Algebra alge = new Algebra();
121 double normS, normT;
122
123 for (int j = 2; j <= JMAX; ++j) {
124 Term = alge.mult(A, Term); // Term <-- A*Term
125 Term.assign(F.mult(1.0 / j)); // Term <-- Term/j
126 Sum.assign(Term, F.plus); // Sum <-- Sum + Term
127 if (j > k + 5) {
128 normS = alge.normInfinity(Sum);
129 normT = alge.normInfinity(Term);
130 if (normT <= normS * EPS)
131 break;
132 }
133 }
134 return Sum;
135 }
136
137 // ======================================================================
138
139 private static DoubleMatrix1D m_taylor(final DoubleMatrix2D A, final DoubleMatrix1D b) {
140 // Compute and returns (exp(A) - I)b, using the Taylor series around 0
141
142 final double EPS = 1.0e-12;
143 final int k = A.rows();
144 final int JMAX = 2 * k + 100;
145 DoubleFactory1D factory = DoubleFactory1D.dense;
146 DoubleMatrix1D Term = b.copy();
147 DoubleMatrix1D Sum = factory.make(k);
148
149 Functions F = Functions.functions; // alias F
150 Algebra alge = new Algebra();
151 double Snorm, Tnorm;
152
153 for (int j = 1; j <= JMAX; ++j) {
154 Term = alge.mult(A, Term); // Term <-- A*Term
155 Term.assign(F.mult(1.0 / j)); // Term <-- Term/j
156 Sum.assign(Term, F.plus); // Sum <-- Sum + Term
157 if (j > k + 5) {
158 Tnorm = alge.norm1(Term);
159 Snorm = alge.norm1(Sum);
160 if (Tnorm <= Snorm * EPS)
161 break;
162 }
163 }
164 return Sum;
165 }
166
167 // ======================================================================
168
169 private static DoubleMatrix2D m_expmiBidiag(final DoubleMatrix2D A) {
170 // Use the diagonal Pade approximant of order [7/7] for (exp(A) - I)/A:
171 // See Higham J.H., Functions of matrices, SIAM, 2008, p. 262.
172 // This method scale A to a matrix with small norm B = A/2^s,
173 // compute U = (exp(B) - I) with Pade approximants, and returns U.
174 // Returns also the scale s in scale[0].
175
176 final int n = A.rows();
177 DoubleMatrix2D B = A.copy();
178 DoubleFactory2D fac = DoubleFactory2D.dense;
179 final DoubleMatrix2D I = fac.identity(n);
180 final DoubleMatrix2D B2 = fac.make(n, n);
181 final DoubleMatrix2D B4 = fac.make(n, n);
182 final DoubleMatrix2D B6 = fac.make(n, n);
183 DMatrix.multBand(B, 1, B, 1, B2); // B^2
184 DMatrix.multBand(B2, 2, B2, 2, B4); // B^4
185 DMatrix.multBand(B4, 4, B2, 2, B6); // B^6
186
187 DoubleMatrix2D V = B6.copy();
188 DoubleMatrix2D U = B4.copy();
189 DMatrix.addMultBand(p_em1[4], U, 4, p_em1[2], B2, 2); // U <-- U*p_em1[4] + B2*p_em1[2]
190 DMatrix.addMultBand(p_em1[6], V, 6, p_em1[0], I, 0); // V <-- V*p_em1[6] + I*p_em1[0]
191 DMatrix.addMultBand(1.0, V, 6, 1.0, U, 6); // V <-- V + U
192
193 DoubleMatrix2D W = B6.copy();
194 U = B4.copy();
195 DMatrix.addMultBand(p_em1[5], U, 4, p_em1[3], B2, 2); // U <-- U*p_em1[5] + B2*p_em1[3]
196 DMatrix.addMultBand(p_em1[7], W, 6, p_em1[1], I, 0); // W <-- W*p_em1[7] + I*p_em1[1]
197 DMatrix.addMultBand(1.0, W, 6, 1.0, U, 6); // W <-- W + U
198 DMatrix.multBand(W, 6, B, 1, U); // U <-- W*B
199
200 DMatrix.addMultBand(1.0, V, 6, 1.0, U, 7); // V <-- V + U
201 DoubleMatrix2D N = V.copy(); // numerator Pade
202
203 V = B6.copy();
204 U = B4.copy();
205 DMatrix.addMultBand(q_em1[4], U, 4, q_em1[2], B2, 2); // U <-- U*q_em1[4] + B2*q_em1[2]
206 DMatrix.addMultBand(q_em1[6], V, 6, q_em1[0], I, 0); // V <-- V*q_em1[6] + I*q_em1[0]
207 DMatrix.addMultBand(1.0, V, 6, 1.0, U, 6); // V <-- V + U
208
209 W = B6.copy();
210 U = B4.copy();
211 DMatrix.addMultBand(q_em1[5], U, 4, q_em1[3], B2, 2); // U <-- U*q_em1[5] + B2*q_em1[3]
212 DMatrix.addMultBand(q_em1[7], W, 6, q_em1[1], I, 0); // W <-- W*q_em1[7] + I*q_em1[1]
213 DMatrix.addMultBand(1.0, W, 6, 1.0, U, 6); // W <-- W + U
214 DMatrix.multBand(W, 6, B, 1, U); // U <-- W*B
215
216 DMatrix.addMultBand(1.0, V, 6, 1.0, U, 7); // V <-- V + U, denominator Pade
217
218 // Compute Pade approximant W = N/V for (exp(B) - I)/B
219 DMatrix.solveTriangular(V, N, W);
220 DMatrix.multBand(B, 1, W, n - 1, U); // (exp(B) - I) = U <-- B*W
221
222 // calcDiagm1 (B, U);
223 return U;
224 }
225
226 static void addMultTriang(final DoubleMatrix2D A, DoubleMatrix1D b, double h) {
227 /*
228 * Multiplies the upper triangular matrix A by vector b multiplied by h. Put the
229 * result back in b.
230 */
231 final int n = A.rows();
232 double z;
233 for (int i = 0; i < n; ++i) {
234 for (int j = i; j < n; ++j) {
235 z = A.getQuick(i, j) * b.getQuick(j);
236 b.setQuick(i, h * z);
237 }
238 }
239 }
240
241 // ======================================================================
242 /*
243 * Compute the 1-norm for matrix B, which is bidiagonal. The only non-zero
244 * elements are on the diagonal and the first superdiagonal.
245 *
246 * @param B matrix
247 *
248 * @return the norm
249 */
250 private static double norm1bidiag(DoubleMatrix2D B) {
251 final int n = B.rows();
252 double x;
253 double norm = Math.abs(B.getQuick(0, 0));
254 for (int i = 1; i < n; ++i) {
255 x = Math.abs(B.getQuick(i - 1, i)) + Math.abs(B.getQuick(i, i));
256 if (x > norm)
257 norm = x;
258 }
259 return norm;
260 }
261
268 public DMatrix(int r, int c) {
269 mat = new double[r][c];
270 this.r = r;
271 this.c = c;
272 }
273
282 public DMatrix(double[][] data, int r, int c) {
283 this(r, c);
284 for (int i = 0; i < r; i++)
285 for (int j = 0; j < c; j++)
286 mat[i][j] = data[i][j];
287 }
288
294 public DMatrix(DMatrix that) {
295 this(that.mat, that.r, that.c);
296 }
297
306 public static void CholeskyDecompose(double[][] M, double[][] L) {
307 int d = M.length;
308 DoubleMatrix2D MM = new DenseDoubleMatrix2D(M);
309 DoubleMatrix2D LL = new DenseDoubleMatrix2D(d, d);
310 CholeskyDecomposition decomp = new CholeskyDecomposition(MM);
311 LL = decomp.getL();
312 for (int i = 0; i < L.length; i++)
313 for (int j = 0; j <= i; j++)
314 L[i][j] = LL.get(i, j);
315 for (int i = 0; i < L.length; i++)
316 for (int j = i + 1; j < L.length; j++)
317 L[i][j] = 0.0;
318 }
319
328 public static DoubleMatrix2D CholeskyDecompose(DoubleMatrix2D M) {
329 CholeskyDecomposition decomp = new CholeskyDecomposition(M);
330 return decomp.getL();
331 }
332
345 public static void PCADecompose(double[][] M, double[][] A, double[] lambda) {
346 int d = M.length;
347 DoubleMatrix2D MM = new DenseDoubleMatrix2D(M);
348 DoubleMatrix2D AA = new DenseDoubleMatrix2D(d, d);
349 AA = PCADecompose(MM, lambda);
350
351 for (int i = 0; i < d; i++)
352 for (int j = 0; j < d; j++)
353 A[i][j] = AA.get(i, j);
354 }
355
367 public static DoubleMatrix2D PCADecompose(DoubleMatrix2D M, double[] lambda) {
368 // L'objet SingularValueDecomposition permet de recuperer la matrice
369 // des valeurs propres en ordre decroissant et celle des vecteurs propres de
370 // sigma (pour une matrice symetrique et definie-positive seulement).
371
372 SingularValueDecomposition sv = new SingularValueDecomposition(M);
373 // D contient les valeurs propres sur la diagonale
374 DoubleMatrix2D D = sv.getS();
375
376 for (int i = 0; i < D.rows(); ++i)
377 lambda[i] = D.getQuick(i, i);
378
379 // Calculer la racine carree des valeurs propres
380 for (int i = 0; i < D.rows(); ++i)
381 D.setQuick(i, i, Math.sqrt(lambda[i]));
382 DoubleMatrix2D P = sv.getV();
383 // Multiplier par la matrice orthogonale (ici P)
384 return P.zMult(D, null);
385 }
386
396 public static double[] solveLU(double[][] A, double[] b) {
397 DoubleMatrix2D M = new DenseDoubleMatrix2D(A);
398 DoubleMatrix1D c = new DenseDoubleMatrix1D(b);
399 LUDecompositionQuick lu = new LUDecompositionQuick();
400 lu.decompose(M);
401 lu.solve(c);
402 return c.toArray();
403 }
404
414 public static void solveTriangular(DoubleMatrix2D U, DoubleMatrix2D B, DoubleMatrix2D X) {
415 final int n = U.rows();
416 final int m = B.columns();
417 double y, z;
418 X.assign(0.);
419 for (int j = 0; j < m; ++j) {
420 for (int i = n - 1; i >= 0; --i) {
421 z = B.getQuick(i, j);
422 for (int k = i + 1; k < n; ++k)
423 z -= U.getQuick(i, k) * X.getQuick(k, j);
424 z /= U.getQuick(i, i);
425 X.setQuick(i, j, z);
426 }
427 }
428 }
429
436 public static double[][] exp(double[][] A) {
437 DoubleMatrix2D V = new DenseDoubleMatrix2D(A);
438 DoubleMatrix2D R = exp(V);
439 return R.toArray();
440 }
441
450 public static DoubleMatrix2D exp(final DoubleMatrix2D A) {
451 /*
452 * Use the diagonal Pade approximant of order [9/9] for exp: See Higham J.H.,
453 * Functions of matrices, SIAM, 2008.
454 */
455 DoubleMatrix2D B = A.copy();
456 int n = B.rows();
457 Algebra alge = new Algebra();
458 final double mu = alge.trace(B) / n;
459 double x;
460
461 // B <-- B - mu*I
462 for (int i = 0; i < n; ++i) {
463 x = B.getQuick(i, i);
464 B.setQuick(i, i, x - mu);
465 }
466 /*
467 * int bal = 0; if (bal > 0) { throw new UnsupportedOperationException
468 * (" balancing"); }
469 */
470
471 final double THETA9 = 2.097847961257068; // in Higham
472 int s = getScale(B, THETA9);
473
474 Functions F = Functions.functions; // alias F
475 // B <-- B/2^s
476 double v = 1.0 / Math.pow(2.0, s);
477 if (v <= 0)
478 throw new IllegalArgumentException(" v <= 0");
479 B.assign(F.mult(v));
480
481 DoubleFactory2D fac = DoubleFactory2D.dense;
482 final DoubleMatrix2D B0 = fac.identity(n); // B^0 = I
483 final DoubleMatrix2D B2 = alge.mult(B, B); // B^2
484 final DoubleMatrix2D B4 = alge.mult(B2, B2); // B^4
485
486 DoubleMatrix2D T = B2.copy(); // T = work matrix
487 DoubleMatrix2D W = B4.copy(); // W = work matrix
488 W.assign(F.mult(cPade[9])); // W <-- W*cPade[9]
489 W.assign(T, F.plusMult(cPade[7])); // W <-- W + T*cPade[7]
490 DoubleMatrix2D U = alge.mult(B4, W); // U <-- B4*W
491
492 // T = B2.copy();
493 W = B4.copy();
494 W.assign(F.mult(cPade[5])); // W <-- W*cPade[5]
495 W.assign(T, F.plusMult(cPade[3])); // W <-- W + T*cPade[3]
496 W.assign(B0, F.plusMult(cPade[1])); // W <-- W + B0*cPade[1]
497 U.assign(W, F.plus); // U <-- U + W
498 U = alge.mult(B, U); // U <-- B*U
499
500 // T = B2.copy();
501 W = B4.copy();
502 W.assign(F.mult(cPade[8])); // W <-- W*cPade[8]
503 W.assign(T, F.plusMult(cPade[6])); // W <-- W + T*cPade[6]
504 DoubleMatrix2D V = alge.mult(B4, W); // V <-- B4*W
505
506 // T = B2.copy();
507 W = B4.copy();
508 W.assign(F.mult(cPade[4])); // W <-- W*cPade[4]
509 W.assign(T, F.plusMult(cPade[2])); // W <-- W + T*cPade[2]
510 W.assign(B0, F.plusMult(cPade[0])); // W <-- W + B0*cPade[0]
511 V.assign(W, F.plus); // V <-- V + W
512
513 W = V.copy();
514 W.assign(U, F.plus); // W = V + U, Pade numerator
515 T = V.copy();
516 T.assign(U, F.minus); // T = V - U, Pade denominator
517
518 // Compute Pade approximant for exponential = W / T
519 LUDecomposition lu = new LUDecomposition(T);
520 B = lu.solve(W);
521
522 if (false) {
523 // This overflows for large |mu|
524 // B <-- B^(2^s)
525 for (int i = 0; i < s; i++)
526 B = alge.mult(B, B);
527 /*
528 * if (bal > 0) { throw new UnsupportedOperationException (" balancing"); }
529 */
530 v = Math.exp(mu);
531 B.assign(F.mult(v)); // B <-- B*e^mu
532
533 } else {
534 // equivalent to B^(2^s) * e^mu, but only if no balancing
535 double r = mu * v;
536 r = Math.exp(r);
537 B.assign(F.mult(r));
538 for (int i = 0; i < s; i++)
539 B = alge.mult(B, B);
540 }
541
542 return B;
543 }
544
554 public static DoubleMatrix2D expBidiagonal(final DoubleMatrix2D A) {
555 // Use the diagonal Pade approximant of order [9/9] for exp:
556 // See Higham J.H., Functions of matrices, SIAM, 2008.
557 // This method scale A to a matrix with small norm B = A/2^s,
558 // compute U = exp(B) with Pade approximants, and returns U.
559
560 DoubleMatrix2D B = A.copy();
561 final int n = B.rows();
562 Algebra alge = new Algebra();
563 final double mu = alge.trace(B) / n;
564 double x;
565
566 // B <-- B - mu*I
567 for (int i = 0; i < n; ++i) {
568 x = B.getQuick(i, i);
569 B.setQuick(i, i, x - mu);
570 }
571
572 final double THETA9 = 2.097847961257068; // in Higham
573 int s = getScale(B, THETA9);
574 final double v = 1.0 / Math.pow(2.0, s);
575 if (v <= 0)
576 throw new IllegalArgumentException(" v <= 0");
577 DMatrix.multBand(B, 1, v); // B <-- B/2^s
578
579 DoubleFactory2D fac = DoubleFactory2D.dense;
580 DoubleMatrix2D T = fac.make(n, n);
581 DoubleMatrix2D B4 = fac.make(n, n);
582 DMatrix.multBand(B, 1, B, 1, T); // B^2
583 DMatrix.multBand(T, 2, T, 2, B4); // B^4
584
585 DoubleMatrix2D W = B4.copy(); // W = work matrix
586 DMatrix.addMultBand(cPade[9], W, 4, cPade[7], T, 2); // W <-- W*cPade[9] + T*cPade[7]
587 DoubleMatrix2D U = fac.make(n, n);
588 DMatrix.multBand(W, 4, B4, 4, U); // U <-- B4*W
589
590 W = B4.copy();
591 DMatrix.addMultBand(cPade[5], W, 4, cPade[3], T, 2); // W <-- W*cPade[5] + T*cPade[3]
592 for (int i = 0; i < n; ++i) { // W <-- W + I*cPade[1]
593 x = W.getQuick(i, i);
594 W.setQuick(i, i, x + cPade[1]);
595 }
596 DMatrix.addMultBand(1.0, U, 8, 1.0, W, 4); // U <-- U + W
597 DMatrix.multBand(B, 1, U, 8, U); // U <-- B*U
598
599 W = B4.copy();
600 DMatrix.addMultBand(cPade[8], W, 4, cPade[6], T, 2); // W <-- W*cPade[8] + T*cPade[6]
601 DoubleMatrix2D V = B;
602 DMatrix.multBand(W, 4, B4, 4, V); // V <-- B4*W
603
604 W = B4.copy();
605 DMatrix.addMultBand(cPade[4], W, 4, cPade[2], T, 2); // W <-- W*cPade[4] + T*cPade[2]
606 for (int i = 0; i < n; ++i) { // W <-- W + I*cPade[0]
607 x = W.getQuick(i, i);
608 W.setQuick(i, i, x + cPade[0]);
609 }
610 DMatrix.addMultBand(1.0, V, 8, 1.0, W, 4); // V <-- V + W
611
612 W = V.copy();
613 DMatrix.addMultBand(1.0, W, 9, 1.0, U, 9); // W = V + U, Pade numerator
614 T = V.copy();
615 DMatrix.addMultBand(1.0, T, 9, -1.0, U, 9); // T = V - U, Pade denominator
616
617 // Compute Pade approximant B = W/T for exponential
618 DMatrix.solveTriangular(T, W, B);
619
620 // equivalent to B^(2^s) * e^mu
621 double r = mu * v;
622 r = Math.exp(r);
623 DMatrix.multBand(B, n - 1, r); // B <-- B*r
624
625 T.assign(0.);
626
627 for (int i = 0; i < s; i++) {
628 DMatrix.multBand(B, n - 1, B, n - 1, T);
629 B = T.copy();
630 }
631
632 return B;
633 }
634
646 public static DoubleMatrix1D expBidiagonal(final DoubleMatrix2D A, final DoubleMatrix1D b) {
647 // This is probably not efficient;
648 DoubleMatrix2D U = expBidiagonal(A); // U = exp(A)
649 Algebra alge = new Algebra();
650 return alge.mult(U, b);
651 }
652
663 public static DoubleMatrix2D expmiBidiagonal(final DoubleMatrix2D A) {
664 // Use the diagonal Pade approximant of order [7/7] for (exp(A) - I)/A:
665 // See Higham J.H., Functions of matrices, SIAM, 2008, p. 262.
666
667 DoubleMatrix2D B = A.copy();
668 final double THETA = 1.13; // theta_{7,1}
669 int s = getScale(B, THETA);
670 final double v = 1.0 / Math.pow(2.0, s);
671 if (v <= 0)
672 throw new IllegalArgumentException(" v <= 0");
673 DMatrix.multBand(B, 1, v); // B <-- B/2^s
674 DoubleMatrix2D U = m_expmiBidiag(B); // U = exp(B) - I
675
676 DoubleMatrix2D N = U.copy();
677 addIdentity(N); // N <-- exp(B)
678 DoubleMatrix2D V = N.copy(); // V <-- exp(B)
679
680 // Now undo scaling of B = A/2^s using
681 // (exp(A) - I) = (exp(B) - I)(exp(B) + I)(exp(B^2) + I) ... (exp(B^(2^(s-1))) +
682 // I)
683
684 Algebra alge = new Algebra();
685 for (int i = 1; i <= s; i++) {
686 addIdentity(N); // N <-- exp(B) + I
687 U = alge.mult(N, U); // U <-- N*U
688 if (i < s) {
689 V = alge.mult(V, V); // V <-- V*V
690 N = V.copy();
691 }
692 }
693
694 return U;
695 }
696
708 public static DoubleMatrix1D expmiBidiagonal(final DoubleMatrix2D A, final DoubleMatrix1D b) {
709 DoubleMatrix2D F = A.copy();
710 int s = getScale(F, 1.0 / 16.0);
711 final double v = 1.0 / Math.pow(2.0, s);
712 if (v <= 0)
713 throw new IllegalArgumentException(" v <= 0");
714 DMatrix.multBand(F, 1, v); // F <-- F/2^s
715
716 DoubleMatrix2D U = expBidiagonal(F); // U = exp(F)
717 DoubleMatrix2D N = U.copy();
718 DoubleMatrix1D C = m_taylor(F, b); // C = (exp(F) - I)b
719 DoubleMatrix1D D = C.copy();
720 Algebra alge = new Algebra();
721
722 // Now undo scaling of F = A/2^s using
723 // (exp(A) - I)b = (exp(F^(2^(s-1))) + I)...(exp(F^2) + I)(exp(F) + I)(exp(F) -
724 // I)b
725 for (int i = 1; i <= s; i++) {
726 addIdentity(N); // N <-- exp(F) + I
727 C = alge.mult(N, C); // C <-- N*C
728 if (i < s) {
729 U = alge.mult(U, U); // U <-- U*U
730 N = U.copy();
731 }
732 }
733
734 return C;
735 }
736
737 private static void addIdentity(DoubleMatrix2D A) {
738 // add identity matrix to matrix A: A <-- A + I
739 final int n = A.rows();
740 double x;
741 for (int i = 0; i < n; ++i) {
742 x = A.getQuick(i, i);
743 A.setQuick(i, i, x + 1.0);
744 }
745 }
746
747 private static void calcDiagm1(DoubleMatrix2D A, DoubleMatrix2D R) {
748 // calc diagonal of expm1 of triangular matrix A: exp(A) - I
749 final int n = A.rows();
750 double x, v;
751 for (int i = 0; i < n; ++i) {
752 x = A.getQuick(i, i);
753 v = Math.expm1(x); // exp(x) - 1
754 R.setQuick(i, i, v);
755 }
756 }
757
772 static void multBand(final DoubleMatrix2D A, int sa, final DoubleMatrix2D B, int sb, DoubleMatrix2D C) {
773 innerMultBand(A, sa, B, sb, C);
774 }
775
786 static void multBand(DoubleMatrix2D A, int sa, double h) {
787 final int n = A.rows();
788 double z;
789 for (int i = 0; i < n; ++i) {
790 int jmax = Math.min(i + sa, n - 1);
791 for (int j = i; j <= jmax; ++j) {
792 z = A.getQuick(i, j);
793 A.setQuick(i, j, z * h);
794 }
795 }
796 }
797
812 static void addMultBand(double g, DoubleMatrix2D A, int sa, double h, final DoubleMatrix2D B, int sb) {
813 DoubleMatrix2D S;
814 S = A.copy();
815 final int n = A.rows();
816 double z;
817 for (int i = 0; i < n; ++i) {
818 int jmax = Math.max(i + sa, i + sb);
819 jmax = Math.min(jmax, n - 1);
820 for (int j = i; j <= jmax; ++j) {
821 z = g * S.getQuick(i, j) + h * B.getQuick(i, j);
822 A.setQuick(i, j, z);
823 }
824 }
825 }
826
833 public static void copy(double[][] M, double[][] R) {
834 for (int i = 0; i < M.length; i++) {
835 for (int j = 0; j < M[i].length; j++) {
836 R[i][j] = M[i][j];
837 }
838 }
839 }
840
847 public static String toString(double[][] M) {
848 StringBuffer sb = new StringBuffer();
849
850 sb.append("{" + PrintfFormat.NEWLINE);
851 for (int i = 0; i < M.length; i++) {
852 sb.append(" { ");
853 for (int j = 0; j < M[i].length; j++) {
854 sb.append(M[i][j] + " ");
855 if (j < M.length - 1)
856 sb.append(" ");
857 }
858 sb.append("}" + PrintfFormat.NEWLINE);
859 }
860 sb.append("}");
861
862 return sb.toString();
863 }
864
871 public String toString() {
872 return toString(mat);
873 }
874
880 public int numRows() {
881 return r;
882 }
883
889 public int numColumns() {
890 return c;
891 }
892
903 public double get(int row, int column) {
904 if (row >= r || column >= c)
905 throw new IndexOutOfBoundsException();
906
907 return mat[row][column];
908 }
909
919 public void set(int row, int column, double value) {
920 if (row >= r || column >= c)
921 throw new IndexOutOfBoundsException();
922
923 mat[row][column] = value;
924 }
925
932 DMatrix result = new DMatrix(c, r);
933
934 for (int i = 0; i < r; i++)
935 for (int j = 0; j < c; j++)
936 result.mat[j][i] = mat[i][j];
937
938 return result;
939 }
940
941}
int numColumns()
Returns the number of columns of the DMatrix.
Definition DMatrix.java:889
static DoubleMatrix2D expmiBidiagonal(final DoubleMatrix2D A)
Computes , where is the exponential of the bidiagonal square matrix .
Definition DMatrix.java:663
String toString()
Creates a String containing all the data of the DMatrix.
Definition DMatrix.java:871
DMatrix(double[][] data, int r, int c)
Creates a new DMatrix with r rows and c columns using the data in data.
Definition DMatrix.java:282
DMatrix(DMatrix that)
Copy constructor.
Definition DMatrix.java:294
static DoubleMatrix2D CholeskyDecompose(DoubleMatrix2D M)
Given a symmetric positive-definite matrix , performs the Cholesky decomposition of and returns the ...
Definition DMatrix.java:328
static void addMultBand(double g, DoubleMatrix2D A, int sa, double h, final DoubleMatrix2D B, int sb)
Addition of the matrices after multiplication with the scalars and .
Definition DMatrix.java:812
static String toString(double[][] M)
Returns matrix as a string.
Definition DMatrix.java:847
int numRows()
Returns the number of rows of the DMatrix.
Definition DMatrix.java:880
static double[][] exp(double[][] A)
Similar to exp(final DoubleMatrix2D).
Definition DMatrix.java:436
static void solveTriangular(DoubleMatrix2D U, DoubleMatrix2D B, DoubleMatrix2D X)
Solve the triangular matrix equation for .
Definition DMatrix.java:414
static void copy(double[][] M, double[][] R)
Copies the matrix into .
Definition DMatrix.java:833
static DoubleMatrix2D PCADecompose(DoubleMatrix2D M, double[] lambda)
Computes the principal components decomposition =.
Definition DMatrix.java:367
DMatrix(int r, int c)
Creates a new DMatrix with r rows and c columns.
Definition DMatrix.java:268
DMatrix transpose()
Returns the transposed matrix.
Definition DMatrix.java:931
static DoubleMatrix1D expBidiagonal(final DoubleMatrix2D A, final DoubleMatrix1D b)
Computes , where is the exponential of the bidiagonal square matrix .
Definition DMatrix.java:646
static DoubleMatrix2D expBidiagonal(final DoubleMatrix2D A)
Returns , the exponential of the bidiagonal square matrix.
Definition DMatrix.java:554
static void CholeskyDecompose(double[][] M, double[][] L)
Given a symmetric positive-definite matrix , performs the Cholesky decomposition of and returns the ...
Definition DMatrix.java:306
static void multBand(DoubleMatrix2D A, int sa, double h)
Multiplication of the matrix by the scalar .
Definition DMatrix.java:786
static DoubleMatrix1D expmiBidiagonal(final DoubleMatrix2D A, final DoubleMatrix1D b)
Computes , where is the exponential of the bidiagonal square matrix .
Definition DMatrix.java:708
static DoubleMatrix2D exp(final DoubleMatrix2D A)
Returns , the exponential of the square matrix .
Definition DMatrix.java:450
static double[] solveLU(double[][] A, double[] b)
Solves the matrix equation using LU decomposition.
Definition DMatrix.java:396
static void multBand(final DoubleMatrix2D A, int sa, final DoubleMatrix2D B, int sb, DoubleMatrix2D C)
Matrix multiplication .
Definition DMatrix.java:772
static void PCADecompose(double[][] M, double[][] A, double[] lambda)
Computes the principal components decomposition =.
Definition DMatrix.java:345
This class provides various constants and methods to compute numerical quantities such as factorials,...
Definition Num.java:35
static double log2(double x)
Returns x .
Definition Num.java:405
This class acts like a StringBuffer which defines new types of append methods.
static final String NEWLINE
End-of-line symbol or line separator.