~ubuntu-branches/ubuntu/trusty/commons-math/trusty

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/commons/math/linear/SingularValueDecompositionImpl.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2010-04-05 23:33:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100405233302-gpqlceked76nw28a
Tags: 2.1-1
* New upstream release.
* Bump Standards-Version to 3.8.4: no changes needed
* Bump debhelper to >= 7
* Switch to 3.0 (quilt) source format:
  - Remove B-D on quilt
  - Add d/source/format
  - Remove d/README.source

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
package org.apache.commons.math.linear;
19
19
 
20
 
import org.apache.commons.math.ConvergenceException;
21
20
import org.apache.commons.math.MathRuntimeException;
22
 
import org.apache.commons.math.util.MathUtils;
23
21
 
24
22
/**
25
 
 * Calculates the Singular Value Decomposition of a matrix.
26
 
 * <p>The Singular Value Decomposition of matrix A is a set of three matrices:
27
 
 * U, &Sigma; and V such that A = U &times; &Sigma; &times; V<sup>T</sup>.
28
 
 * Let A be an m &times; n matrix, then U is an m &times; m orthogonal matrix,
29
 
 * &Sigma; is a m &times; n diagonal matrix with positive diagonal elements,
30
 
 * and V is an n &times; n orthogonal matrix.</p>
31
 
 *
32
 
 * @version $Revision: 799857 $ $Date: 2009-08-01 09:07:12 -0400 (Sat, 01 Aug 2009) $
 
23
 * Calculates the compact Singular Value Decomposition of a matrix.
 
24
 * <p>
 
25
 * The Singular Value Decomposition of matrix A is a set of three matrices: U,
 
26
 * &Sigma; and V such that A = U &times; &Sigma; &times; V<sup>T</sup>. Let A be
 
27
 * a m &times; n matrix, then U is a m &times; p orthogonal matrix, &Sigma; is a
 
28
 * p &times; p diagonal matrix with positive or null elements, V is a p &times;
 
29
 * n orthogonal matrix (hence V<sup>T</sup> is also orthogonal) where
 
30
 * p=min(m,n).
 
31
 * </p>
 
32
 * @version $Revision: 912413 $ $Date: 2010-02-21 16:46:12 -0500 (Sun, 21 Feb 2010) $
33
33
 * @since 2.0
34
34
 */
35
 
public class SingularValueDecompositionImpl implements SingularValueDecomposition {
 
35
public class SingularValueDecompositionImpl implements
 
36
        SingularValueDecomposition {
36
37
 
37
38
    /** Number of rows of the initial matrix. */
38
39
    private int m;
40
41
    /** Number of columns of the initial matrix. */
41
42
    private int n;
42
43
 
43
 
    /** Transformer to bidiagonal. */
44
 
    private BiDiagonalTransformer transformer;
45
 
 
46
 
    /** Main diagonal of the bidiagonal matrix. */
47
 
    private double[] mainBidiagonal;
48
 
 
49
 
    /** Secondary diagonal of the bidiagonal matrix. */
50
 
    private double[] secondaryBidiagonal;
51
 
 
52
 
    /** Main diagonal of the tridiagonal matrix. */
53
 
    private double[] mainTridiagonal;
54
 
 
55
 
    /** Secondary diagonal of the tridiagonal matrix. */
56
 
    private double[] secondaryTridiagonal;
57
 
 
58
44
    /** Eigen decomposition of the tridiagonal matrix. */
59
45
    private EigenDecomposition eigenDecomposition;
60
46
 
77
63
    private RealMatrix cachedVt;
78
64
 
79
65
    /**
80
 
     * Calculates the Singular Value Decomposition of the given matrix. 
81
 
     * @param matrix The matrix to decompose.
82
 
     * @exception InvalidMatrixException (wrapping a {@link ConvergenceException}
83
 
     * if algorithm fails to converge
 
66
     * Calculates the compact Singular Value Decomposition of the given matrix.
 
67
     * @param matrix
 
68
     *            The matrix to decompose.
 
69
     * @exception InvalidMatrixException
 
70
     *                (wrapping a
 
71
     *                {@link org.apache.commons.math.ConvergenceException} if
 
72
     *                algorithm fails to converge
84
73
     */
85
 
    public SingularValueDecompositionImpl(RealMatrix matrix)
86
 
        throws InvalidMatrixException {
 
74
    public SingularValueDecompositionImpl(final RealMatrix matrix)
 
75
            throws InvalidMatrixException {
87
76
 
88
77
        m = matrix.getRowDimension();
89
78
        n = matrix.getColumnDimension();
90
79
 
91
 
        cachedU  = null;
92
 
        cachedS  = null;
93
 
        cachedV  = null;
 
80
        cachedU = null;
 
81
        cachedS = null;
 
82
        cachedV = null;
94
83
        cachedVt = null;
95
84
 
96
 
        // transform the matrix to bidiagonal
97
 
        transformer         = new BiDiagonalTransformer(matrix);
98
 
        mainBidiagonal      = transformer.getMainDiagonalRef();
99
 
        secondaryBidiagonal = transformer.getSecondaryDiagonalRef();
100
 
 
101
 
        // compute Bt.B (if upper diagonal) or B.Bt (if lower diagonal)
102
 
        mainTridiagonal      = new double[mainBidiagonal.length];
103
 
        secondaryTridiagonal = new double[mainBidiagonal.length - 1];
104
 
        double a = mainBidiagonal[0];
105
 
        mainTridiagonal[0] = a * a;
106
 
        for (int i = 1; i < mainBidiagonal.length; ++i) {
107
 
            final double b  = secondaryBidiagonal[i - 1];
108
 
            secondaryTridiagonal[i - 1] = a * b;
109
 
            a = mainBidiagonal[i];
110
 
            mainTridiagonal[i] = a * a + b * b;
111
 
        }
112
 
 
113
 
        // compute singular values
114
 
        eigenDecomposition =
115
 
            new EigenDecompositionImpl(mainTridiagonal, secondaryTridiagonal,
116
 
                                       MathUtils.SAFE_MIN);
117
 
        singularValues = eigenDecomposition.getRealEigenvalues();
118
 
        for (int i = 0; i < singularValues.length; ++i) {
119
 
            singularValues[i] = Math.sqrt(singularValues[i]);
120
 
        }
121
 
 
 
85
        double[][] localcopy = matrix.getData();
 
86
        double[][] matATA = new double[n][n];
 
87
        //
 
88
        // create A^T*A
 
89
        //
 
90
        for (int i = 0; i < n; i++) {
 
91
            for (int j = i; j < n; j++) {
 
92
                matATA[i][j] = 0.0;
 
93
                for (int k = 0; k < m; k++) {
 
94
                    matATA[i][j] += localcopy[k][i] * localcopy[k][j];
 
95
                }
 
96
                matATA[j][i]=matATA[i][j];
 
97
            }
 
98
        }
 
99
 
 
100
        double[][] matAAT = new double[m][m];
 
101
        //
 
102
        // create A*A^T
 
103
        //
 
104
        for (int i = 0; i < m; i++) {
 
105
            for (int j = i; j < m; j++) {
 
106
                matAAT[i][j] = 0.0;
 
107
                for (int k = 0; k < n; k++) {
 
108
                    matAAT[i][j] += localcopy[i][k] * localcopy[j][k];
 
109
                }
 
110
                matAAT[j][i]=matAAT[i][j];
 
111
            }
 
112
        }
 
113
        int p;
 
114
        if (m>=n) {
 
115
            p=n;
 
116
            // compute eigen decomposition of A^T*A
 
117
            eigenDecomposition = new EigenDecompositionImpl(
 
118
                    new Array2DRowRealMatrix(matATA),1.0);
 
119
            singularValues = eigenDecomposition.getRealEigenvalues();
 
120
            cachedV = eigenDecomposition.getV();
 
121
 
 
122
            // compute eigen decomposition of A*A^T
 
123
            eigenDecomposition = new EigenDecompositionImpl(
 
124
                    new Array2DRowRealMatrix(matAAT),1.0);
 
125
            cachedU = eigenDecomposition.getV().getSubMatrix(0, m - 1, 0, p - 1);
 
126
        } else {
 
127
            p=m;
 
128
            // compute eigen decomposition of A*A^T
 
129
            eigenDecomposition = new EigenDecompositionImpl(
 
130
                    new Array2DRowRealMatrix(matAAT),1.0);
 
131
            singularValues = eigenDecomposition.getRealEigenvalues();
 
132
            cachedU = eigenDecomposition.getV();
 
133
 
 
134
            // compute eigen decomposition of A^T*A
 
135
            eigenDecomposition = new EigenDecompositionImpl(
 
136
                    new Array2DRowRealMatrix(matATA),1.0);
 
137
            cachedV = eigenDecomposition.getV().getSubMatrix(0,n-1,0,p-1);
 
138
        }
 
139
        for (int i = 0; i < p; i++) {
 
140
            singularValues[i] = Math.sqrt(Math.abs(singularValues[i]));
 
141
        }
 
142
        // Up to this point, U and V are computed independently of each other.
 
143
        // There still an sign indetermination of each column of, say, U.
 
144
        // The sign is set such that A.V_i=sigma_i.U_i (i<=p)
 
145
        // The right sign corresponds to a positive dot product of A.V_i and U_i
 
146
        for (int i = 0; i < p; i++) {
 
147
          RealVector tmp = cachedU.getColumnVector(i);
 
148
          double product=matrix.operate(cachedV.getColumnVector(i)).dotProduct(tmp);
 
149
          if (product<0) {
 
150
            cachedU.setColumnVector(i, tmp.mapMultiply(-1.0));
 
151
          }
 
152
        }
122
153
    }
123
154
 
124
155
    /** {@inheritDoc} */
125
 
    public RealMatrix getU()
126
 
        throws InvalidMatrixException {
127
 
 
128
 
        if (cachedU == null) {
129
 
 
130
 
            if (m >= n) {
131
 
                // the tridiagonal matrix is Bt.B, where B is upper bidiagonal
132
 
                final double[][] eData = eigenDecomposition.getV().getData();
133
 
                final double[][] iData = new double[m][];
134
 
                double[] ei1 = eData[0];
135
 
                iData[0] = ei1;
136
 
                for (int i = 0; i < n - 1; ++i) {
137
 
                    // compute Bt.E.S^(-1) where E is the eigenvectors matrix
138
 
                    // we reuse the array from matrix E to store the result 
139
 
                    final double[] ei0 = ei1;
140
 
                    ei1 = eData[i + 1];
141
 
                    iData[i + 1] = ei1;
142
 
                    for (int j = 0; j < n; ++j) {
143
 
                        ei0[j] = (mainBidiagonal[i] * ei0[j] +
144
 
                                  secondaryBidiagonal[i] * ei1[j]) / singularValues[j];
145
 
                    }
146
 
                }
147
 
                // last row
148
 
                final double lastMain = mainBidiagonal[n - 1];
149
 
                for (int j = 0; j < n; ++j) {
150
 
                    ei1[j] *= lastMain / singularValues[j];
151
 
                }
152
 
                for (int i = n; i < m; ++i) {
153
 
                    iData[i] = new double[n];
154
 
                }
155
 
                cachedU =
156
 
                    transformer.getU().multiply(MatrixUtils.createRealMatrix(iData));
157
 
            } else {
158
 
                // the tridiagonal matrix is B.Bt, where B is lower bidiagonal
159
 
                cachedU = transformer.getU().multiply(eigenDecomposition.getV());
160
 
            }
161
 
 
162
 
        }
163
 
 
 
156
    public RealMatrix getU() throws InvalidMatrixException {
164
157
        // return the cached matrix
165
158
        return cachedU;
166
159
 
167
160
    }
168
161
 
169
162
    /** {@inheritDoc} */
170
 
    public RealMatrix getUT()
171
 
        throws InvalidMatrixException {
 
163
    public RealMatrix getUT() throws InvalidMatrixException {
172
164
 
173
165
        if (cachedUt == null) {
174
166
            cachedUt = getU().transpose();
180
172
    }
181
173
 
182
174
    /** {@inheritDoc} */
183
 
    public RealMatrix getS()
184
 
        throws InvalidMatrixException {
 
175
    public RealMatrix getS() throws InvalidMatrixException {
185
176
 
186
177
        if (cachedS == null) {
187
178
 
193
184
    }
194
185
 
195
186
    /** {@inheritDoc} */
196
 
    public double[] getSingularValues()
197
 
        throws InvalidMatrixException {
 
187
    public double[] getSingularValues() throws InvalidMatrixException {
198
188
        return singularValues.clone();
199
189
    }
200
190
 
201
191
    /** {@inheritDoc} */
202
 
    public RealMatrix getV()
203
 
        throws InvalidMatrixException {
204
 
 
205
 
        if (cachedV == null) {
206
 
 
207
 
            if (m >= n) {
208
 
                // the tridiagonal matrix is Bt.B, where B is upper bidiagonal
209
 
                cachedV = transformer.getV().multiply(eigenDecomposition.getV());
210
 
            } else {
211
 
                // the tridiagonal matrix is B.Bt, where B is lower bidiagonal
212
 
                final double[][] eData = eigenDecomposition.getV().getData();
213
 
                final double[][] iData = new double[n][];
214
 
                double[] ei1 = eData[0];
215
 
                iData[0] = ei1;
216
 
                for (int i = 0; i < m - 1; ++i) {
217
 
                    // compute Bt.E.S^(-1) where E is the eigenvectors matrix
218
 
                    // we reuse the array from matrix E to store the result 
219
 
                    final double[] ei0 = ei1;
220
 
                    ei1 = eData[i + 1];
221
 
                    iData[i + 1] = ei1;
222
 
                    for (int j = 0; j < m; ++j) {
223
 
                        ei0[j] = (mainBidiagonal[i] * ei0[j] +
224
 
                                  secondaryBidiagonal[i] * ei1[j]) / singularValues[j];
225
 
                    }
226
 
                }
227
 
                // last row
228
 
                final double lastMain = mainBidiagonal[m - 1];
229
 
                for (int j = 0; j < m; ++j) {
230
 
                    ei1[j] *= lastMain / singularValues[j];
231
 
                }
232
 
                for (int i = m; i < n; ++i) {
233
 
                    iData[i] = new double[m];
234
 
                }
235
 
                cachedV =
236
 
                    transformer.getV().multiply(MatrixUtils.createRealMatrix(iData));
237
 
            }
238
 
 
239
 
        }
240
 
 
 
192
    public RealMatrix getV() throws InvalidMatrixException {
241
193
        // return the cached matrix
242
194
        return cachedV;
243
195
 
244
196
    }
245
197
 
246
198
    /** {@inheritDoc} */
247
 
    public RealMatrix getVT()
248
 
        throws InvalidMatrixException {
 
199
    public RealMatrix getVT() throws InvalidMatrixException {
249
200
 
250
201
        if (cachedVt == null) {
251
202
            cachedVt = getV().transpose();
260
211
    public RealMatrix getCovariance(final double minSingularValue) {
261
212
 
262
213
        // get the number of singular values to consider
 
214
        final int p = singularValues.length;
263
215
        int dimension = 0;
264
 
        while ((dimension < n) && (singularValues[dimension] >= minSingularValue)) {
 
216
        while ((dimension < p) && (singularValues[dimension] >= minSingularValue)) {
265
217
            ++dimension;
266
218
        }
267
219
 
268
220
        if (dimension == 0) {
269
221
            throw MathRuntimeException.createIllegalArgumentException(
270
 
                  "cutoff singular value is {0}, should be at most {1}",
271
 
                  minSingularValue, singularValues[0]);
 
222
                    "cutoff singular value is {0}, should be at most {1}",
 
223
                    minSingularValue, singularValues[0]);
272
224
        }
273
225
 
274
 
        final double[][] data = new double[dimension][n];
 
226
        final double[][] data = new double[dimension][p];
275
227
        getVT().walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
276
228
            /** {@inheritDoc} */
277
229
            @Override
278
 
            public void visit(final int row, final int column, final double value) {
 
230
            public void visit(final int row, final int column,
 
231
                    final double value) {
279
232
                data[row][column] = value / singularValues[row];
280
233
            }
281
 
        }, 0, dimension - 1, 0, n - 1);
 
234
        }, 0, dimension - 1, 0, p - 1);
282
235
 
283
236
        RealMatrix jv = new Array2DRowRealMatrix(data, false);
284
237
        return jv.transpose().multiply(jv);
286
239
    }
287
240
 
288
241
    /** {@inheritDoc} */
289
 
    public double getNorm()
290
 
        throws InvalidMatrixException {
 
242
    public double getNorm() throws InvalidMatrixException {
291
243
        return singularValues[0];
292
244
    }
293
245
 
294
246
    /** {@inheritDoc} */
295
 
    public double getConditionNumber()
296
 
        throws InvalidMatrixException {
 
247
    public double getConditionNumber() throws InvalidMatrixException {
297
248
        return singularValues[0] / singularValues[singularValues.length - 1];
298
249
    }
299
250
 
300
251
    /** {@inheritDoc} */
301
 
    public int getRank()
302
 
        throws IllegalStateException {
 
252
    public int getRank() throws IllegalStateException {
303
253
 
304
254
        final double threshold = Math.max(m, n) * Math.ulp(singularValues[0]);
305
255
 
306
256
        for (int i = singularValues.length - 1; i >= 0; --i) {
307
 
           if (singularValues[i] > threshold) {
308
 
              return i + 1;
309
 
           }
 
257
            if (singularValues[i] > threshold) {
 
258
                return i + 1;
 
259
            }
310
260
        }
311
261
        return 0;
312
262
 
314
264
 
315
265
    /** {@inheritDoc} */
316
266
    public DecompositionSolver getSolver() {
317
 
        return new Solver(singularValues, getUT(), getV(),
318
 
                          getRank() == singularValues.length);
 
267
        return new Solver(singularValues, getUT(), getV(), getRank() == Math
 
268
                .max(m, n));
319
269
    }
320
270
 
321
271
    /** Specialized solver. */
322
272
    private static class Solver implements DecompositionSolver {
323
 
        
324
 
        /** Singular values. */
325
 
        private final double[] singularValues;
326
 
 
327
 
        /** U<sup>T</sup> matrix of the decomposition. */
328
 
        private final RealMatrix uT;
329
 
 
330
 
        /** V matrix of the decomposition. */
331
 
        private final RealMatrix v;
 
273
 
 
274
        /** Pseudo-inverse of the initial matrix. */
 
275
        private final RealMatrix pseudoInverse;
332
276
 
333
277
        /** Singularity indicator. */
334
278
        private boolean nonSingular;
335
279
 
336
280
        /**
337
281
         * Build a solver from decomposed matrix.
338
 
         * @param singularValues singularValues
339
 
         * @param uT U<sup>T</sup> matrix of the decomposition
340
 
         * @param v V matrix of the decomposition
341
 
         * @param nonSingular singularity indicator
342
 
         */
343
 
        private Solver(final double[] singularValues, final RealMatrix uT, final RealMatrix v,
344
 
                       final boolean nonSingular) {
345
 
            this.singularValues = singularValues;
346
 
            this.uT             = uT;
347
 
            this.v              = v;
348
 
            this.nonSingular    = nonSingular;
349
 
        }
350
 
 
351
 
        /** Solve the linear equation A &times; X = B in least square sense.
352
 
         * <p>The m&times;n matrix A may not be square, the solution X is
353
 
         * such that ||A &times; X - B|| is minimal.</p>
354
 
         * @param b right-hand side of the equation A &times; X = B
355
 
         * @return a vector X that minimizes the two norm of A &times; X - B
356
 
         * @exception IllegalArgumentException if matrices dimensions don't match
357
 
         * @exception InvalidMatrixException if decomposed matrix is singular
358
 
         */
359
 
        public double[] solve(final double[] b)
360
 
            throws IllegalArgumentException, InvalidMatrixException {
361
 
 
362
 
            if (b.length != singularValues.length) {
363
 
                throw MathRuntimeException.createIllegalArgumentException(
364
 
                        "vector length mismatch: got {0} but expected {1}",
365
 
                        b.length, singularValues.length);
366
 
            }
367
 
 
368
 
            final double[] w = uT.operate(b);
 
282
         * @param singularValues
 
283
         *            singularValues
 
284
         * @param uT
 
285
         *            U<sup>T</sup> matrix of the decomposition
 
286
         * @param v
 
287
         *            V matrix of the decomposition
 
288
         * @param nonSingular
 
289
         *            singularity indicator
 
290
         */
 
291
        private Solver(final double[] singularValues, final RealMatrix uT,
 
292
                final RealMatrix v, final boolean nonSingular) {
 
293
            double[][] suT = uT.getData();
369
294
            for (int i = 0; i < singularValues.length; ++i) {
370
 
                final double si = singularValues[i];
371
 
                if (si == 0) {
372
 
                    throw new SingularMatrixException();
373
 
                }
374
 
                w[i] /= si;
 
295
                final double a;
 
296
                if (singularValues[i]>0) {
 
297
                 a=1.0 / singularValues[i];
 
298
                } else {
 
299
                 a=0.0;
 
300
                }
 
301
                final double[] suTi = suT[i];
 
302
                for (int j = 0; j < suTi.length; ++j) {
 
303
                    suTi[j] *= a;
 
304
                }
375
305
            }
376
 
            return v.operate(w);
377
 
 
378
 
        }
379
 
 
380
 
        /** Solve the linear equation A &times; X = B in least square sense.
381
 
         * <p>The m&times;n matrix A may not be square, the solution X is
382
 
         * such that ||A &times; X - B|| is minimal.</p>
383
 
         * @param b right-hand side of the equation A &times; X = B
384
 
         * @return a vector X that minimizes the two norm of A &times; X - B
385
 
         * @exception IllegalArgumentException if matrices dimensions don't match
386
 
         * @exception InvalidMatrixException if decomposed matrix is singular
 
306
            pseudoInverse = v.multiply(new Array2DRowRealMatrix(suT, false));
 
307
            this.nonSingular = nonSingular;
 
308
        }
 
309
 
 
310
        /**
 
311
         * Solve the linear equation A &times; X = B in least square sense.
 
312
         * <p>
 
313
         * The m&times;n matrix A may not be square, the solution X is such that
 
314
         * ||A &times; X - B|| is minimal.
 
315
         * </p>
 
316
         * @param b
 
317
         *            right-hand side of the equation A &times; X = B
 
318
         * @return a vector X that minimizes the two norm of A &times; X - B
 
319
         * @exception IllegalArgumentException
 
320
         *                if matrices dimensions don't match
 
321
         */
 
322
        public double[] solve(final double[] b) throws IllegalArgumentException {
 
323
            return pseudoInverse.operate(b);
 
324
        }
 
325
 
 
326
        /**
 
327
         * Solve the linear equation A &times; X = B in least square sense.
 
328
         * <p>
 
329
         * The m&times;n matrix A may not be square, the solution X is such that
 
330
         * ||A &times; X - B|| is minimal.
 
331
         * </p>
 
332
         * @param b
 
333
         *            right-hand side of the equation A &times; X = B
 
334
         * @return a vector X that minimizes the two norm of A &times; X - B
 
335
         * @exception IllegalArgumentException
 
336
         *                if matrices dimensions don't match
387
337
         */
388
338
        public RealVector solve(final RealVector b)
389
 
            throws IllegalArgumentException, InvalidMatrixException {
390
 
 
391
 
            if (b.getDimension() != singularValues.length) {
392
 
                throw MathRuntimeException.createIllegalArgumentException(
393
 
                        "vector length mismatch: got {0} but expected {1}",
394
 
                         b.getDimension(), singularValues.length);
395
 
            }
396
 
 
397
 
            final RealVector w = uT.operate(b);
398
 
            for (int i = 0; i < singularValues.length; ++i) {
399
 
                final double si = singularValues[i];
400
 
                if (si == 0) {
401
 
                    throw new SingularMatrixException();
402
 
                }
403
 
                w.setEntry(i, w.getEntry(i) / si);
404
 
            }
405
 
            return v.operate(w);
406
 
 
 
339
                throws IllegalArgumentException {
 
340
            return pseudoInverse.operate(b);
407
341
        }
408
342
 
409
 
        /** Solve the linear equation A &times; X = B in least square sense.
410
 
         * <p>The m&times;n matrix A may not be square, the solution X is
411
 
         * such that ||A &times; X - B|| is minimal.</p>
412
 
         * @param b right-hand side of the equation A &times; X = B
 
343
        /**
 
344
         * Solve the linear equation A &times; X = B in least square sense.
 
345
         * <p>
 
346
         * The m&times;n matrix A may not be square, the solution X is such that
 
347
         * ||A &times; X - B|| is minimal.
 
348
         * </p>
 
349
         * @param b
 
350
         *            right-hand side of the equation A &times; X = B
413
351
         * @return a matrix X that minimizes the two norm of A &times; X - B
414
 
         * @exception IllegalArgumentException if matrices dimensions don't match
415
 
         * @exception InvalidMatrixException if decomposed matrix is singular
 
352
         * @exception IllegalArgumentException
 
353
         *                if matrices dimensions don't match
416
354
         */
417
355
        public RealMatrix solve(final RealMatrix b)
418
 
            throws IllegalArgumentException, InvalidMatrixException {
419
 
 
420
 
            if (b.getRowDimension() != singularValues.length) {
421
 
                throw MathRuntimeException.createIllegalArgumentException(
422
 
                        "dimensions mismatch: got {0}x{1} but expected {2}x{3}",
423
 
                        b.getRowDimension(), b.getColumnDimension(),
424
 
                        singularValues.length, "n");
425
 
            }
426
 
 
427
 
            final RealMatrix w = uT.multiply(b);
428
 
            for (int i = 0; i < singularValues.length; ++i) {
429
 
                final double si  = singularValues[i];
430
 
                if (si == 0) {
431
 
                    throw new SingularMatrixException();
432
 
                }
433
 
                final double inv = 1.0 / si;
434
 
                for (int j = 0; j < b.getColumnDimension(); ++j) {
435
 
                    w.multiplyEntry(i, j, inv);
436
 
                }
437
 
            }
438
 
            return v.multiply(w);
439
 
 
 
356
                throws IllegalArgumentException {
 
357
            return pseudoInverse.multiply(b);
440
358
        }
441
359
 
442
360
        /**
447
365
            return nonSingular;
448
366
        }
449
367
 
450
 
        /** Get the pseudo-inverse of the decomposed matrix.
 
368
        /**
 
369
         * Get the pseudo-inverse of the decomposed matrix.
451
370
         * @return inverse matrix
452
 
         * @throws InvalidMatrixException if decomposed matrix is singular
453
371
         */
454
 
        public RealMatrix getInverse()
455
 
            throws InvalidMatrixException {
456
 
 
457
 
            if (!isNonSingular()) {
458
 
                throw new SingularMatrixException();
459
 
            }
460
 
 
461
 
            return solve(MatrixUtils.createRealIdentityMatrix(singularValues.length));
462
 
 
 
372
        public RealMatrix getInverse() {
 
373
            return pseudoInverse;
463
374
        }
464
375
 
465
376
    }