/** {@inheritDoc} */ public RealMatrix getV() throws InvalidMatrixException { if (cachedV == null) { if (m >= n) { // the tridiagonal matrix is Bt.B, where B is upper bidiagonal cachedV = transformer.getV().multiply(eigenDecomposition.getV()); } else { // the tridiagonal matrix is B.Bt, where B is lower bidiagonal final double[][] eData = eigenDecomposition.getV().getData(); final double[][] iData = new double[n][]; double[] ei1 = eData[0]; iData[0] = ei1; for (int i = 0; i < m - 1; ++i) { // compute Bt.E.S^(-1) where E is the eigenvectors matrix // we reuse the array from matrix E to store the result final double mi = mainBidiagonal[i]; final double si = secondaryBidiagonal[i]; final double[] ei0 = ei1; ei1 = eData[i + 1]; iData[i + 1] = ei1; for (int j = 0; j < m; ++j) { ei0[j] = (mi * ei0[j] + si * ei1[j]) / singularValues[j]; } } // last row final double lastMain = mainBidiagonal[m - 1]; for (int j = 0; j < m; ++j) { ei1[j] *= lastMain / singularValues[j]; } for (int i = m; i < n; ++i) { iData[i] = new double[m]; } cachedV = transformer.getV().multiply(MatrixUtils.createRealMatrix(iData)); } } // return the cached matrix return cachedV; }
/** * Calculates the Singular Value Decomposition of the given matrix. * * @param matrix The matrix to decompose. * @exception InvalidMatrixException (wrapping a {@link * org.apache.commons.math.ConvergenceException} if algorithm fails to converge */ public SingularValueDecompositionImpl(RealMatrix matrix) throws InvalidMatrixException { m = matrix.getRowDimension(); n = matrix.getColumnDimension(); cachedU = null; cachedS = null; cachedV = null; cachedVt = null; // transform the matrix to bidiagonal transformer = new BiDiagonalTransformer(matrix); mainBidiagonal = transformer.getMainDiagonalRef(); secondaryBidiagonal = transformer.getSecondaryDiagonalRef(); // compute Bt.B (if upper diagonal) or B.Bt (if lower diagonal) mainTridiagonal = new double[mainBidiagonal.length]; secondaryTridiagonal = new double[mainBidiagonal.length - 1]; double a = mainBidiagonal[0]; mainTridiagonal[0] = a * a; for (int i = 1; i < mainBidiagonal.length; ++i) { final double b = secondaryBidiagonal[i - 1]; secondaryTridiagonal[i - 1] = a * b; a = mainBidiagonal[i]; mainTridiagonal[i] = a * a + b * b; } // compute singular values eigenDecomposition = new EigenDecompositionImpl(mainTridiagonal, secondaryTridiagonal, MathUtils.SAFE_MIN); singularValues = eigenDecomposition.getRealEigenvalues(); for (int i = 0; i < singularValues.length; ++i) { final double si = singularValues[i]; singularValues[i] = (si < 0) ? 0.0 : Math.sqrt(si); } }