/**
         * <p>
         * A = (I + W Y<sup>T</sup>)<sup>T</sup>A<BR>
         * A = A + Y (W<sup>T</sup>A)<BR>
         * <br>
         * where A is a submatrix of the input matrix.
         * </p>
         */
        protected void updateA(FSubmatrixD1 A)
        {
            setW();

            A.row0 = Y.row0;
            A.row1 = Y.row1;
            A.col0 = Y.col1;
            A.col1 = Y.original.numCols;

            WTA.row0 = 0;
            WTA.col0 = 0;
            WTA.row1 = W.col1 - W.col0;
            WTA.col1 = A.col1 - A.col0;
            WTA.original.reshape(WTA.row1, WTA.col1, false);

            if (A.col1 > A.col0)
            {
                BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0);

                MatrixMult_FDRB.multTransA(blockLength, W, A, WTA);
                BlockHouseHolder_FDRB.multAdd_zeros(blockLength, Y, WTA, A);
            }
            else if (saveW)
            {
                BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0);
            }
        }
        public virtual bool decompose(FMatrixRBlock orig)
        {
            setup(orig);

            int m = Math.Min(orig.numCols, orig.numRows);

            // process the matrix one column block at a time and overwrite the input matrix
            for (int j = 0; j < m; j += blockLength)
            {
                Y.col0 = j;
                Y.col1 = Math.Min(orig.numCols, Y.col0 + blockLength);
                Y.row0 = j;

                // compute the QR decomposition of the left most block column
                // this overwrites the original input matrix
                if (!BlockHouseHolder_FDRB.decomposeQR_block_col(blockLength, Y, gammas))
                {
                    return(false);
                }

                // Update the remainder of the matrix using the reflectors just computed
                updateA(A);
            }

            return(true);
        }
        /**
         * <p>
         * Computes the householder vector that is used to create reflector for the column.
         * The results are stored in the original matrix.
         * </p>
         *
         * <p>
         * The householder vector 'u' is computed as follows:<br>
         * <br>
         * u(1) = 1 <br>
         * u(i) = x(i)/(&tau; + x(1))<br>
         * </p>
         *
         * The first element is implicitly assumed to be one and not written.
         *
         * @return If there was any problems or not. true = no problem.
         */
        public static bool computeHouseHolderCol(int blockLength, FSubmatrixD1 Y,
                                                 float[] gamma, int i)
        {
            float max = BlockHouseHolder_FDRB.findMaxCol(blockLength, Y, i);

            if (max == 0.0f)
            {
                return(false);
            }
            else
            {
                // computes tau and normalizes u by max
                float tau = computeTauAndDivideCol(blockLength, Y, i, max);

                // divide u by u_0
                float u_0 = Y.get(i, i) + tau;
                divideElementsCol(blockLength, Y, i, u_0);

                gamma[Y.col0 + i] = u_0 / tau;
                tau *= max;

                // after the reflector is applied the column would be all zeros but be -tau in the first element
                Y.set(i, i, -tau);
            }
            return(true);
        }
        /**
         * <p>
         * Computes the householder vector from the specified row
         * </p>
         *
         * <p>
         * The householder vector 'u' is computed as follows:<br>
         * <br>
         * u(1) = 1 <br>
         * u(i) = x(i)/(&tau; + x(1))<br>
         * </p>
         *
         * The first element is implicitly assumed to be one and not written.
         *
         * @return If there was any problems or not. true = no problem.
         */
        public static bool computeHouseHolderRow(int blockLength, FSubmatrixD1 Y,
                                                 float[] gamma, int i)
        {
            float max = BlockHouseHolder_FDRB.findMaxRow(blockLength, Y, i, i + 1);

            if (max == 0.0f)
            {
                return(false);
            }
            else
            {
                // computes tau and normalizes u by max
                float tau = computeTauAndDivideRow(blockLength, Y, i, i + 1, max);

                // divide u by u_0
                float u_0 = Y.get(i, i + 1) + tau;
                VectorOps_FDRB.div_row(blockLength, Y, i, u_0, Y, i, i + 1, Y.col1 - Y.col0);

                gamma[Y.row0 + i] = u_0 / tau;

                // after the reflector is applied the column would be all zeros but be -tau in the first element
                Y.set(i, i + 1, -tau * max);
            }
            return(true);
        }
        /**
         * Specialized version of applyQ() that allows the zeros in an identity matrix
         * to be taken advantage of depending on if isIdentity is true or not.
         *
         * @param B
         * @param isIdentity If B is an identity matrix.
         */
        public void applyQ(FMatrixRBlock B, bool isIdentity)
        {
            int minDimen = Math.Min(dataA.numCols, dataA.numRows);

            FSubmatrixD1 subB = new FSubmatrixD1(B);

            W.col0   = W.row0 = 0;
            Y.row1   = W.row1 = dataA.numRows;
            WTA.row0 = WTA.col0 = 0;

            int start = minDimen - minDimen % blockLength;

            if (start == minDimen)
            {
                start -= blockLength;
            }
            if (start < 0)
            {
                start = 0;
            }

            // (Q1^T * (Q2^T * (Q3^t * A)))
            for (int i = start; i >= 0; i -= blockLength)
            {
                Y.col0 = i;
                Y.col1 = Math.Min(Y.col0 + blockLength, dataA.numCols);
                Y.row0 = i;
                if (isIdentity)
                {
                    subB.col0 = i;
                }
                subB.row0 = i;

                setW();
                WTA.row1 = Y.col1 - Y.col0;
                WTA.col1 = subB.col1 - subB.col0;
                WTA.original.reshape(WTA.row1, WTA.col1, false);

                // Compute W matrix from reflectors stored in Y
                if (!saveW)
                {
                    BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0);
                }

                // Apply the Qi to Q
                BlockHouseHolder_FDRB.multTransA_vecCol(blockLength, Y, subB, WTA);
                MatrixMult_FDRB.multPlus(blockLength, W, WTA, subB);
            }
        }
        /**
         * <p>
         * Multiplies the provided matrix by Q<sup>T</sup> using householder reflectors.  This is more
         * efficient that computing Q then applying it to the matrix.
         * </p>
         *
         * <p>
         * Q = Q*(I - &gamma; W*Y^T)<br>
         * QR = A &ge; R = Q^T*A  = (Q3^T * (Q2^T * (Q1^t * A)))
         * </p>
         *
         * @param B Matrix which Q is applied to.  Modified.
         */
        public void applyQTran(FMatrixRBlock B)
        {
            int minDimen = Math.Min(dataA.numCols, dataA.numRows);

            FSubmatrixD1 subB = new FSubmatrixD1(B);

            W.col0   = W.row0 = 0;
            Y.row1   = W.row1 = dataA.numRows;
            WTA.row0 = WTA.col0 = 0;

            // (Q3^T * (Q2^T * (Q1^t * A)))
            for (int i = 0; i < minDimen; i += blockLength)
            {
                Y.col0 = i;
                Y.col1 = Math.Min(Y.col0 + blockLength, dataA.numCols);
                Y.row0 = i;

                subB.row0 = i;
//            subB.row1 = B.numRows;
//            subB.col0 = 0;
//            subB.col1 = B.numCols;

                setW();
//            W.original.reshape(W.row1,W.col1,false);
                WTA.row0 = 0;
                WTA.col0 = 0;
                WTA.row1 = W.col1 - W.col0;
                WTA.col1 = subB.col1 - subB.col0;
                WTA.original.reshape(WTA.row1, WTA.col1, false);

                // Compute W matrix from reflectors stored in Y
                if (!saveW)
                {
                    BlockHouseHolder_FDRB.computeW_Column(blockLength, Y, W, temp, gammas, Y.col0);
                }

                // Apply the Qi to Q
                MatrixMult_FDRB.multTransA(blockLength, W, subB, WTA);
                BlockHouseHolder_FDRB.multAdd_zeros(blockLength, Y, WTA, subB);
            }
        }