예제 #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(DMatrixRMaj Q, DMatrixRMaj R, double[] 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;
        }
        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();

            // 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_DDRM.multTransA(Q, Y, x_basic);

                // 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]);
                }
            }
        }
예제 #3
0
        public override bool setA(DMatrixRMaj 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_DDRM.extract(R, 0, rank, 0, rank, R11, 0, 0);

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

                // W=inv(R11)*R12
                TriangularSolver_DDRM.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);
        }
예제 #4
0
 /**
  * Creates a zeros matrix only if A does not already exist.  If it does exist it will fill
  * the lower triangular portion with zeros.
  */
 public static DMatrixRMaj checkZerosLT(DMatrixRMaj A, int numRows, int numCols)
 {
     if (A == null)
     {
         return(new DMatrixRMaj(numRows, numCols));
     }
     else if (numRows != A.numRows || numCols != A.numCols)
     {
         A.reshape(numRows, numCols);
         A.zero();
     }
     else
     {
         for (int i = 0; i < A.numRows; i++)
         {
             int index = i * A.numCols;
             int end   = index + Math.Min(i, A.numCols);
             while (index < end)
             {
                 A.data[index++] = 0;
             }
         }
     }
     return(A);
 }
 /**
  * Must be called before any other functions. Declares and sets up internal data structures.
  *
  * @param numSamples Number of samples that will be processed.
  * @param sampleSize Number of elements in each sample.
  */
 public void setup(int numSamples, int sampleSize)
 {
     mean = new double[sampleSize];
     A.reshape(numSamples, sampleSize, false);
     sampleIndex   = 0;
     numComponents = -1;
 }
예제 #6
0
        /**
         * Computes the best fit set of polynomial coefficients to the provided observations.
         *
         * @param samplePoints where the observations were sampled.
         * @param observations A set of observations.
         */
        public void fit(double[] samplePoints, double[] observations)
        {
            // Create a copy of the observations and put it into a matrix
            y.reshape(observations.Length, 1, false);
            Array.Copy(observations, 0, y.data, 0, observations.Length);

            // reshape the matrix to avoid unnecessarily declaring new memory
            // save values is set to false since its old values don't matter
            A.reshape(y.numRows, coef.numRows, false);

            // set up the A matrix
            for (int i = 0; i < observations.Length; i++)
            {
                double obs = 1;

                for (int j = 0; j < coef.numRows; j++)
                {
                    A.set(i, j, obs);
                    obs *= samplePoints[i];
                }
            }

            // process the A matrix and see if it failed
            if (!solver.setA(A))
            {
                throw new InvalidOperationException("Solver failed");
            }

            // solver the the coefficients
            solver.solve(y, coef);
        }
예제 #7
0
        /**
         * Converts {@link DMatrixRBlock} into {@link DMatrixRMaj}
         *
         * @param src Input matrix.
         * @param dst Output matrix.  If null a new matrix will be declared.
         * @return Converted matrix.
         */
        public static DMatrixRMaj convert(DMatrixRBlock src, DMatrixRMaj dst)
        {
            if (dst != null)
            {
                dst.reshape(src.NumRows, src.NumCols);
            }
            else
            {
                dst = new DMatrixRMaj(src.numRows, src.numCols);
            }

            for (int i = 0; i < src.numRows; i += src.blockLength)
            {
                int blockHeight = Math.Min(src.blockLength, src.numRows - i);

                for (int j = 0; j < src.numCols; j += src.blockLength)
                {
                    int blockWidth = Math.Min(src.blockLength, src.numCols - j);

                    int indexSrc    = i * src.numCols + blockHeight * j;
                    int indexDstRow = i * dst.numCols + j;

                    for (int k = 0; k < blockHeight; k++)
                    {
                        System.Array.Copy(src.data, indexSrc, dst.data, indexDstRow, blockWidth);
                        indexSrc    += blockWidth;
                        indexDstRow += dst.numCols;
                    }
                }
            }

            return(dst);
        }
        /**
         * Performs QR decomposition on A
         *
         * @param A not modified.
         */
        public override bool setA(DMatrixRMaj 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);
        }
        /**
         * Computes a basis (the principal components) from the most dominant eigenvectors.
         *
         * @param numComponents Number of vectors it will use to describe the data.  Typically much
         * smaller than the number of elements in the input vector.
         */
        public void computeBasis(int numComponents)
        {
            if (numComponents > A.getNumCols())
            {
                throw new ArgumentException("More components requested that the data's length.");
            }
            if (sampleIndex != A.getNumRows())
            {
                throw new ArgumentException("Not all the data has been added");
            }
            if (numComponents > sampleIndex)
            {
                throw new ArgumentException("More data needed to compute the desired number of components");
            }

            this.numComponents = numComponents;

            // compute the mean of all the samples
            for (int i = 0; i < A.getNumRows(); i++)
            {
                for (int j = 0; j < mean.Length; j++)
                {
                    mean[j] += A.get(i, j);
                }
            }
            for (int j = 0; j < mean.Length; j++)
            {
                mean[j] /= A.getNumRows();
            }

            // subtract the mean from the original data
            for (int i = 0; i < A.getNumRows(); i++)
            {
                for (int j = 0; j < mean.Length; j++)
                {
                    A.set(i, j, A.get(i, j) - mean[j]);
                }
            }

            // Compute SVD and save time by not computing U
            SingularValueDecomposition <DMatrixRMaj> svd =
                DecompositionFactory_DDRM.svd(A.numRows, A.numCols, false, true, false);

            if (!svd.decompose(A))
            {
                throw new InvalidOperationException("SVD failed");
            }

            V_t = svd.getV(null, true);
            DMatrixRMaj W = svd.getW(null);

            // Singular values are in an arbitrary order initially
            SingularOps_DDRM.descendingOrder(null, false, W, V_t, true);

            // strip off unneeded components and find the basis
            V_t.reshape(numComponents, mean.Length, true);
        }
예제 #10
0
 public static DMatrixRMaj ensureZeros(DMatrixRMaj A, int numRows, int numCols)
 {
     if (A == null)
     {
         return(new DMatrixRMaj(numRows, numCols));
     }
     A.reshape(numRows, numCols);
     A.zero();
     return(A);
 }
        private void solveEigenvectorDuplicateEigenvalue(double real, int first, bool isTriangle)
        {
            double 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_F64 c = _implicit.eigenvalues[N - i - 1];

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

                    DMatrixRMaj v = new DMatrixRMaj(N, 1);
                    CommonOps_DDRM.multTransA(Q, eigenvectorTemp, v);
                    eigenvectors[N - i - 1] = v;
                    NormOps_DDRM.normalizeF(v);

                    eigenvectorTemp.data[i] = 0;
                }
            }
        }
예제 #12
0
 public static DMatrixRMaj ensureIdentity(DMatrixRMaj A, int numRows, int numCols)
 {
     if (A == null)
     {
         return(CommonOps_DDRM.identity(numRows, numCols));
     }
     A.reshape(numRows, numCols);
     CommonOps_DDRM.setIdentity(A);
     return(A);
 }
예제 #13
0
        /**
         * Compute the A matrix from the Q and R matrices.
         *
         * @return The A matrix.
         */
        public override DMatrixRMaj getA()
        {
            if (A.data.Length < numRows * numCols)
            {
                A = new DMatrixRMaj(numRows, numCols);
            }
            A.reshape(numRows, numCols, false);
            CommonOps_DDRM.mult(Q, R, A);

            return(A);
        }
예제 #14
0
        public override void invert(DMatrixRMaj A_inv)
        {
            if (A_inv.numCols != numRows || A_inv.numRows != numCols)
            {
                throw new ArgumentException("Unexpected dimensions for A_inv");
            }

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

            solve(I, A_inv);
        }
        public override bool setA(DMatrixRMaj A)
        {
            if (!base.setA(A))
            {
                return(false);
            }

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

            decomposition.getQ(Q, false);

            return(true);
        }
예제 #16
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++)
                {
                    double 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++)
                {
                    double 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;
                }
            }
        }
        private void init(DMatrixRBlock 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 double[A.numCols];
            }

            zerosM.reshape(A.blockLength, A.blockLength + 1, false);
        }
예제 #18
0
        public override /**/ double quality()
        {
            return(SpecializedOps_DDRM.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(DMatrixRMaj X)
        {
            DMatrixRMaj 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_DDRM.multAdd(-1, W, z, X);
        }
예제 #19
0
        protected void setToRequiredSize(DMatrixRMaj matrix)
        {
            int         matrixRow = 0;
            int         matrixCol = 0;
            List <Item> row       = new List <Item>();

            for (int i = 0; i < items.Count; i++)
            {
                Item item = items[i];

                if (item.endRow)
                {
                    Item v       = row[0];
                    int  numRows = v.getRows();
                    int  numCols = v.getColumns();
                    for (int j = 1; j < row.Count; j++)
                    {
                        v = row[j];
                        if (v.getRows() != numRows)
                        {
                            throw new InvalidOperationException("Row miss-matched. " + numRows + " " + v.getRows());
                        }
                        numCols += v.getColumns();
                    }
                    matrixRow += numRows;

                    if (matrixCol == 0)
                    {
                        matrixCol = numCols;
                    }
                    else if (matrixCol != numCols)
                    {
                        throw new ParseError("Row " + matrixRow + " has an unexpected number of columns; expected = " +
                                             matrixCol + " found = " + numCols);
                    }

                    row.Clear();
                }
                else
                {
                    row.Add(item);
                }
            }

            matrix.reshape(matrixRow, matrixCol);
        }
예제 #20
0
        /**
         * Performs QR decomposition on A
         *
         * @param A not modified.
         */
        public override bool setA(DMatrixRMaj 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);
        }
예제 #21
0
        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");
            }
            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_DDRM.multTransA(Q, Y, Z);

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

                // save the results
                for (int i = 0; i < numCols; i++)
                {
                    X.set(i, colB, Z.data[i]);
                }
            }
        }
        /**
         * If needed declares and sets up internal data structures.
         *
         * @param A Matrix being decomposed.
         */
        public void init(DMatrixRMaj 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 double[N];
                    gammas = new double[N];
                    b      = new double[N];
                }
            }

            // just copy the top right triangle
            QT.set(A);
        }
        private void solveWithLU(double real, int index, DMatrixRMaj r)
        {
            DMatrixRMaj A = new DMatrixRMaj(index, index);

            CommonOps_DDRM.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_DDRM.subvector(_implicit.A, 0, index, index, false, 0, r);
            CommonOps_DDRM.changeSign(r);

            // TODO this must be very inefficient
            if (!solver.setA(A))
            {
                throw new InvalidOperationException("Solve failed");
            }
            solver.solve(r, r);
        }
예제 #24
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(DMatrixRMaj Q, DMatrixRMaj 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.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]);
                }
            }
        }
예제 #27
0
        /**
         * Computes the QR decomposition of the provided matrix.
         *
         * @param A Matrix which is to be decomposed.  Not modified.
         */
        public void decompose(DMatrixRMaj A)
        {
            this.QR = (DMatrixRMaj)A.copy();

            int N = Math.Min(A.numCols, A.numRows);

            gammas = new double[A.numCols];

            DMatrixRMaj A_small = new DMatrixRMaj(A.numRows, A.numCols);
            DMatrixRMaj A_mod   = new DMatrixRMaj(A.numRows, A.numCols);
            DMatrixRMaj v       = new DMatrixRMaj(A.numRows, 1);
            DMatrixRMaj Q_k     = new DMatrixRMaj(A.numRows, A.numRows);

            for (int i = 0; i < N; i++)
            {
                // reshape temporary variables
                A_small.reshape(QR.numRows - i, QR.numCols - i, false);
                A_mod.reshape(A_small.numRows, A_small.numCols, false);
                v.reshape(A_small.numRows, 1, false);
                Q_k.reshape(v.getNumElements(), v.getNumElements(), false);

                // use extract matrix to get the column that is to be zeroed
                CommonOps_DDRM.extract(QR, i, QR.numRows, i, i + 1, v, 0, 0);

                double max = CommonOps_DDRM.elementMaxAbs(v);

                if (max > 0 && v.getNumElements() > 1)
                {
                    // normalize to reduce overflow issues
                    CommonOps_DDRM.divide(v, max);

                    // compute the magnitude of the vector
                    double tau = NormOps_DDRM.normF(v);

                    if (v.get(0) < 0)
                    {
                        tau *= -1.0;
                    }

                    double u_0   = v.get(0) + tau;
                    double gamma = u_0 / tau;

                    CommonOps_DDRM.divide(v, u_0);
                    v.set(0, 1.0);

                    // extract the submatrix of A which is being operated on
                    CommonOps_DDRM.extract(QR, i, QR.numRows, i, QR.numCols, A_small, 0, 0);

                    // A = (I - &gamma;*u*u<sup>T</sup>)A
                    CommonOps_DDRM.setIdentity(Q_k);
                    CommonOps_DDRM.multAddTransB(-gamma, v, v, Q_k);
                    CommonOps_DDRM.mult(Q_k, A_small, A_mod);

                    // save the results
                    CommonOps_DDRM.insert(A_mod, QR, i, i);
                    CommonOps_DDRM.insert(v, QR, i, i);
                    QR.unsafe_set(i, i, -tau * max);

                    // save gamma for recomputing Q later on
                    gammas[i] = gamma;
                }
            }
        }