Example #1
0
        /// <summary>
        /// Returns the bi-diagonal matrix B of the transform.
        /// </summary>
        /// <returns>the B matrix</returns>
        public RealMatrix getB()
        {
            if (cachedB == null)
            {
                int        m  = householderVectors.Length;
                int        n  = householderVectors[0].Length;
                double[][] ba = new double[m][];
                for (int i = 0; i < main.Length; ++i)
                {
                    ba[i][i] = main[i];
                    if (m < n)
                    {
                        if (i > 0)
                        {
                            ba[i][i - 1] = secondary[i - 1];
                        }
                    }
                    else
                    {
                        if (i < main.Length - 1)
                        {
                            ba[i][i + 1] = secondary[i];
                        }
                    }
                }
                cachedB = MatrixUtils.createRealMatrix(ba);
            }

            // return the cached matrix
            return(cachedB);
        }
 /// <inheritdoc/>
 public new RealMatrix outerProduct(RealVector v)
 {
     if (v is ArrayRealVector)
     {
         double[]   vData = ((ArrayRealVector)v).data;
         int        m     = data.Length;
         int        n     = vData.Length;
         RealMatrix outp  = MatrixUtils.createRealMatrix(m, n);
         for (int i = 0; i < m; i++)
         {
             for (int j = 0; j < n; j++)
             {
                 outp.setEntry(i, j, data[i] * vData[j]);
             }
         }
         return(outp);
     }
     else
     {
         int        m    = data.Length;
         int        n    = v.getDimension();
         RealMatrix outp = MatrixUtils.createRealMatrix(m, n);
         for (int i = 0; i < m; i++)
         {
             for (int j = 0; j < n; j++)
             {
                 outp.setEntry(i, j, data[i] * v.getEntry(j));
             }
         }
         return(outp);
     }
 }
        /// <summary>
        /// Returns the Hessenberg matrix H of the transform.
        /// </summary>
        /// <returns>the H matrix</returns>
        public RealMatrix getH()
        {
            if (cachedH == null)
            {
                int        m = householderVectors.Length;
                double[][] h = new double[m][];
                for (int i = 0; i < m; ++i)
                {
                    if (i > 0)
                    {
                        // copy the entry of the lower sub-diagonal
                        h[i][i - 1] = householderVectors[i][i - 1];
                    }

                    // copy upper triangular part of the matrix
                    for (int j = i; j < m; ++j)
                    {
                        h[i][j] = householderVectors[i][j];
                    }
                }
                cachedH = MatrixUtils.createRealMatrix(h);
            }

            // return the cached matrix
            return(cachedH);
        }
            /// <summary>
            /// Get the inverse of the decomposed matrix.
            /// </summary>
            /// <returns>the inverse matrix.</returns>
            /// <exception cref="SingularMatrixException"> if the decomposed matrix is singular.
            /// </exception>
            public RealMatrix getInverse()
            {
                if (!isNonSingular())
                {
                    throw new SingularMatrixException();
                }

                int m = realEigenvalues.Length;

                double[][] invData = new double[m][];

                for (int i = 0; i < m; ++i)
                {
                    double[] invI = invData[i];
                    for (int j = 0; j < m; ++j)
                    {
                        double invIJ = 0;
                        for (int k = 0; k < m; ++k)
                        {
                            double[] vK = eigenvectors[k].getDataRef();
                            invIJ += vK[i] * vK[j] / realEigenvalues[k];
                        }
                        invI[j] = invIJ;
                    }
                }
                return(MatrixUtils.createRealMatrix(invData));
            }
Example #5
0
 /// <summary>
 /// Returns the matrix P of the transform.
 /// <para>P is an orthogonal matrix, i.e. its inverse is also its transpose.</para>
 /// </summary>
 /// <returns>the P matrix</returns>
 public RealMatrix getP()
 {
     if (cachedP == null)
     {
         cachedP = MatrixUtils.createRealMatrix(matrixP);
     }
     return(cachedP);
 }
Example #6
0
        /// <summary>
        /// Returns the transpose of the matrix L of the decomposition.
        /// <para>L^T is an upper-triangular matrix</para>
        /// </summary>
        /// <returns>the transpose of the matrix L of the decomposition</returns>
        public RealMatrix getLT()
        {
            if (cachedLT == null)
            {
                cachedLT = MatrixUtils.createRealMatrix(lTData);
            }

            // return the cached matrix
            return(cachedLT);
        }
Example #7
0
        /// <summary>
        /// Returns the quasi-triangular Schur matrix T of the transform.
        /// </summary>
        /// <returns>the T matrix</returns>
        public RealMatrix getT()
        {
            if (cachedT == null)
            {
                cachedT = MatrixUtils.createRealMatrix(matrixT);
            }

            // return the cached matrix
            return(cachedT);
        }
 /// <summary>
 /// Gets the matrix V of the decomposition.
 /// V is an orthogonal matrix, i.e. its transpose is also its inverse.
 /// The columns of V are the eigenvectors of the original matrix.
 /// No assumption is made about the orientation of the system axes formed
 /// by the columns of V (e.g. in a 3-dimension space, V can form a left-
 /// or right-handed system).
 /// </summary>
 /// <returns>the V matrix.</returns>
 public RealMatrix getV()
 {
     if (cachedV == null)
     {
         int m = eigenvectors.Length;
         cachedV = MatrixUtils.createRealMatrix(m, m);
         for (int k = 0; k < m; ++k)
         {
             cachedV.setColumnVector(k, eigenvectors[k]);
         }
     }
     // return the cached matrix
     return(cachedV);
 }
Example #9
0
        /// <summary>
        /// Returns the matrix U of the transform.
        /// <para>U is an orthogonal matrix, i.e. its transpose is also its inverse.</para>
        /// </summary>
        /// <returns>the U matrix</returns>
        public RealMatrix getU()
        {
            if (cachedU == null)
            {
                int        m          = householderVectors.Length;
                int        n          = householderVectors[0].Length;
                int        p          = main.Length;
                int        diagOffset = (m >= n) ? 0 : 1;
                double[]   diagonal   = (m >= n) ? main : secondary;
                double[][] ua         = new double[m][];

                // fill up the part of the matrix not affected by Householder transforms
                for (int k = m - 1; k >= p; --k)
                {
                    ua[k][k] = 1;
                }

                // build up first part of the matrix by applying Householder transforms
                for (int k = p - 1; k >= diagOffset; --k)
                {
                    double[] hK = householderVectors[k];
                    ua[k][k] = 1;
                    if (hK[k - diagOffset] != 0.0)
                    {
                        for (int j = k; j < m; ++j)
                        {
                            double alpha = 0;
                            for (int i = k; i < m; ++i)
                            {
                                alpha -= ua[i][j] * householderVectors[i][k - diagOffset];
                            }
                            alpha /= diagonal[k - diagOffset] * hK[k - diagOffset];

                            for (int i = k; i < m; ++i)
                            {
                                ua[i][j] += -alpha * householderVectors[i][k - diagOffset];
                            }
                        }
                    }
                }
                if (diagOffset > 0)
                {
                    ua[0][0] = 1;
                }
                cachedU = MatrixUtils.createRealMatrix(ua);
            }

            // return the cached matrix
            return(cachedU);
        }
Example #10
0
        /// <summary>
        /// Returns the matrix V of the transform.
        /// <para>V is an orthogonal matrix, i.e. its transpose is also its inverse.</para>
        /// </summary>
        /// <returns>the V matrix</returns>
        public RealMatrix getV()
        {
            if (cachedV == null)
            {
                int        m          = householderVectors.Length;
                int        n          = householderVectors[0].Length;
                int        p          = main.Length;
                int        diagOffset = (m >= n) ? 1 : 0;
                double[]   diagonal   = (m >= n) ? secondary : main;
                double[][] va         = new double[n][];

                // fill up the part of the matrix not affected by Householder transforms
                for (int k = n - 1; k >= p; --k)
                {
                    va[k][k] = 1;
                }

                // build up first part of the matrix by applying Householder transforms
                for (int k = p - 1; k >= diagOffset; --k)
                {
                    double[] hK = householderVectors[k - diagOffset];
                    va[k][k] = 1;
                    if (hK[k] != 0.0)
                    {
                        for (int j = k; j < n; ++j)
                        {
                            double beta = 0;
                            for (int i = k; i < n; ++i)
                            {
                                beta -= va[i][j] * hK[i];
                            }
                            beta /= diagonal[k - diagOffset] * hK[k];

                            for (int i = k; i < n; ++i)
                            {
                                va[i][j] += -beta * hK[i];
                            }
                        }
                    }
                }
                if (diagOffset > 0)
                {
                    va[0][0] = 1;
                }
                cachedV = MatrixUtils.createRealMatrix(va);
            }

            // return the cached matrix
            return(cachedV);
        }
        /// <summary>
        /// Returns the matrix P of the transform.
        /// <para>P is an orthogonal matrix, i.e. its inverse is also its transpose.</para>
        /// </summary>
        /// <returns>the P matrix</returns>
        public RealMatrix getP()
        {
            if (cachedP == null)
            {
                int        n    = householderVectors.Length;
                int        high = n - 1;
                double[][] pa   = new double[n][];

                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        pa[i][j] = (i == j) ? 1 : 0;
                    }
                }

                for (int m = high - 1; m >= 1; m--)
                {
                    if (householderVectors[m][m - 1] != 0.0)
                    {
                        for (int i = m + 1; i <= high; i++)
                        {
                            ort[i] = householderVectors[i][m - 1];
                        }

                        for (int j = m; j <= high; j++)
                        {
                            double g = 0.0;

                            for (int i = m; i <= high; i++)
                            {
                                g += ort[i] * pa[i][j];
                            }

                            // Double division avoids possible underflow
                            g = (g / ort[m]) / householderVectors[m][m - 1];

                            for (int i = m; i <= high; i++)
                            {
                                pa[i][j] += g * ort[i];
                            }
                        }
                    }
                }

                cachedP = MatrixUtils.createRealMatrix(pa);
            }
            return(cachedP);
        }
Example #12
0
        /// <summary>
        /// Returns the transpose of the matrix Q of the decomposition.
        /// <para>Q is an orthogonal matrix</para>
        /// </summary>
        /// <returns>the transpose of the Q matrix, Q^T</returns>
        public RealMatrix getQT()
        {
            if (cachedQT == null)
            {
                // QT is supposed to be m x m
                int        n   = qrt.Length;
                int        m   = qrt[0].Length;
                double[][] qta = new double[m][];

                /*
                 * Q = Q1 Q2 ... Q_m, so Q is formed by first constructing Q_m and then
                 * applying the Householder transformations Q_(m-1),Q_(m-2),...,Q1 in
                 * succession to the result
                 */
                for (int minor = m - 1; minor >= FastMath.min(m, n); minor--)
                {
                    qta[minor][minor] = 1.0d;
                }

                for (int minor = FastMath.min(m, n) - 1; minor >= 0; minor--)
                {
                    double[] qrtMinor = qrt[minor];
                    qta[minor][minor] = 1.0d;
                    if (qrtMinor[minor] != 0.0)
                    {
                        for (int col = minor; col < m; col++)
                        {
                            double alpha = 0;
                            for (int row = minor; row < m; row++)
                            {
                                alpha -= qta[col][row] * qrtMinor[row];
                            }
                            alpha /= rDiag[minor] * qrtMinor[minor];

                            for (int row = minor; row < m; row++)
                            {
                                qta[col][row] += -alpha * qrtMinor[row];
                            }
                        }
                    }
                }
                cachedQT = MatrixUtils.createRealMatrix(qta);
            }

            // return the cached matrix
            return(cachedQT);
        }
Example #13
0
        /// <summary>
        /// Returns the transpose of the matrix Q of the transform.
        /// <para>Q is an orthogonal matrix, i.e. its transpose is also its inverse.</para>
        /// </summary>
        /// <returns>the Q matrix</returns>
        public RealMatrix getQT()
        {
            if (cachedQt == null)
            {
                int        m   = householderVectors.Length;
                double[][] qta = new double[m][];

                // build up first part of the matrix by applying Householder transforms
                for (int k = m - 1; k >= 1; --k)
                {
                    double[] hK = householderVectors[k - 1];
                    qta[k][k] = 1;
                    if (hK[k] != 0.0)
                    {
                        double inv  = 1.0 / (secondary[k - 1] * hK[k]);
                        double beta = 1.0 / secondary[k - 1];
                        qta[k][k] = 1 + beta * hK[k];
                        for (int i = k + 1; i < m; ++i)
                        {
                            qta[k][i] = beta * hK[i];
                        }
                        for (int j = k + 1; j < m; ++j)
                        {
                            beta = 0;
                            for (int i = k + 1; i < m; ++i)
                            {
                                beta += qta[j][i] * hK[i];
                            }
                            beta     *= inv;
                            qta[j][k] = beta * hK[k];
                            for (int i = k + 1; i < m; ++i)
                            {
                                qta[j][i] += beta * hK[i];
                            }
                        }
                    }
                }
                qta[0][0] = 1;
                cachedQt  = MatrixUtils.createRealMatrix(qta);
            }

            // return the cached matrix
            return(cachedQt);
        }
Example #14
0
        /// <summary>
        /// Returns the Householder reflector vectors.
        /// <para>H is a lower trapezoidal matrix whose columns represent
        /// each successive Householder reflector vector. This matrix is used
        /// to compute Q.</para>
        /// </summary>
        /// <returns>a matrix containing the Householder reflector vectors</returns>
        public RealMatrix getH()
        {
            if (cachedH == null)
            {
                int        n  = qrt.Length;
                int        m  = qrt[0].Length;
                double[][] ha = new double[m][];
                for (int i = 0; i < m; ++i)
                {
                    for (int j = 0; j < FastMath.min(i + 1, n); ++j)
                    {
                        ha[i][j] = qrt[j][i] / -rDiag[j];
                    }
                }
                cachedH = MatrixUtils.createRealMatrix(ha);
            }

            // return the cached matrix
            return(cachedH);
        }
Example #15
0
        /// <summary>
        /// Returns the matrix R of the decomposition.
        /// <para>R is an upper-triangular matrix</para>
        /// </summary>
        /// <returns>the R matrix</returns>
        public RealMatrix getR()
        {
            if (cachedR == null)
            {
                // R is supposed to be m x n
                int        n  = qrt.Length;
                int        m  = qrt[0].Length;
                double[][] ra = new double[m][];
                // copy the diagonal from rDiag and the upper triangle of qr
                for (int row = FastMath.min(m, n) - 1; row >= 0; row--)
                {
                    ra[row][row] = rDiag[row];
                    for (int col = row + 1; col < n; col++)
                    {
                        ra[row][col] = qrt[col][row];
                    }
                }
                cachedR = MatrixUtils.createRealMatrix(ra);
            }

            // return the cached matrix
            return(cachedR);
        }
Example #16
0
        /// <summary>
        /// Returns the tridiagonal matrix T of the transform.
        /// </summary>
        /// <returns>the T matrix</returns>
        public RealMatrix getT()
        {
            if (cachedT == null)
            {
                int        m  = main.Length;
                double[][] ta = new double[m][];
                for (int i = 0; i < m; ++i)
                {
                    ta[i][i] = main[i];
                    if (i > 0)
                    {
                        ta[i][i - 1] = secondary[i - 1];
                    }
                    if (i < main.Length - 1)
                    {
                        ta[i][i + 1] = secondary[i];
                    }
                }
                cachedT = MatrixUtils.createRealMatrix(ta);
            }

            // return the cached matrix
            return(cachedT);
        }
        /// <summary>
        /// Calculates the compact Singular Value Decomposition of the given matrix.
        /// </summary>
        /// <param name="matrix">Matrix to decompose.</param>
        public SingularValueDecomposition(RealMatrix matrix)
        {
            double[][] A;

            // "m" is always the largest dimension.
            if (matrix.getRowDimension() < matrix.getColumnDimension())
            {
                transposed = true;
                A          = matrix.transpose().getData();
                m          = matrix.getColumnDimension();
                n          = matrix.getRowDimension();
            }
            else
            {
                transposed = false;
                A          = matrix.getData();
                m          = matrix.getRowDimension();
                n          = matrix.getColumnDimension();
            }

            singularValues = new double[n];
            double[][] U    = new double[m][];
            double[][] V    = new double[n][];
            double[]   e    = new double[n];
            double[]   work = new double[m];
            // Reduce A to bidiagonal form, storing the diagonal elements
            // in s and the super-diagonal elements in e.
            int nct = FastMath.min(m - 1, n);
            int nrt = FastMath.max(0, n - 2);

            for (int k = 0; k < FastMath.max(nct, nrt); k++)
            {
                if (k < nct)
                {
                    // Compute the transformation for the k-th column and
                    // place the k-th diagonal in s[k].
                    // Compute 2-norm of k-th column without under/overflow.
                    singularValues[k] = 0;
                    for (int i = k; i < m; i++)
                    {
                        singularValues[k] = FastMath.hypot(singularValues[k], A[i][k]);
                    }
                    if (singularValues[k] != 0)
                    {
                        if (A[k][k] < 0)
                        {
                            singularValues[k] = -singularValues[k];
                        }
                        for (int i = k; i < m; i++)
                        {
                            A[i][k] /= singularValues[k];
                        }
                        A[k][k] += 1;
                    }
                    singularValues[k] = -singularValues[k];
                }
                for (int j = k + 1; j < n; j++)
                {
                    if (k < nct &&
                        singularValues[k] != 0)
                    {
                        // Apply the transformation.
                        double t = 0;
                        for (int i = k; i < m; i++)
                        {
                            t += A[i][k] * A[i][j];
                        }
                        t = -t / A[k][k];
                        for (int i = k; i < m; i++)
                        {
                            A[i][j] += t * A[i][k];
                        }
                    }
                    // Place the k-th row of A into e for the
                    // subsequent calculation of the row transformation.
                    e[j] = A[k][j];
                }
                if (k < nct)
                {
                    // Place the transformation in U for subsequent back
                    // multiplication.
                    for (int i = k; i < m; i++)
                    {
                        U[i][k] = A[i][k];
                    }
                }
                if (k < nrt)
                {
                    // Compute the k-th row transformation and place the
                    // k-th super-diagonal in e[k].
                    // Compute 2-norm without under/overflow.
                    e[k] = 0;
                    for (int i = k + 1; i < n; i++)
                    {
                        e[k] = FastMath.hypot(e[k], e[i]);
                    }
                    if (e[k] != 0)
                    {
                        if (e[k + 1] < 0)
                        {
                            e[k] = -e[k];
                        }
                        for (int i = k + 1; i < n; i++)
                        {
                            e[i] /= e[k];
                        }
                        e[k + 1] += 1;
                    }
                    e[k] = -e[k];
                    if (k + 1 < m &&
                        e[k] != 0)
                    {
                        // Apply the transformation.
                        for (int i = k + 1; i < m; i++)
                        {
                            work[i] = 0;
                        }
                        for (int j = k + 1; j < n; j++)
                        {
                            for (int i = k + 1; i < m; i++)
                            {
                                work[i] += e[j] * A[i][j];
                            }
                        }
                        for (int j = k + 1; j < n; j++)
                        {
                            double t = -e[j] / e[k + 1];
                            for (int i = k + 1; i < m; i++)
                            {
                                A[i][j] += t * work[i];
                            }
                        }
                    }

                    // Place the transformation in V for subsequent
                    // back multiplication.
                    for (int i = k + 1; i < n; i++)
                    {
                        V[i][k] = e[i];
                    }
                }
            }
            // Set up the final bidiagonal matrix or order p.
            int p = n;

            if (nct < n)
            {
                singularValues[nct] = A[nct][nct];
            }
            if (m < p)
            {
                singularValues[p - 1] = 0;
            }
            if (nrt + 1 < p)
            {
                e[nrt] = A[nrt][p - 1];
            }
            e[p - 1] = 0;

            // Generate U.
            for (int j = nct; j < n; j++)
            {
                for (int i = 0; i < m; i++)
                {
                    U[i][j] = 0;
                }
                U[j][j] = 1;
            }
            for (int k = nct - 1; k >= 0; k--)
            {
                if (singularValues[k] != 0)
                {
                    for (int j = k + 1; j < n; j++)
                    {
                        double t = 0;
                        for (int i = k; i < m; i++)
                        {
                            t += U[i][k] * U[i][j];
                        }
                        t = -t / U[k][k];
                        for (int i = k; i < m; i++)
                        {
                            U[i][j] += t * U[i][k];
                        }
                    }
                    for (int i = k; i < m; i++)
                    {
                        U[i][k] = -U[i][k];
                    }
                    U[k][k] = 1 + U[k][k];
                    for (int i = 0; i < k - 1; i++)
                    {
                        U[i][k] = 0;
                    }
                }
                else
                {
                    for (int i = 0; i < m; i++)
                    {
                        U[i][k] = 0;
                    }
                    U[k][k] = 1;
                }
            }

            // Generate V.
            for (int k = n - 1; k >= 0; k--)
            {
                if (k < nrt &&
                    e[k] != 0)
                {
                    for (int j = k + 1; j < n; j++)
                    {
                        double t = 0;
                        for (int i = k + 1; i < n; i++)
                        {
                            t += V[i][k] * V[i][j];
                        }
                        t = -t / V[k + 1][k];
                        for (int i = k + 1; i < n; i++)
                        {
                            V[i][j] += t * V[i][k];
                        }
                    }
                }
                for (int i = 0; i < n; i++)
                {
                    V[i][k] = 0;
                }
                V[k][k] = 1;
            }

            // Main iteration loop for the singular values.
            int pp = p - 1;

            while (p > 0)
            {
                int k;
                int kase;
                // Here is where a test for too many iterations would go.
                // This section of the program inspects for
                // negligible elements in the s and e arrays.  On
                // completion the variables kase and k are set as follows.
                // kase = 1     if s(p) and e[k-1] are negligible and k<p
                // kase = 2     if s(k) is negligible and k<p
                // kase = 3     if e[k-1] is negligible, k<p, and
                //              s(k), ..., s(p) are not negligible (qr step).
                // kase = 4     if e(p-1) is negligible (convergence).
                for (k = p - 2; k >= 0; k--)
                {
                    double threshold
                        = TINY + EPS * (FastMath.abs(singularValues[k]) +
                                        FastMath.abs(singularValues[k + 1]));

                    // the following condition is written this way in order
                    // to break out of the loop when NaN occurs, writing it
                    // as "if (FastMath.abs(e[k]) <= threshold)" would loop
                    // indefinitely in case of NaNs because comparison on NaNs
                    // always return false, regardless of what is checked
                    // see issue MATH-947
                    if (!(FastMath.abs(e[k]) > threshold))
                    {
                        e[k] = 0;
                        break;
                    }
                }

                if (k == p - 2)
                {
                    kase = 4;
                }
                else
                {
                    int ks;
                    for (ks = p - 1; ks >= k; ks--)
                    {
                        if (ks == k)
                        {
                            break;
                        }
                        double t = (ks != p ? FastMath.abs(e[ks]) : 0) +
                                   (ks != k + 1 ? FastMath.abs(e[ks - 1]) : 0);
                        if (FastMath.abs(singularValues[ks]) <= TINY + EPS * t)
                        {
                            singularValues[ks] = 0;
                            break;
                        }
                    }
                    if (ks == k)
                    {
                        kase = 3;
                    }
                    else if (ks == p - 1)
                    {
                        kase = 1;
                    }
                    else
                    {
                        kase = 2;
                        k    = ks;
                    }
                }
                k++;
                // Perform the task indicated by kase.
                switch (kase)
                {
                // Deflate negligible s(p).
                case 1:
                {
                    double f = e[p - 2];
                    e[p - 2] = 0;
                    for (int j = p - 2; j >= k; j--)
                    {
                        double t  = FastMath.hypot(singularValues[j], f);
                        double cs = singularValues[j] / t;
                        double sn = f / t;
                        singularValues[j] = t;
                        if (j != k)
                        {
                            f        = -sn * e[j - 1];
                            e[j - 1] = cs * e[j - 1];
                        }

                        for (int i = 0; i < n; i++)
                        {
                            t           = cs * V[i][j] + sn * V[i][p - 1];
                            V[i][p - 1] = -sn * V[i][j] + cs * V[i][p - 1];
                            V[i][j]     = t;
                        }
                    }
                }
                break;

                // Split at negligible s(k).
                case 2:
                {
                    double f = e[k - 1];
                    e[k - 1] = 0;
                    for (int j = k; j < p; j++)
                    {
                        double t  = FastMath.hypot(singularValues[j], f);
                        double cs = singularValues[j] / t;
                        double sn = f / t;
                        singularValues[j] = t;
                        f    = -sn * e[j];
                        e[j] = cs * e[j];

                        for (int i = 0; i < m; i++)
                        {
                            t           = cs * U[i][j] + sn * U[i][k - 1];
                            U[i][k - 1] = -sn * U[i][j] + cs * U[i][k - 1];
                            U[i][j]     = t;
                        }
                    }
                }
                break;

                // Perform one qr step.
                case 3:
                {
                    // Calculate the shift.
                    double maxPm1Pm2 = FastMath.max(FastMath.abs(singularValues[p - 1]),
                                                    FastMath.abs(singularValues[p - 2]));
                    double scale = FastMath.max(FastMath.max(FastMath.max(maxPm1Pm2,
                                                                          FastMath.abs(e[p - 2])),
                                                             FastMath.abs(singularValues[k])),
                                                FastMath.abs(e[k]));
                    double sp    = singularValues[p - 1] / scale;
                    double spm1  = singularValues[p - 2] / scale;
                    double epm1  = e[p - 2] / scale;
                    double sk    = singularValues[k] / scale;
                    double ek    = e[k] / scale;
                    double b     = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
                    double c     = (sp * epm1) * (sp * epm1);
                    double shift = 0;
                    if (b != 0 ||
                        c != 0)
                    {
                        shift = FastMath.sqrt(b * b + c);
                        if (b < 0)
                        {
                            shift = -shift;
                        }
                        shift = c / (b + shift);
                    }
                    double f = (sk + sp) * (sk - sp) + shift;
                    double g = sk * ek;
                    // Chase zeros.
                    for (int j = k; j < p - 1; j++)
                    {
                        double t  = FastMath.hypot(f, g);
                        double cs = f / t;
                        double sn = g / t;
                        if (j != k)
                        {
                            e[j - 1] = t;
                        }
                        f    = cs * singularValues[j] + sn * e[j];
                        e[j] = cs * e[j] - sn * singularValues[j];
                        g    = sn * singularValues[j + 1];
                        singularValues[j + 1] = cs * singularValues[j + 1];

                        for (int i = 0; i < n; i++)
                        {
                            t           = cs * V[i][j] + sn * V[i][j + 1];
                            V[i][j + 1] = -sn * V[i][j] + cs * V[i][j + 1];
                            V[i][j]     = t;
                        }
                        t  = FastMath.hypot(f, g);
                        cs = f / t;
                        sn = g / t;
                        singularValues[j] = t;
                        f = cs * e[j] + sn * singularValues[j + 1];
                        singularValues[j + 1] = -sn * e[j] + cs * singularValues[j + 1];
                        g        = sn * e[j + 1];
                        e[j + 1] = cs * e[j + 1];
                        if (j < m - 1)
                        {
                            for (int i = 0; i < m; i++)
                            {
                                t           = cs * U[i][j] + sn * U[i][j + 1];
                                U[i][j + 1] = -sn * U[i][j] + cs * U[i][j + 1];
                                U[i][j]     = t;
                            }
                        }
                    }
                    e[p - 2] = f;
                }
                break;

                // Convergence.
                default:
                {
                    // Make the singular values positive.
                    if (singularValues[k] <= 0)
                    {
                        singularValues[k] = singularValues[k] < 0 ? -singularValues[k] : 0;

                        for (int i = 0; i <= pp; i++)
                        {
                            V[i][k] = -V[i][k];
                        }
                    }
                    // Order the singular values.
                    while (k < pp)
                    {
                        if (singularValues[k] >= singularValues[k + 1])
                        {
                            break;
                        }
                        double t = singularValues[k];
                        singularValues[k]     = singularValues[k + 1];
                        singularValues[k + 1] = t;
                        if (k < n - 1)
                        {
                            for (int i = 0; i < n; i++)
                            {
                                t           = V[i][k + 1];
                                V[i][k + 1] = V[i][k];
                                V[i][k]     = t;
                            }
                        }
                        if (k < m - 1)
                        {
                            for (int i = 0; i < m; i++)
                            {
                                t           = U[i][k + 1];
                                U[i][k + 1] = U[i][k];
                                U[i][k]     = t;
                            }
                        }
                        k++;
                    }
                    p--;
                }
                break;
                }
            }

            // Set the small value tolerance used to calculate rank and pseudo-inverse
            tol = FastMath.max(m * singularValues[0] * EPS,
                               FastMath.sqrt(Precision.SAFE_MIN));

            if (!transposed)
            {
                cachedU = MatrixUtils.createRealMatrix(U);
                cachedV = MatrixUtils.createRealMatrix(V);
            }
            else
            {
                cachedU = MatrixUtils.createRealMatrix(V);
                cachedV = MatrixUtils.createRealMatrix(U);
            }
        }
        /// <summary>
        /// Parse a string to produce a <see cref="RealMatrix"/> object.
        /// </summary>
        /// <param name="source">String to parse.</param>
        /// <param name="pos">input/ouput parsing parameter.</param>
        /// <returns>the parsed <see cref="RealMatrix"/> object.</returns>
        public RealMatrix parse(String source, ref Int32 pos)
        {
            int initialIndex = pos;

            String trimmedPrefix          = prefix.Trim();
            String trimmedSuffix          = suffix.Trim();
            String trimmedRowPrefix       = rowPrefix.Trim();
            String trimmedRowSuffix       = rowSuffix.Trim();
            String trimmedColumnSeparator = columnSeparator.Trim();
            String trimmedRowSeparator    = rowSeparator.Trim();

            // parse prefix
            CompositeFormat.parseAndIgnoreWhitespace(source, pos);
            if (!CompositeFormat.parseFixedstring(source, trimmedPrefix))
            {
                return(null);
            }


            // parse components
            List <List <double> > matrix        = new List <List <double> >();
            List <double>         rowComponents = new List <double>();

            for (Boolean loop = true; loop;)
            {
                if (rowComponents.Count != 0)
                {
                    CompositeFormat.parseAndIgnoreWhitespace(source, pos);
                    if (!CompositeFormat.parseFixedstring(source, trimmedColumnSeparator))
                    {
                        if (trimmedRowSuffix.Length != 0 &&
                            !CompositeFormat.parseFixedstring(source, trimmedRowSuffix))
                        {
                            return(null);
                        }
                        else
                        {
                            CompositeFormat.parseAndIgnoreWhitespace(source, pos);
                            if (CompositeFormat.parseFixedstring(source, trimmedRowSeparator))
                            {
                                matrix.Add(rowComponents);
                                rowComponents = new List <double>();
                                continue;
                            }
                            else
                            {
                                loop = false;
                            }
                        }
                    }
                }
                else
                {
                    CompositeFormat.parseAndIgnoreWhitespace(source, pos);
                    if (trimmedRowPrefix.Length != 0 &&
                        !CompositeFormat.parseFixedstring(source, trimmedRowPrefix))
                    {
                        return(null);
                    }
                }

                if (loop)
                {
                    CompositeFormat.parseAndIgnoreWhitespace(source, pos);
                    double component = CompositeFormat.parseNumber(source, CultureInfo.CurrentCulture);
                    if (Double.IsNaN(component))
                    {
                        rowComponents.Add(component);
                    }
                    else
                    {
                        if (rowComponents.Count == 0)
                        {
                            loop = false;
                        }
                        else
                        {
                            // invalid component
                            // set index back to initial, error index should already be set
                            pos = initialIndex;
                            return(null);
                        }
                    }
                }
            }

            if (rowComponents.Count != 0)
            {
                matrix.Add(rowComponents);
            }

            // parse suffix
            CompositeFormat.parseAndIgnoreWhitespace(source, pos);
            if (!CompositeFormat.parseFixedstring(source, trimmedSuffix))
            {
                return(null);
            }

            // do not allow an empty matrix
            if (matrix.Count == 0)
            {
                pos = initialIndex;
                return(null);
            }

            // build vector
            double[][] data = new double[matrix.Count][];
            int        row  = 0;

            foreach (List <double> rowList in matrix)
            {
                data[row] = new double[rowList.Count];
                for (int i = 0; i < rowList.Count; i++)
                {
                    data[row][i] = rowList[i];
                }
                row++;
            }
            return(MatrixUtils.createRealMatrix(data));
        }