/** {@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; }