Example #1
0
        private static void swapRowOrCol(FMatrixRMaj M, bool tran, int i, int bigIndex)
        {
            float tmp;

            if (tran)
            {
                // swap the rows
                for (int col = 0; col < M.numCols; col++)
                {
                    tmp = M.get(i, col);
                    M.set(i, col, M.get(bigIndex, col));
                    M.set(bigIndex, col, tmp);
                }
            }
            else
            {
                // swap the columns
                for (int row = 0; row < M.numRows; row++)
                {
                    tmp = M.get(row, i);
                    M.set(row, i, M.get(row, bigIndex));
                    M.set(row, bigIndex, tmp);
                }
            }
        }
Example #2
0
        /**
         * <p>
         * Adjusts the matrices so that the singular values are in descending order.
         * </p>
         *
         * <p>
         * In most implementations of SVD the singular values are automatically arranged in in descending
         * order.  In EJML this is not the case since it is often not needed and some computations can
         * be saved by not doing that.
         * </p>
         *
         * @param U Matrix. Modified.
         * @param tranU is U transposed or not.
         * @param W Diagonal matrix with singular values. Modified.
         * @param V Matrix. Modified.
         * @param tranV is V transposed or not.
         */
        // TODO the number of copies can probably be reduced here
        public static void descendingOrder(FMatrixRMaj U, bool tranU,
                                           FMatrixRMaj W,
                                           FMatrixRMaj V, bool tranV)
        {
            int numSingular = Math.Min(W.numRows, W.numCols);

            checkSvdMatrixSize(U, tranU, W, V, tranV);

            for (int i = 0; i < numSingular; i++)
            {
                float bigValue = -1;
                int   bigIndex = -1;

                // find the smallest singular value in the submatrix
                for (int j = i; j < numSingular; j++)
                {
                    float v = W.get(j, j);

                    if (v > bigValue)
                    {
                        bigValue = v;
                        bigIndex = j;
                    }
                }

                // only swap if the current index is not the smallest
                if (bigIndex == i)
                {
                    continue;
                }

                if (bigIndex == -1)
                {
                    // there is at least one uncountable singular value.  just stop here
                    break;
                }

                float tmp = W.get(i, i);
                W.set(i, i, bigValue);
                W.set(bigIndex, bigIndex, tmp);

                if (V != null)
                {
                    swapRowOrCol(V, tranV, i, bigIndex);
                }

                if (U != null)
                {
                    swapRowOrCol(U, tranU, i, bigIndex);
                }
            }
        }
        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);
        }
Example #4
0
        /**
         * <p>
         * Puts all the real eigenvectors into the columns of a matrix.  If an eigenvalue is imaginary
         * then the corresponding eigenvector will have zeros in its column.
         * </p>
         *
         * @param eig An eigenvalue decomposition which has already decomposed a matrix.
         * @return An m by m matrix containing eigenvectors in its columns.
         */
        public static FMatrixRMaj createMatrixV(EigenDecomposition_F32 <FMatrixRMaj> eig)
        {
            int N = eig.getNumberOfEigenvalues();

            FMatrixRMaj V = new FMatrixRMaj(N, N);

            for (int i = 0; i < N; i++)
            {
                Complex_F32 c = eig.getEigenvalue(i);

                if (c.isReal())
                {
                    FMatrixRMaj v = eig.getEigenVector(i);

                    if (v != null)
                    {
                        for (int j = 0; j < N; j++)
                        {
                            V.set(j, i, v.get(j, 0));
                        }
                    }
                }
            }

            return(V);
        }
        /**
         * Makes a draw on the distribution.  The results are added to parameter 'x'
         */
        public void next(FMatrixRMaj x)
        {
            for (int i = 0; i < r.numRows; i++)
            {
                r.set(i, 0, (float)rand.NextGaussian());
            }

            CommonOps_FDRM.multAdd(A, r, x);
        }
        /**
         * Extracts the tridiagonal matrix found in the decomposition.
         *
         * @param T If not null then the results will be stored here.  Otherwise a new matrix will be created.
         * @return The extracted T matrix.
         */
        public FMatrixRMaj getT(FMatrixRMaj T)
        {
            T = UtilDecompositons_FDRM.checkZeros(T, N, N);

            T.data[0] = QT.data[0];
            T.data[1] = QT.data[1];


            for (int i = 1; i < N - 1; i++)
            {
                T.set(i, i, QT.get(i, i));
                T.set(i, i + 1, QT.get(i, i + 1));
                T.set(i, i - 1, QT.get(i - 1, i));
            }

            T.data[(N - 1) * N + N - 1] = QT.data[(N - 1) * N + N - 1];
            T.data[(N - 1) * N + N - 2] = QT.data[(N - 2) * N + N - 1];

            return(T);
        }
Example #7
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]);
                }
            }
        }
Example #8
0
        /**
         * Sets the provided square matrix to be a random symmetric matrix whose values are selected from an uniform distribution
         * from min to max, inclusive.
         *
         * @param A The matrix that is to be modified.  Must be square.  Modified.
         * @param min Minimum value an element can have.
         * @param max Maximum value an element can have.
         * @param rand Random number generator.
         */
        public static void symmetric(FMatrixRMaj A, float min, float max, IMersenneTwister rand)
        {
            if (A.numRows != A.numCols)
            {
                throw new ArgumentException("A must be a square matrix");
            }

            float range = max - min;

            int length = A.numRows;

            for (int i = 0; i < length; i++)
            {
                for (int j = i; j < length; j++)
                {
                    float val = rand.NextFloat() * range + min;
                    A.set(i, j, val);
                    A.set(j, i, val);
                }
            }
        }
Example #9
0
        /**
         * <p>
         * Creates a randomly generated set of orthonormal vectors.  At most it can generate the same
         * number of vectors as the dimension of the vectors.
         * </p>
         *
         * <p>
         * This is done by creating random vectors then ensuring that they are orthogonal
         * to all the ones previously created with reflectors.
         * </p>
         *
         * <p>
         * NOTE: This employs a brute force O(N<sup>3</sup>) algorithm.
         * </p>
         *
         * @param dimen dimension of the space which the vectors will span.
         * @param numVectors How many vectors it should generate.
         * @param rand Used to create random vectors.
         * @return Array of N random orthogonal vectors of unit length.
         */
        // is there a faster algorithm out there? This one is a bit sluggish
        public static FMatrixRMaj[] span(int dimen, int numVectors, IMersenneTwister rand)
        {
            if (dimen < numVectors)
            {
                throw new ArgumentException("The number of vectors must be less than or equal to the dimension");
            }

            FMatrixRMaj[] u = new FMatrixRMaj[numVectors];

            u[0] = RandomMatrices_FDRM.rectangle(dimen, 1, -1, 1, rand);
            NormOps_FDRM.normalizeF(u[0]);

            for (int i = 1; i < numVectors; i++)
            {
//            Console.WriteLine(" i = "+i);
                FMatrixRMaj a = new FMatrixRMaj(dimen, 1);
                FMatrixRMaj r = null;

                for (int j = 0; j < i; j++)
                {
//                Console.WriteLine("j = "+j);
                    if (j == 0)
                    {
                        r = RandomMatrices_FDRM.rectangle(dimen, 1, -1, 1, rand);
                    }

                    // find a vector that is normal to vector j
                    // u[i] = (1/2)*(r + Q[j]*r)
                    a.set(r);
                    VectorVectorMult_FDRM.householder(-2.0f, u[j], r, a);
                    CommonOps_FDRM.add(r, a, a);
                    CommonOps_FDRM.scale(0.5f, a);

//                UtilEjml.print(a);

                    FMatrixRMaj t = a;
                    a = r;
                    r = t;

                    // normalize it so it doesn't get too small
                    float val = NormOps_FDRM.normF(r);
                    if (val == 0 || float.IsNaN(val) || float.IsInfinity(val))
                    {
                        throw new InvalidOperationException("Failed sanity check");
                    }
                    CommonOps_FDRM.divide(r, val);
                }

                u[i] = r;
            }

            return(u);
        }
Example #10
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;
                }
            }
        }
Example #11
0
        /**
         * Multiplied a transpose orthogonal matrix Q by the specified rotator.  This is used
         * to update the U and V matrices.  Updating the transpose of the matrix is faster
         * since it only modifies the rows.
         *
         *
         * @param Q Orthogonal matrix
         * @param m Coordinate of rotator.
         * @param n Coordinate of rotator.
         * @param c cosine of rotator.
         * @param s sine of rotator.
         */
        protected void updateRotator(FMatrixRMaj Q, int m, int n, float c, float s)
        {
            int rowA = m * Q.numCols;
            int rowB = n * Q.numCols;

//        for( int i = 0; i < Q.numCols; i++ ) {
//            float a = Q.get(rowA+i);
//            float b = Q.get(rowB+i);
//            Q.set( rowA+i, c*a + s*b);
//            Q.set( rowB+i, -s*a + c*b);
//        }
//        Console.WriteLine("------ AFter Update Rotator "+m+" "+n);
//        Q.print();
//        Console.WriteLine();
            int endA = rowA + Q.numCols;

            for (; rowA != endA; rowA++, rowB++)
            {
                float a = Q.get(rowA);
                float b = Q.get(rowB);
                Q.set(rowA, c * a + s * b);
                Q.set(rowB, -s * a + c * b);
            }
        }
Example #12
0
        /**
         * <p>
         * Computes the F norm of the difference between the two Matrices:<br>
         * <br>
         * Sqrt{&sum;<sub>i=1:m</sub> &sum;<sub>j=1:n</sub> ( a<sub>ij</sub> - b<sub>ij</sub>)<sup>2</sup>}
         * </p>
         * <p>
         * This is often used as a cost function.
         * </p>
         *
         * @see NormOps_FDRM#fastNormF
         *
         * @param a m by n matrix. Not modified.
         * @param b m by n matrix. Not modified.
         *
         * @return The F normal of the difference matrix.
         */
        public static float diffNormF(FMatrixD1 a, FMatrixD1 b)
        {
            if (a.numRows != b.numRows || a.numCols != b.numCols)
            {
                throw new ArgumentException("Both matrices must have the same shape.");
            }

            int size = a.getNumElements();

            FMatrixRMaj diff = new FMatrixRMaj(size, 1);

            for (int i = 0; i < size; i++)
            {
                diff.set(i, b.get(i) - a.get(i));
            }
            return(NormOps_FDRM.normF(diff));
        }
Example #13
0
        /**
         * Creates a random vector that is inside the specified span.
         *
         * @param span The span the random vector belongs in.
         * @param rand RNG
         * @return A random vector within the specified span.
         */
        public static FMatrixRMaj insideSpan(FMatrixRMaj[] span, float min, float max, IMersenneTwister rand)
        {
            FMatrixRMaj A = new FMatrixRMaj(span.Length, 1);

            FMatrixRMaj B = new FMatrixRMaj(span[0].getNumElements(), 1);

            for (int i = 0; i < span.Length; i++)
            {
                B.set(span[i]);
                float val = rand.NextFloat() * (max - min) + min;
                CommonOps_FDRM.scale(val, B);

                CommonOps_FDRM.add(A, B, A);
            }

            return(A);
        }
Example #14
0
        /**
         * <p>
         * A diagonal matrix where real diagonal element contains a real eigenvalue.  If an eigenvalue
         * is imaginary then zero is stored in its place.
         * </p>
         *
         * @param eig An eigenvalue decomposition which has already decomposed a matrix.
         * @return A diagonal matrix containing the eigenvalues.
         */
        public static FMatrixRMaj createMatrixD(EigenDecomposition_F32 <FMatrixRMaj> eig)
        {
            int N = eig.getNumberOfEigenvalues();

            FMatrixRMaj D = new FMatrixRMaj(N, N);

            for (int i = 0; i < N; i++)
            {
                Complex_F32 c = eig.getEigenvalue(i);

                if (c.isReal())
                {
                    D.set(i, i, c.real);
                }
            }

            return(D);
        }
        private void createMinor(FMatrix1Row mat)
        {
            int w        = minWidth - 1;
            int firstRow = (width - w) * width;

            for (int i = 0; i < numOpen; i++)
            {
                int col      = open[i];
                int srcIndex = firstRow + col;
                int dstIndex = i;

                for (int j = 0; j < w; j++)
                {
                    tempMat.set(dstIndex, mat.get(srcIndex));
                    dstIndex += w;
                    srcIndex += width;
                }
            }
        }
        private void initPower(FMatrixRMaj A)
        {
            if (A.numRows != A.numCols)
            {
                throw new ArgumentException("A must be a square matrix.");
            }

            if (seed != null)
            {
                q0.set(seed);
            }
            else
            {
                for (int i = 0; i < A.numRows; i++)
                {
                    q0.data[i] = 1;
                }
            }
        }
Example #17
0
        /**
         * Creates a random symmetric positive definite matrix.
         *
         * @param width The width of the square matrix it returns.
         * @param rand Random number generator used to make the matrix.
         * @return The random symmetric  positive definite matrix.
         */
        public static FMatrixRMaj symmetricPosDef(int width, IMersenneTwister rand)
        {
            // This is not formally proven to work.  It just seems to work.
            FMatrixRMaj a = new FMatrixRMaj(width, 1);
            FMatrixRMaj b = new FMatrixRMaj(width, width);

            for (int i = 0; i < width; i++)
            {
                a.set(i, 0, rand.NextFloat());
            }

            CommonOps_FDRM.multTransB(a, a, b);

            for (int i = 0; i < width; i++)
            {
                b.add(i, i, 1);
            }

            return(b);
        }
Example #18
0
        /**
         * Creates a random matrix where all elements are zero but diagonal elements.  Diagonal elements
         * randomly drawn from a uniform distribution from min to max, inclusive.
         *
         * @param numRows Number of rows in the returned matrix..
         * @param numCols Number of columns in the returned matrix.
         * @param min Minimum value of a diagonal element.
         * @param max Maximum value of a diagonal element.
         * @param rand Random number generator.
         * @return A random diagonal matrix.
         */
        public static FMatrixRMaj diagonal(int numRows, int numCols, float min, float max, IMersenneTwister rand)
        {
            if (max < min)
            {
                throw new ArgumentException("The max must be >= the min");
            }

            FMatrixRMaj ret = new FMatrixRMaj(numRows, numCols);

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

            float r = max - min;

            for (int i = 0; i < N; i++)
            {
                ret.set(i, i, rand.NextFloat() * r + min);
            }

            return(ret);
        }
Example #19
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]);
                }
            }
        }
        /**
         * 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);
        }
Example #21
0
        /**
         * Creates an upper triangular matrix whose values are selected from a uniform distribution.  If hessenberg
         * is greater than zero then a hessenberg matrix of the specified degree is created instead.
         *
         * @param dimen Number of rows and columns in the matrix..
         * @param hessenberg 0 for triangular matrix and &gt; 0 for hessenberg matrix.
         * @param min minimum value an element can be.
         * @param max maximum value an element can be.
         * @param rand random number generator used.
         * @return The randomly generated matrix.
         */
        public static FMatrixRMaj triangularUpper(int dimen, int hessenberg, float min, float max,
                                                  IMersenneTwister rand)
        {
            if (hessenberg < 0)
            {
                throw new InvalidOperationException("hessenberg must be more than or equal to 0");
            }

            float range = max - min;

            FMatrixRMaj A = new FMatrixRMaj(dimen, dimen);

            for (int i = 0; i < dimen; i++)
            {
                int start = i <= hessenberg ? 0 : i - hessenberg;

                for (int j = start; j < dimen; j++)
                {
                    A.set(i, j, rand.NextFloat() * range + min);
                }
            }

            return(A);
        }
Example #22
0
        /**
         * <p>
         * Creates a random matrix which will have the provided singular values.  The length of sv
         * is assumed to be the rank of the matrix.  This can be useful for testing purposes when one
         * needs to ensure that a matrix is not singular but randomly generated.
         * </p>
         *
         * @param numRows Number of rows in generated matrix.
         * @param numCols NUmber of columns in generated matrix.
         * @param rand Random number generator.
         * @param sv Singular values of the matrix.
         * @return A new matrix with the specified singular values.
         */
        public static FMatrixRMaj singleValues(int numRows, int numCols,
                                               IMersenneTwister rand, float[] sv)
        {
            FMatrixRMaj U = RandomMatrices_FDRM.orthogonal(numRows, numRows, rand);
            FMatrixRMaj V = RandomMatrices_FDRM.orthogonal(numCols, numCols, rand);

            FMatrixRMaj S = new FMatrixRMaj(numRows, numCols);

            int min = Math.Min(numRows, numCols);

            min = Math.Min(min, sv.Length);

            for (int i = 0; i < min; i++)
            {
                S.set(i, i, sv[i]);
            }

            FMatrixRMaj tmp = new FMatrixRMaj(numRows, numCols);

            CommonOps_FDRM.mult(U, S, tmp);
            CommonOps_FDRM.multTransB(tmp, V, S);

            return(S);
        }
Example #23
0
        /**
         * Give a string of numbers it returns a DenseMatrix
         */
        public static FMatrixRMaj parse_FDRM(string s, int numColumns)
        {
            string[] vals = s.Split('+');

            // there is the possibility the first element could be empty
            int start = string.IsNullOrEmpty(vals[0]) ? 1 : 0;

            // covert it from string to doubles
            int numRows = (vals.Length - start) / numColumns;

            FMatrixRMaj ret = new FMatrixRMaj(numRows, numColumns);

            int index = start;

            for (int i = 0; i < numRows; i++)
            {
                for (int j = 0; j < numColumns; j++)
                {
                    ret.set(i, j, float.Parse(vals[index++]));
                }
            }

            return(ret);
        }
Example #24
0
        /**
         * <p>
         * Given an eigenvalue it computes an eigenvector using inverse iteration:
         * <br>
         * for i=1:MAX {<br>
         *   (A - &mu;I)z<sup>(i)</sup> = q<sup>(i-1)</sup><br>
         *   q<sup>(i)</sup> = z<sup>(i)</sup> / ||z<sup>(i)</sup>||<br>
         * &lambda;<sup>(i)</sup> =  q<sup>(i)</sup><sup>T</sup> A  q<sup>(i)</sup><br>
         * }<br>
         * </p>
         * <p>
         * NOTE: If there is another eigenvalue that is very similar to the provided one then there
         * is a chance of it converging towards that one instead.  The larger a matrix is the more
         * likely this is to happen.
         * </p>
         * @param A Matrix whose eigenvector is being computed.  Not modified.
         * @param eigenvalue The eigenvalue in the eigen pair.
         * @return The eigenvector or null if none could be found.
         */
        public static FEigenpair computeEigenVector(FMatrixRMaj A, float eigenvalue)
        {
            if (A.numRows != A.numCols)
            {
                throw new ArgumentException("Must be a square matrix.");
            }

            FMatrixRMaj M = new FMatrixRMaj(A.numRows, A.numCols);

            FMatrixRMaj x = new FMatrixRMaj(A.numRows, 1);
            FMatrixRMaj b = new FMatrixRMaj(A.numRows, 1);

            CommonOps_FDRM.fill(b, 1);

            // perturb the eigenvalue slightly so that its not an exact solution the first time
//        eigenvalue -= eigenvalue*UtilEjml.F_EPS*10;

            float origEigenvalue = eigenvalue;

            SpecializedOps_FDRM.addIdentity(A, M, -eigenvalue);

            float threshold = NormOps_FDRM.normPInf(A) * UtilEjml.F_EPS;

            float prevError = float.MaxValue;
            bool  hasWorked = false;

            LinearSolverDense <FMatrixRMaj> solver = LinearSolverFactory_FDRM.linear(M.numRows);

            float perp = 0.0001f;

            for (int i = 0; i < 200; i++)
            {
                bool failed = false;
                // if the matrix is singular then the eigenvalue is within machine precision
                // of the true value, meaning that x must also be.
                if (!solver.setA(M))
                {
                    failed = true;
                }
                else
                {
                    solver.solve(b, x);
                }

                // see if solve silently failed
                if (MatrixFeatures_FDRM.hasUncountable(x))
                {
                    failed = true;
                }

                if (failed)
                {
                    if (!hasWorked)
                    {
                        // if it failed on the first trial try perturbing it some more
                        float val = i % 2 == 0 ? 1.0f - perp : 1.0f + perp;
                        // maybe this should be turn into a parameter allowing the user
                        // to configure the wise of each step

                        eigenvalue = origEigenvalue * (float)Math.Pow(val, i / 2 + 1);
                        SpecializedOps_FDRM.addIdentity(A, M, -eigenvalue);
                    }
                    else
                    {
                        // otherwise assume that it was so accurate that the matrix was singular
                        // and return that result
                        return(new FEigenpair(eigenvalue, b));
                    }
                }
                else
                {
                    hasWorked = true;

                    b.set(x);
                    NormOps_FDRM.normalizeF(b);

                    // compute the residual
                    CommonOps_FDRM.mult(M, b, x);
                    float error = NormOps_FDRM.normPInf(x);

                    if (error - prevError > UtilEjml.F_EPS * 10)
                    {
                        // if the error increased it is probably converging towards a different
                        // eigenvalue
//                    CommonOps.set(b,1);
                        prevError = float.MaxValue;
                        hasWorked = false;
                        float val = i % 2 == 0 ? 1.0f - perp : 1.0f + perp;
                        eigenvalue = origEigenvalue * (float)Math.Pow(val, 1);
                    }
                    else
                    {
                        // see if it has converged
                        if (error <= threshold || Math.Abs(prevError - error) <= UtilEjml.F_EPS)
                        {
                            return(new FEigenpair(eigenvalue, b));
                        }

                        // update everything
                        prevError  = error;
                        eigenvalue = VectorVectorMult_FDRM.innerProdA(b, A, b);
                    }

                    SpecializedOps_FDRM.addIdentity(A, M, -eigenvalue);
                }
            }

            return(null);
        }
Example #25
0
        public bool bulgeDoubleStepQn(int i,
                                      float a11, float a21, float a31,
                                      float threshold, bool set)
        {
            float max;

            if (normalize)
            {
                float absA11 = Math.Abs(a11);
                float absA21 = Math.Abs(a21);
                float absA31 = Math.Abs(a31);

                max = absA11 > absA21 ? absA11 : absA21;
                if (absA31 > max)
                {
                    max = absA31;
                }

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

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

            // compute the reflector using the b's above

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

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

            float div = a11 + tau;

            u.set(i, 0, 1);
            u.set(i + 1, 0, a21 / div);
            u.set(i + 2, 0, a31 / 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 + 3, _temp.data);

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

            if (printHumps)
            {
                Console.WriteLine("  After Q.   A =");
                A.print();
            }

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

//        Console.WriteLine("  after Q*A*Q ");
//        A.print();

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

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