/**
         * Returns the orthogonal V matrix.
         *
         * @param V If not null then the results will be stored here.  Otherwise a new matrix will be created.
         * @return The extracted Q matrix.
         */
        public virtual FMatrixRMaj getV(FMatrixRMaj V, bool transpose, bool compact)
        {
            V = handleV(V, transpose, compact, m, n, min);
            CommonOps_FDRM.setIdentity(V);

//        UBV.print();

            // todo the very first multiplication can be avoided by setting to the rank1update output
            for (int j = min - 1; j >= 0; j--)
            {
                u[j + 1] = 1;
                for (int i = j + 2; i < n; i++)
                {
                    u[i] = UBV.get(j, i);
                }
                if (transpose)
                {
                    QrHelperFunctions_FDRM.rank1UpdateMultL(V, u, gammasV[j], j + 1, j + 1, n);
                }
                else
                {
                    QrHelperFunctions_FDRM.rank1UpdateMultR(V, u, gammasV[j], j + 1, j + 1, n, this.b);
                }
            }

            return(V);
        }
        /**
         * Returns the orthogonal U matrix.
         *
         * @param U If not null then the results will be stored here.  Otherwise a new matrix will be created.
         * @return The extracted Q matrix.
         */
        public virtual FMatrixRMaj getU(FMatrixRMaj U, bool transpose, bool compact)
        {
            U = handleU(U, transpose, compact, m, n, min);
            CommonOps_FDRM.setIdentity(U);

            for (int i = 0; i < m; i++)
            {
                u[i] = 0;
            }

            for (int j = min - 1; j >= 0; j--)
            {
                u[j] = 1;
                for (int i = j + 1; i < m; i++)
                {
                    u[i] = UBV.get(i, j);
                }
                if (transpose)
                {
                    QrHelperFunctions_FDRM.rank1UpdateMultL(U, u, gammasU[j], j, j, m);
                }
                else
                {
                    QrHelperFunctions_FDRM.rank1UpdateMultR(U, u, gammasU[j], j, j, m, this.b);
                }
            }

            return(U);
        }
예제 #3
0
        public void performImplicitSingleStep(int x1, int x2, float eigenvalue)
        {
            if (!createBulgeSingleStep(x1, eigenvalue))
            {
                return;
            }

            // get rid of the bump
            if (Q != null)
            {
                QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x1, x1 + 2, _temp.data);
                if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32))
                {
                    throw new InvalidOperationException("Bad");
                }
            }

            if (printHumps)
            {
                Console.WriteLine("Applied first Q matrix, it should be humped now. A = ");
                A.print("%12.3fe");
                Console.WriteLine("Pushing the hump off the matrix.");
            }

            // perform simple steps
            for (int i = x1; i < x2 - 1; i++)
            {
                if (bulgeSingleStepQn(i) && Q != null)
                {
                    QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, i + 1, i + 3, _temp.data);
                    if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TESTP_F32))
                    {
                        throw new InvalidOperationException("Bad");
                    }
                }

                if (printHumps)
                {
                    Console.WriteLine("i = " + i + " A = ");
                    A.print("%12.3fe");
                }
            }

            if (checkHessenberg && !MatrixFeatures_FDRM.isUpperTriangle(A, 1, UtilEjml.TESTP_F32))
            {
                A.print("%12.3fe");
                throw new InvalidOperationException("Bad matrix");
            }
        }
        public override /**/ double quality()
        {
            return(SpecializedOps_FDRM.qualityTriangular(R));
        }

        /**
         * Solves for X using the QR decomposition.
         *
         * @param B A matrix that is n by m.  Not modified.
         * @param X An n by m matrix where the solution is written to.  Modified.
         */
        public override void solve(FMatrixRMaj B, FMatrixRMaj X)
        {
            if (X.numRows != numCols)
            {
                throw new ArgumentException("Unexpected dimensions for X: X rows = " + X.numRows + " expected = " +
                                            numCols);
            }
            else if (B.numRows != numRows || B.numCols != X.numCols)
            {
                throw new ArgumentException("Unexpected dimensions for B");
            }

            int BnumCols = B.numCols;

            // solve each column one by one
            for (int colB = 0; colB < BnumCols; colB++)
            {
                // make a copy of this column in the vector
                for (int i = 0; i < numRows; i++)
                {
                    a.data[i] = B.data[i * BnumCols + colB];
                }

                // Solve Qa=b
                // a = Q'b
                // a = Q_{n-1}...Q_2*Q_1*b
                //
                // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b)
                for (int n = 0; n < numCols; n++)
                {
                    float[] u = QR[n];

                    float vv = u[n];
                    u[n] = 1;
                    QrHelperFunctions_FDRM.rank1UpdateMultR(a, u, gammas[n], 0, n, numRows, temp.data);
                    u[n] = vv;
                }

                // solve for Rx = b using the standard upper triangular solver
                TriangularSolver_FDRM.solveU(R.data, a.data, numCols);

                // save the results
                for (int i = 0; i < numCols; i++)
                {
                    X.data[i * X.numCols + colB] = a.data[i];
                }
            }
        }
예제 #5
0
        /**
         * An orthogonal matrix that has the following property: H = Q<sup>T</sup>AQ
         *
         * @param Q If not null then the results will be stored here.  Otherwise a new matrix will be created.
         * @return The extracted Q matrix.
         */
        public FMatrixRMaj getQ(FMatrixRMaj Q)
        {
            Q = UtilDecompositons_FDRM.checkIdentity(Q, N, N);

            for (int j = N - 2; j >= 0; j--)
            {
                u[j + 1] = 1;
                for (int i = j + 2; i < N; i++)
                {
                    u[i] = QH.get(i, j);
                }
                QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u, gammas[j], j + 1, j + 1, N, b);
            }

            return(Q);
        }
        /**
         * Computes and performs the similar a transform for submatrix k.
         */
        private void similarTransform(int k)
        {
            float[] t = QT.data;

            // find the largest value in this column
            // this is used to normalize the column and mitigate overflow/underflow
            float max = 0;

            int rowU = (k - 1) * N;

            for (int i = k; i < N; i++)
            {
                float val = Math.Abs(t[rowU + i]);
                if (val > max)
                {
                    max = val;
                }
            }

            if (max > 0)
            {
                // -------- set up the reflector Q_k

                float tau = QrHelperFunctions_FDRM.computeTauAndDivide(k, N, t, rowU, max);

                // write the reflector into the lower left column of the matrix
                float nu = t[rowU + k] + tau;
                QrHelperFunctions_FDRM.divideElements(k + 1, N, t, rowU, nu);
                t[rowU + k] = 1.0f;

                float gamma = nu / tau;
                gammas[k] = gamma;

                // ---------- Specialized householder that takes advantage of the symmetry
                householderSymmetric(k, gamma);

                // since the first element in the householder vector is known to be 1
                // store the full upper hessenberg
                t[rowU + k] = -tau * max;
            }
            else
            {
                gammas[k] = 0;
            }
        }
        protected void computeU(int k)
        {
            float[] b = UBV.data;

            // find the largest value in this column
            // this is used to normalize the column and mitigate overflow/underflow
            float max = 0;

            for (int i = k; i < m; i++)
            {
                // copy the householder vector to vector outside of the matrix to reduce caching issues
                // big improvement on larger matrices and a relatively small performance hit on small matrices.
                float val = u[i] = b[i * n + k];
                val = Math.Abs(val);
                if (val > max)
                {
                    max = val;
                }
            }

            if (max > 0)
            {
                // -------- set up the reflector Q_k
                float tau = QrHelperFunctions_FDRM.computeTauAndDivide(k, m, u, max);

                // write the reflector into the lower left column of the matrix
                // while dividing u by nu
                float nu = u[k] + tau;
                QrHelperFunctions_FDRM.divideElements_Bcol(k + 1, m, n, u, b, k, nu);
                u[k] = 1.0f;

                float gamma = nu / tau;
                gammasU[k] = gamma;

                // ---------- multiply on the left by Q_k
                QrHelperFunctions_FDRM.rank1UpdateMultR(UBV, u, gamma, k + 1, k, m, this.b);

                b[k * n + k] = -tau * max;
            }
            else
            {
                gammasU[k] = 0;
            }
        }
        /**
         * An orthogonal matrix that has the following property: T = Q<sup>T</sup>AQ
         *
         * @param Q If not null then the results will be stored here.  Otherwise a new matrix will be created.
         * @return The extracted Q matrix.
         */
        public FMatrixRMaj getQ(FMatrixRMaj Q)
        {
            Q = UtilDecompositons_FDRM.checkIdentity(Q, N, N);

            for (int i = 0; i < N; i++)
            {
                w[i] = 0;
            }

            for (int j = N - 2; j >= 0; j--)
            {
                w[j + 1] = 1;
                for (int i = j + 2; i < N; i++)
                {
                    w[i] = QT.get(j, i);
                }
                QrHelperFunctions_FDRM.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b);
//            Q.print();
            }

            return(Q);
        }
        protected void computeV(int k)
        {
            float[] b = UBV.data;

            int row = k * n;

            // find the largest value in this column
            // this is used to normalize the column and mitigate overflow/underflow
            float max = QrHelperFunctions_FDRM.findMax(b, row + k + 1, n - k - 1);

            if (max > 0)
            {
                // -------- set up the reflector Q_k

                float tau = QrHelperFunctions_FDRM.computeTauAndDivide(k + 1, n, b, row, max);

                // write the reflector into the lower left column of the matrix
                float nu = b[row + k + 1] + tau;
                QrHelperFunctions_FDRM.divideElements_Brow(k + 2, n, u, b, row, nu);

                u[k + 1] = 1.0f;

                float gamma = nu / tau;
                gammasV[k] = gamma;

                // writing to u could be avoided by working directly with b.
                // requires writing a custom rank1Update function
                // ---------- multiply on the left by Q_k
                QrHelperFunctions_FDRM.rank1UpdateMultL(UBV, u, gamma, k + 1, k + 1, n);

                b[row + k + 1] = -tau * max;
            }
            else
            {
                gammasV[k] = 0;
            }
        }
        /**
         * An orthogonal matrix that has the following property: T = Q<sup>T</sup>AQ
         *
         * @param Q If not null then the results will be stored here.  Otherwise a new matrix will be created.
         * @return The extracted Q matrix.
         */
        public virtual FMatrixRMaj getQ(FMatrixRMaj Q, bool transposed)
        {
            Q = UtilDecompositons_FDRM.checkIdentity(Q, N, N);

            for (int i = 0; i < N; i++)
            {
                w[i] = 0;
            }

            if (transposed)
            {
                for (int j = N - 2; j >= 0; j--)
                {
                    w[j + 1] = 1;
                    for (int i = j + 2; i < N; i++)
                    {
                        w[i] = QT.data[j * N + i];
                    }
                    QrHelperFunctions_FDRM.rank1UpdateMultL(Q, w, gammas[j + 1], j + 1, j + 1, N);
                }
            }
            else
            {
                for (int j = N - 2; j >= 0; j--)
                {
                    w[j + 1] = 1;
                    for (int i = j + 2; i < N; i++)
                    {
                        w[i] = QT.get(j, i);
                    }
                    QrHelperFunctions_FDRM.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b);
                }
            }

            return(Q);
        }
        public override void solve(FMatrixRMaj B, FMatrixRMaj X)
        {
            if (X.numRows != numCols)
            {
                throw new ArgumentException("Unexpected dimensions for X");
            }
            else if (B.numRows != numRows || B.numCols != X.numCols)
            {
                throw new ArgumentException("Unexpected dimensions for B");
            }

            int BnumCols = B.numCols;

            // get the pivots and transpose them
            int[] pivots = decomposition.getColPivots();

            float[][] qr     = decomposition.getQR();
            float[]   gammas = decomposition.getGammas();

            // solve each column one by one
            for (int colB = 0; colB < BnumCols; colB++)
            {
                x_basic.reshape(numRows, 1);
                Y.reshape(numRows, 1);

                // make a copy of this column in the vector
                for (int i = 0; i < numRows; i++)
                {
                    x_basic.data[i] = B.get(i, colB);
                }

                // Solve Q*x=b => x = Q'*b
                // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b)
                for (int i = 0; i < rank; i++)
                {
                    float[] u = qr[i];

                    float vv = u[i];
                    u[i] = 1;
                    QrHelperFunctions_FDRM.rank1UpdateMultR(x_basic, u, gammas[i], 0, i, numRows, Y.data);
                    u[i] = vv;
                }

                // solve for Rx = b using the standard upper triangular solver
                TriangularSolver_FDRM.solveU(R11.data, x_basic.data, rank);

                // finish the basic solution by filling in zeros
                x_basic.reshape(numCols, 1, true);
                for (int i = rank; i < numCols; i++)
                {
                    x_basic.data[i] = 0;
                }

                if (norm2Solution && rank < numCols)
                {
                    upgradeSolution(x_basic);
                }

                // save the results
                for (int i = 0; i < numCols; i++)
                {
                    X.set(pivots[i], colB, x_basic.data[i]);
                }
            }
        }
예제 #12
0
        public bool bulgeSingleStepQn(int i,
                                      float a11, float a21,
                                      float threshold, bool set)
        {
            float max;

            if (normalize)
            {
                max = Math.Abs(a11);
                if (max < Math.Abs(a21))
                {
                    max = Math.Abs(a21);
                }

//            if( max <= Math.Abs(A.get(i,i))*UtilEjml.F_EPS ) {
                if (max <= threshold)
                {
//                Console.WriteLine("i = "+i);
//                A.print();
                    if (set)
                    {
                        A.set(i, i - 1, 0);
                        A.set(i + 1, i - 1, 0);
                    }
                    return(false);
                }

                a11 /= max;
                a21 /= max;
            }
            else
            {
                max = 1;
            }

            // compute the reflector using the b's above

            float tau = (float)Math.Sqrt(a11 * a11 + a21 * a21);

            if (a11 < 0)
            {
                tau = -tau;
            }

            float div = a11 + tau;

            u.set(i, 0, 1);
            u.set(i + 1, 0, a21 / div);

            gamma = div / tau;

            // compute A_1 = Q_1^T * A * Q_1

            // apply Q*A  - just do the 3 rows
            QrHelperFunctions_FDRM.rank1UpdateMultR(A, u.data, gamma, 0, i, i + 2, _temp.data);

            if (set)
            {
                A.set(i, i - 1, -max * tau);
                A.set(i + 1, i - 1, 0);
            }

            // apply A*Q - just the three things
            QrHelperFunctions_FDRM.rank1UpdateMultL(A, u.data, gamma, 0, i, i + 2);

            if (checkUncountable && MatrixFeatures_FDRM.hasUncountable(A))
            {
                throw new InvalidOperationException("bad matrix");
            }

            return(true);
        }
예제 #13
0
        private void performImplicitDoubleStep(int x1, int x2,
                                               float b11, float b21, float b31)
        {
            if (!bulgeDoubleStepQn(x1, b11, b21, b31, 0, false))
            {
                return;
            }

            // get rid of the bump
            if (Q != null)
            {
                QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x1, x1 + 3, _temp.data);
                if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32))
                {
                    u.print();

                    Q.print();
                    throw new InvalidOperationException("Bad");
                }
            }

            if (printHumps)
            {
                Console.WriteLine("Applied first Q matrix, it should be humped now. A = ");
                A.print("%12.3fe");
                Console.WriteLine("Pushing the hump off the matrix.");
            }

            // perform float steps
            for (int i = x1; i < x2 - 2; i++)
            {
                if (bulgeDoubleStepQn(i) && Q != null)
                {
                    QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, i + 1, i + 4, _temp.data);
                    if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32))
                    {
                        throw new InvalidOperationException("Bad");
                    }
                }

                if (printHumps)
                {
                    Console.WriteLine("i = " + i + " A = ");
                    A.print("%12.3fe");
                }
            }
            if (printHumps)
            {
                Console.WriteLine("removing last bump");
            }
            // the last one has to be a single step
            if (x2 - 2 >= 0 && bulgeSingleStepQn(x2 - 2) && Q != null)
            {
                QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x2 - 1, x2 + 1, _temp.data);
                if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32))
                {
                    throw new InvalidOperationException("Bad");
                }
            }
            if (printHumps)
            {
                Console.WriteLine(" A = ");
                A.print("%12.3fe");
            }
//        A.print("%12.3fe");

            if (checkHessenberg && !MatrixFeatures_FDRM.isUpperTriangle(A, 1, UtilEjml.TEST_F32))
            {
                A.print("%12.3fe");
                throw new InvalidOperationException("Bad matrix");
            }
        }
예제 #14
0
        /**
         * Internal function for computing the decomposition.
         */
        private bool _decompose()
        {
            float[] h = QH.data;

            for (int k = 0; k < N - 2; k++)
            {
                // find the largest value in this column
                // this is used to normalize the column and mitigate overflow/underflow
                float max = 0;

                for (int i = k + 1; i < N; i++)
                {
                    // copy the householder vector to vector outside of the matrix to reduce caching issues
                    // big improvement on larger matrices and a relatively small performance hit on small matrices.
                    float val = u[i] = h[i * N + k];
                    val = Math.Abs(val);
                    if (val > max)
                    {
                        max = val;
                    }
                }

                if (max > 0)
                {
                    // -------- set up the reflector Q_k

                    float tau = 0;
                    // normalize to reduce overflow/underflow
                    // and compute tau for the reflector
                    for (int i = k + 1; i < N; i++)
                    {
                        float val = u[i] /= max;
                        tau += val * val;
                    }

                    tau = (float)Math.Sqrt(tau);

                    if (u[k + 1] < 0)
                    {
                        tau = -tau;
                    }

                    // write the reflector into the lower left column of the matrix
                    float nu = u[k + 1] + tau;
                    u[k + 1] = 1.0f;

                    for (int i = k + 2; i < N; i++)
                    {
                        h[i * N + k] = u[i] /= nu;
                    }

                    float gamma = nu / tau;
                    gammas[k] = gamma;

                    // ---------- multiply on the left by Q_k
                    QrHelperFunctions_FDRM.rank1UpdateMultR(QH, u, gamma, k + 1, k + 1, N, b);

                    // ---------- multiply on the right by Q_k
                    QrHelperFunctions_FDRM.rank1UpdateMultL(QH, u, gamma, 0, k + 1, N);

                    // since the first element in the householder vector is known to be 1
                    // store the full upper hessenberg
                    h[(k + 1) * N + k] = -tau * max;
                }
                else
                {
                    gammas[k] = 0;
                }
            }

            return(true);
        }