Esempio n. 1
0
        /**
         * <p>
         * Adjusts the values of the Q and R matrices to take in account the effects of inserting
         * a row to the 'A' matrix at the specified location.  This operation requires about 6mn + O(n) flops.
         * </p>
         *
         * <p>
         * If Q and/or R does not have enough data elements to grow then an exception is thrown.
         * </p>
         *
         * <p>
         * The adjustment done is by computing a series of planar Givens rotations that make the adjusted R
         * matrix upper triangular again.  This is then used to modify the Q matrix.
         * </p>
         *
         * @param Q The Q matrix which is to be modified, must be big enough to grow.  Must be n by n..  Is modified.
         * @param R The R matrix which is to be modified, must be big enough to grow.  Must be m by n.  Is modified.
         * @param row The row being inserted.  Not modified.
         * @param rowIndex Which row index it is to be inserted at.
         * @param resizeR Should the number of rows in R be changed?  The additional rows are all zero.
         */
        public void addRow(FMatrixRMaj Q, FMatrixRMaj R, float[] row, int rowIndex, bool resizeR)
        {
            // memory management and check precoditions
            setQR(Q, R, 1);
            m_m = m + 1;

            if (Q.data.Length < m_m * m_m)
            {
                throw new ArgumentException("Q matrix does not have enough data to grow");
            }

            if (resizeR && R.data.Length < m_m * n)
            {
                throw new ArgumentException("R matrix does not have enough data to grow");
            }

            if (resizeR)
            {
                R.reshape(m_m, n, false);
            }

            U_tran.reshape(m_m, m_m, false);

            // apply givens rotation to the first two rows of the augmented R matrix
            applyFirstGivens(row);
            applyLaterGivens();
            // compute new Q matrix
            updateInsertQ(rowIndex);

            // discard the reference since it is no longer needed
            this.Q = this.R = null;
        }
Esempio n. 2
0
        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();

            // 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++)
                {
                    Y.data[i] = B.get(i, colB);
                }

                // Solve Q*a=b => a = Q'*b
                CommonOps_FDRM.multTransA(Q, Y, x_basic);

                // 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]);
                }
            }
        }
        public override bool setA(FMatrixRMaj A)
        {
            _setA(A);

            if (!decomposition.decompose(A))
            {
                return(false);
            }

            rank = decomposition.getRank();

            R.reshape(numRows, numCols);
            decomposition.getR(R, false);

            // extract the r11 triangle sub matrix
            R11.reshape(rank, rank);
            CommonOps_FDRM.extract(R, 0, rank, 0, rank, R11, 0, 0);

            if (norm2Solution && rank < numCols)
            {
                // extract the R12 sub-matrix
                W.reshape(rank, numCols - rank);
                CommonOps_FDRM.extract(R, 0, rank, rank, numCols, W, 0, 0);

                // W=inv(R11)*R12
                TriangularSolver_FDRM.solveU(R11.data, 0, R11.numCols, R11.numCols, W.data, 0, W.numCols, W.numCols);

                // set the identity matrix in the upper portion
                W.reshape(numCols, W.numCols, true);

                for (int i = 0; i < numCols - rank; i++)
                {
                    for (int j = 0; j < numCols - rank; j++)
                    {
                        if (i == j)
                        {
                            W.set(i + rank, j, -1);
                        }
                        else
                        {
                            W.set(i + rank, j, 0);
                        }
                    }
                }
            }

            return(true);
        }
        /**
         * Performs QR decomposition on A
         *
         * @param A not modified.
         */
        public override bool setA(FMatrixRMaj A)
        {
            if (A.numRows < A.numCols)
            {
                throw new ArgumentException("Can't solve for wide systems.  More variables than equations.");
            }
            if (A.numRows > maxRows || A.numCols > maxCols)
            {
                setMaxSize(A.numRows, A.numCols);
            }

            R.reshape(A.numCols, A.numCols);
            a.reshape(A.numRows, 1);
            temp.reshape(A.numRows, 1);

            _setA(A);
            if (!decomposer.decompose(A))
            {
                return(false);
            }

            gammas = decomposer.getGammas();
            QR     = decomposer.getQR();
            decomposer.getR(R, true);
            return(true);
        }
        private void solveEigenvectorDuplicateEigenvalue(float real, int first, bool isTriangle)
        {
            float scale = Math.Abs(real);

            if (scale == 0)
            {
                scale = 1;
            }

            eigenvectorTemp.reshape(N, 1, false);
            eigenvectorTemp.zero();

            if (first > 0)
            {
                if (isTriangle)
                {
                    solveUsingTriangle(real, first, eigenvectorTemp);
                }
                else
                {
                    solveWithLU(real, first, eigenvectorTemp);
                }
            }

            eigenvectorTemp.reshape(N, 1, false);

            for (int i = first; i < N; i++)
            {
                Complex_F32 c = _implicit.eigenvalues[N - i - 1];

                if (c.isReal() && Math.Abs(c.real - real) / scale < 100.0f * UtilEjml.F_EPS)
                {
                    eigenvectorTemp.data[i] = 1;

                    FMatrixRMaj v = new FMatrixRMaj(N, 1);
                    CommonOps_FDRM.multTransA(Q, eigenvectorTemp, v);
                    eigenvectors[N - i - 1] = v;
                    NormOps_FDRM.normalizeF(v);

                    eigenvectorTemp.data[i] = 0;
                }
            }
        }
        /**
         * Compute the A matrix from the Q and R matrices.
         *
         * @return The A matrix.
         */
        public override FMatrixRMaj getA()
        {
            if (A.data.Length < numRows * numCols)
            {
                A = new FMatrixRMaj(numRows, numCols);
            }
            A.reshape(numRows, numCols, false);
            CommonOps_FDRM.mult(Q, R, A);

            return(A);
        }
        public override void invert(FMatrixRMaj A_inv)
        {
            if (A_inv.numCols != numRows || A_inv.numRows != numCols)
            {
                throw new ArgumentException("Unexpected dimensions for A_inv");
            }

            I.reshape(numRows, numRows);
            CommonOps_FDRM.setIdentity(I);

            solve(I, A_inv);
        }
Esempio n. 8
0
        public override bool setA(FMatrixRMaj A)
        {
            if (!base.setA(A))
            {
                return(false);
            }

            Q.reshape(A.numRows, A.numRows);

            decomposition.getQ(Q, false);

            return(true);
        }
Esempio n. 9
0
        /**
         * Updates the Q matrix to take in account the inserted matrix.
         *
         * @param rowIndex where the matrix has been inserted.
         */
        private void updateInsertQ(int rowIndex)
        {
            Qm.set(Q);
            Q.reshape(m_m, m_m, false);

            for (int i = 0; i < rowIndex; i++)
            {
                for (int j = 0; j < m_m; j++)
                {
                    float sum = 0;
                    for (int k = 0; k < m; k++)
                    {
                        sum += Qm.data[i * m + k] * U_tran.data[j * m_m + k + 1];
                    }
                    Q.data[i * m_m + j] = sum;
                }
            }

            for (int j = 0; j < m_m; j++)
            {
                Q.data[rowIndex * m_m + j] = U_tran.data[j * m_m];
            }

            for (int i = rowIndex + 1; i < m_m; i++)
            {
                for (int j = 0; j < m_m; j++)
                {
                    float sum = 0;
                    for (int k = 0; k < m; k++)
                    {
                        sum += Qm.data[(i - 1) * m + k] * U_tran.data[j * m_m + k + 1];
                    }
                    Q.data[i * m_m + j] = sum;
                }
            }
        }
        public override /**/ double quality()
        {
            return(SpecializedOps_FDRM.qualityTriangular(R));
        }

        /**
         * <p>
         * Upgrades the basic solution to the optimal 2-norm solution.
         * </p>
         *
         * <pre>
         * First solves for 'z'
         *
         *       || x_b - P*[ R_11^-1 * R_12 ] * z ||2
         * min z ||         [ - I_{n-r}      ]     ||
         *
         * </pre>
         *
         * @param X basic solution, also output solution
         */
        protected void upgradeSolution(FMatrixRMaj X)
        {
            FMatrixRMaj z = Y; // recycle Y

            // compute the z which will minimize the 2-norm of X
            // because of the identity matrix tacked onto the end 'A' should never be singular
            if (!internalSolver.setA(W))
            {
                throw new InvalidOperationException("This should never happen.  Is input NaN?");
            }
            z.reshape(numCols - rank, 1);
            internalSolver.solve(X, z);

            // compute X by tweaking the original
            CommonOps_FDRM.multAdd(-1, W, z, X);
        }
Esempio n. 11
0
        private void init(FMatrixRBlock orig)
        {
            this.A = orig;

            int height = Math.Min(A.blockLength, A.numRows);

            V.reshape(height, A.numCols, A.blockLength, false);
            tmp.reshape(height, A.numCols, A.blockLength, false);

            if (gammas.Length < A.numCols)
            {
                gammas = new float[A.numCols];
            }

            zerosM.reshape(A.blockLength, A.blockLength + 1, false);
        }
Esempio n. 12
0
        /**
         * Performs QR decomposition on A
         *
         * @param A not modified.
         */
        public override bool setA(FMatrixRMaj A)
        {
            if (A.numRows > maxRows || A.numCols > maxCols)
            {
                setMaxSize(A.numRows, A.numCols);
            }

            _setA(A);
            if (!decomposer.decompose(A))
            {
                return(false);
            }

            Q.reshape(numRows, numRows, false);
            R.reshape(numRows, numCols, false);
            decomposer.getQ(Q, false);
            decomposer.getR(R, false);

            return(true);
        }
Esempio n. 13
0
        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");
            }
            else if (B.numRows != numRows || B.numCols != X.numCols)
            {
                throw new ArgumentException("Unexpected dimensions for B");
            }

            int BnumCols = B.numCols;

            Y.reshape(numRows, 1, false);
            Z.reshape(numRows, 1, false);

            // 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++)
                {
                    Y.data[i] = B.get(i, colB);
                }

                // Solve Qa=b
                // a = Q'b
                CommonOps_FDRM.multTransA(Q, Y, Z);

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

                // save the results
                for (int i = 0; i < numCols; i++)
                {
                    X.set(i, colB, Z.data[i]);
                }
            }
        }
        private void solveWithLU(float real, int index, FMatrixRMaj r)
        {
            FMatrixRMaj A = new FMatrixRMaj(index, index);

            CommonOps_FDRM.extract(_implicit.A, 0, index, 0, index, A, 0, 0);

            for (int i = 0; i < index; i++)
            {
                A.add(i, i, -real);
            }

            r.reshape(index, 1, false);

            SpecializedOps_FDRM.subvector(_implicit.A, 0, index, index, false, 0, r);
            CommonOps_FDRM.changeSign(r);

            // TODO this must be very inefficient
            if (!solver.setA(A))
            {
                throw new InvalidOperationException("Solve failed");
            }
            solver.solve(r, r);
        }
        /**
         * If needed declares and sets up internal data structures.
         *
         * @param A Matrix being decomposed.
         */
        public void init(FMatrixRMaj A)
        {
            if (A.numRows != A.numCols)
            {
                throw new ArgumentException("Must be square");
            }

            if (A.numCols != N)
            {
                N = A.numCols;
                QT.reshape(N, N, false);

                if (w.Length < N)
                {
                    w      = new float[N];
                    gammas = new float[N];
                    b      = new float[N];
                }
            }

            // just copy the top right triangle
            QT.set(A);
        }
Esempio n. 16
0
        /**
         * <p>
         * Adjusts the values of the Q and R matrices to take in account the effects of removing
         * a row from the 'A' matrix at the specified location.  This operation requires about 6mn + O(n) flops.
         * </p>
         *
         * <p>
         * The adjustment is done by computing a series of planar Givens rotations that make the removed row in Q
         * equal to [1 0 ... 0].
         * </p>
         *
         * @param Q The Q matrix.  Is modified.
         * @param R The R matrix.  Is modified.
         * @param rowIndex Which index of the row that is being removed.
         * @param resizeR should the shape of R be adjusted?
         */
        public void deleteRow(FMatrixRMaj Q, FMatrixRMaj R, int rowIndex, bool resizeR)
        {
            setQR(Q, R, 0);
            if (m - 1 < n)
            {
                throw new ArgumentException("Removing any row would make the system under determined.");
            }

            m_m = m - 1;
            U_tran.reshape(m, m, false);

            if (resizeR)
            {
                R.reshape(m_m, n, false);
            }

            computeRemoveGivens(rowIndex);
            updateRemoveQ(rowIndex);

            updateRemoveR();

            // discard the reference since it is no longer needed
            this.Q = this.R = null;
        }
        /**
         * <p>
         * Performs Choleksy decomposition on the provided matrix.
         * </p>
         *
         * <p>
         * If the matrix is not positive definite then this function will return
         * false since it can't complete its computations.  Not all errors will be
         * found.
         * </p>
         * @return True if it was able to finish the decomposition.
         */
        protected override bool decomposeLower()
        {
            if (n < blockWidth)
            {
                B.reshape(0, 0, false);
            }
            else
            {
                B.reshape(blockWidth, n - blockWidth, false);
            }

            int numBlocks = n / blockWidth;
            int remainder = n % blockWidth;

            if (remainder > 0)
            {
                numBlocks++;
            }

            B.numCols = n;

            for (int i = 0; i < numBlocks; i++)
            {
                B.numCols -= blockWidth;

                if (B.numCols > 0)
                {
                    // apply cholesky to the current block
                    if (!chol.decompose(T, (i * blockWidth) * T.numCols + i * blockWidth, blockWidth))
                    {
                        return(false);
                    }

                    int indexSrc = i * blockWidth * T.numCols + (i + 1) * blockWidth;
                    int indexDst = (i + 1) * blockWidth * T.numCols + i * blockWidth;

                    // B = L^(-1) * B
                    solveL_special(chol.getL().data, T, indexSrc, indexDst, B);

                    int indexL = (i + 1) * blockWidth * n + (i + 1) * blockWidth;

                    // c = c - a^T*a
                    symmRankTranA_sub(B, T, indexL);
                }
                else
                {
                    int width = remainder > 0 ? remainder : blockWidth;
                    if (!chol.decompose(T, (i * blockWidth) * T.numCols + i * blockWidth, width))
                    {
                        return(false);
                    }
                }
            }


            // zero the top right corner.
            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                {
                    t[i * n + j] = 0.0f;
                }
            }

            return(true);
        }
        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]);
                }
            }
        }