/**
         * 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 DMatrixRMaj getU(DMatrixRMaj U, bool transpose, bool compact)
        {
            U = handleU(U, transpose, compact, m, n, min);
            CommonOps_DDRM.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_DDRM.rank1UpdateMultL(U, u, gammasU[j], j, j, m);
                }
                else
                {
                    QrHelperFunctions_DDRM.rank1UpdateMultR(U, u, gammasU[j], j, j, m, this.b);
                }
            }

            return(U);
        }
        /**
         * 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 DMatrixRMaj getV(DMatrixRMaj V, bool transpose, bool compact)
        {
            V = handleV(V, transpose, compact, m, n, min);
            CommonOps_DDRM.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_DDRM.rank1UpdateMultL(V, u, gammasV[j], j + 1, j + 1, n);
                }
                else
                {
                    QrHelperFunctions_DDRM.rank1UpdateMultR(V, u, gammasV[j], j + 1, j + 1, n, this.b);
                }
            }

            return(V);
        }
Esempio n. 3
0
        public void performImplicitSingleStep(int x1, int x2, double eigenvalue)
        {
            if (!createBulgeSingleStep(x1, eigenvalue))
            {
                return;
            }

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

            if (printHumps)
            {
                Console.WriteLine("Applied first Q matrix, it should be humped now. A = ");
                A.print("%12.3e");
                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_DDRM.rank1UpdateMultR(Q, u.data, gamma, 0, i + 1, i + 3, _temp.data);
                    if (checkOrthogonal && !MatrixFeatures_DDRM.isOrthogonal(Q, UtilEjml.TESTP_F64))
                    {
                        throw new InvalidOperationException("Bad");
                    }
                }

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

            if (checkHessenberg && !MatrixFeatures_DDRM.isUpperTriangle(A, 1, UtilEjml.TESTP_F64))
            {
                A.print("%12.3e");
                throw new InvalidOperationException("Bad matrix");
            }
        }
        public override /**/ double quality()
        {
            return(SpecializedOps_DDRM.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(DMatrixRMaj B, DMatrixRMaj 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++)
                {
                    double[] u = QR[n];

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

                // solve for Rx = b using the standard upper triangular solver
                TriangularSolver_DDRM.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];
                }
            }
        }
        /**
         * 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 DMatrixRMaj getQ(DMatrixRMaj Q)
        {
            Q = UtilDecompositons_DDRM.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_DDRM.rank1UpdateMultR(Q, u, gammas[j], j + 1, j + 1, N, b);
            }

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

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

            int rowU = (k - 1) * N;

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

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

                double tau = QrHelperFunctions_DDRM.computeTauAndDivide(k, N, t, rowU, max);

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

                double 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)
        {
            double[] b = UBV.data;

            // find the largest value in this column
            // this is used to normalize the column and mitigate overflow/underflow
            double 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.
                double 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
                double tau = QrHelperFunctions_DDRM.computeTauAndDivide(k, m, u, max);

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

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

                // ---------- multiply on the left by Q_k
                QrHelperFunctions_DDRM.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 DMatrixRMaj getQ(DMatrixRMaj Q)
        {
            Q = UtilDecompositons_DDRM.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_DDRM.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b);
//            Q.print();
            }

            return(Q);
        }
        protected void computeV(int k)
        {
            double[] 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
            double max = QrHelperFunctions_DDRM.findMax(b, row + k + 1, n - k - 1);

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

                double tau = QrHelperFunctions_DDRM.computeTauAndDivide(k + 1, n, b, row, max);

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

                u[k + 1] = 1.0;

                double 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_DDRM.rank1UpdateMultL(UBV, u, gamma, k + 1, k + 1, n);

                b[row + k + 1] = -tau * max;
            }
            else
            {
                gammasV[k] = 0;
            }
        }
Esempio n. 10
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.
         */
        //@Override
        public DMatrixRMaj getQ(DMatrixRMaj Q, bool transposed)
        {
            Q = UtilDecompositons_DDRM.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_DDRM.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_DDRM.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b);
                }
            }

            return(Q);
        }
        private void performDecomposition(DMatrixSparseCSC A)
        {
            int[] w        = gwork.data;
            int[] permCol  = applyReduce.getArrayQ();
            int[] parent   = structure.getParent();
            int[] leftmost = structure.getLeftMost();
            // permutation that was done to ensure all rows have non-zero elements
            int[] pinv_structure = structure.getPinv();
            int   s = m2;

            // clear mark nodes. See addRowsInAInToC
            //Arrays.fill(w, 0, m2, -1);
            for (var i = 0; i < m2; i++)
            {
                w[i] = -1;
            }
            //Arrays.fill(x, 0, m2, 0);
            Array.Clear(x, 0, m2);

            // the counts from structure are actually an upper limit. the actual counts can be lower
            R.nz_length = 0;
            V.nz_length = 0;

            // compute V and R
            for (int k = 0; k < n; k++)
            {
                R.col_idx[k] = R.nz_length;
                int p1 = V.col_idx[k] = V.nz_length;
                w[k] = k;
                V.nz_rows[V.nz_length++] = k; // Add V(k,k) to V's pattern
                int top = n;
                int col = permCol != null ? permCol[k] : k;

                int idx0 = A.col_idx[col];
                int idx1 = A.col_idx[col + 1];

                for (int p = idx0; p < idx1; p++)
                {
                    int i = leftmost[A.nz_rows[p]];
                    int len;
                    for (len = 0; w[i] != k; i = parent[i])
                    {
                        w[s + len++] = i;
                        w[i]         = k;
                    }
                    while (len > 0)
                    {
                        w[s + --top] = w[s + --len];
                    }
                    i    = pinv_structure[A.nz_rows[p]];
                    x[i] = A.nz_values[p];
                    if (i > k && w[i] < k)
                    {
                        V.nz_rows[V.nz_length++] = i;
                        w[i] = k;
                    }
                }
                // apply previously computed Householder vectors to the current columns
                for (int p = top; p < n; p++)
                {
                    int i = w[s + p];
                    QrHelperFunctions_DSCC.applyHouseholder(V, i, beta[i], x);
                    R.nz_rows[R.nz_length]     = i;
                    R.nz_values[R.nz_length++] = x[i];
                    x[i] = 0;
                    if (parent[i] == k)
                    {
                        ImplSparseSparseMult_DSCC.addRowsInAInToC(V, i, V, k, w);
                    }
                }
                for (int p = p1; p < V.nz_length; p++)
                {
                    V.nz_values[p]  = x[V.nz_rows[p]];
                    x[V.nz_rows[p]] = 0;
                }
                R.nz_rows[R.nz_length] = k;
                double max = QrHelperFunctions_DDRM.findMax(V.nz_values, p1, V.nz_length - p1);
                if (max == 0.0)
                {
                    singular = true;
                    R.nz_values[R.nz_length] = 0;
                    beta[k] = 0;
                }
                else
                {
                    R.nz_values[R.nz_length] =
                        QrHelperFunctions_DSCC.computeHouseholder(V.nz_values, p1, V.nz_length, max, Beta);
                    beta[k] = Beta.value;
                }
                R.nz_length++;
            }
            R.col_idx[n] = R.nz_length;
            V.col_idx[n] = V.nz_length;
        }
        /**
         * Internal function for computing the decomposition.
         */
        private bool _decompose()
        {
            double[] 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
                double 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.
                    double 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

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

                    tau = Math.Sqrt(tau);

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

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

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

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

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

                    // ---------- multiply on the right by Q_k
                    QrHelperFunctions_DDRM.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);
        }
        public override void solve(DMatrixRMaj B, DMatrixRMaj 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();

            double[][] qr     = decomposition.getQR();
            double[]   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++)
                {
                    double[] u = qr[i];

                    double vv = u[i];
                    u[i] = 1;
                    QrHelperFunctions_DDRM.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_DDRM.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]);
                }
            }
        }
Esempio n. 14
0
        public bool bulgeSingleStepQn(int i,
                                      double a11, double a21,
                                      double threshold, bool set)
        {
            double 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.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

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

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

            double 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_DDRM.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_DDRM.rank1UpdateMultL(A, u.data, gamma, 0, i, i + 2);

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

            return(true);
        }
Esempio n. 15
0
        private void performImplicitDoubleStep(int x1, int x2,
                                               double b11, double b21, double b31)
        {
            if (!bulgeDoubleStepQn(x1, b11, b21, b31, 0, false))
            {
                return;
            }

            // get rid of the bump
            if (Q != null)
            {
                QrHelperFunctions_DDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x1, x1 + 3, _temp.data);
                if (checkOrthogonal && !MatrixFeatures_DDRM.isOrthogonal(Q, UtilEjml.TEST_F64))
                {
                    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.3e");
                Console.WriteLine("Pushing the hump off the matrix.");
            }

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

                if (printHumps)
                {
                    Console.WriteLine("i = " + i + " A = ");
                    A.print("%12.3e");
                }
            }
            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_DDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x2 - 1, x2 + 1, _temp.data);
                if (checkOrthogonal && !MatrixFeatures_DDRM.isOrthogonal(Q, UtilEjml.TEST_F64))
                {
                    throw new InvalidOperationException("Bad");
                }
            }
            if (printHumps)
            {
                Console.WriteLine(" A = ");
                A.print("%12.3e");
            }
//        A.print("%12.3e");

            if (checkHessenberg && !MatrixFeatures_DDRM.isUpperTriangle(A, 1, UtilEjml.TEST_F64))
            {
                A.print("%12.3e");
                throw new InvalidOperationException("Bad matrix");
            }
        }