Beispiel #1
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);
        }
Beispiel #2
0
        /**
         * <p>
         * The vector associated will the smallest singular value is returned as the null space
         * of the decomposed system.  A right null space is returned if 'isRight' is set to true,
         * and a left null space if false.
         * </p>
         *
         * @param svd A precomputed decomposition.  Not modified.
         * @param isRight true for right null space and false for left null space.  Right is more commonly used.
         * @param nullVector Optional storage for a vector for the null space.  Modified.
         * @return Vector in V associated with smallest singular value..
         */
        public static FMatrixRMaj nullVector(SingularValueDecomposition_F32 <FMatrixRMaj> svd,
                                             bool isRight,
                                             FMatrixRMaj nullVector)
        {
            int N = svd.numberOfSingularValues();

            float[] s = svd.getSingularValues();

            FMatrixRMaj A = isRight ? svd.getV(null, true) : svd.getU(null, false);

            if (isRight)
            {
                if (A.numRows != svd.numCols())
                {
                    throw new ArgumentException(
                              "Can't compute the null space using a compact SVD for a matrix of this size.");
                }

                if (nullVector == null)
                {
                    nullVector = new FMatrixRMaj(svd.numCols(), 1);
                }
            }
            else
            {
                if (A.numCols != svd.numRows())
                {
                    throw new ArgumentException(
                              "Can't compute the null space using a compact SVD for a matrix of this size.");
                }

                if (nullVector == null)
                {
                    nullVector = new FMatrixRMaj(svd.numRows(), 1);
                }
            }

            int smallestIndex = -1;

            if (isRight && svd.numCols() > svd.numRows())
            {
                smallestIndex = svd.numCols() - 1;
            }
            else if (!isRight && svd.numCols() < svd.numRows())
            {
                smallestIndex = svd.numRows() - 1;
            }
            else
            {
                // find the smallest singular value
                float smallestValue = float.MaxValue;

                for (int i = 0; i < N; i++)
                {
                    if (s[i] < smallestValue)
                    {
                        smallestValue = s[i];
                        smallestIndex = i;
                    }
                }
            }

            // extract the null space
            if (isRight)
            {
                SpecializedOps_FDRM.subvector(A, smallestIndex, 0, A.numRows, true, 0, nullVector);
            }
            else
            {
                SpecializedOps_FDRM.subvector(A, 0, smallestIndex, A.numRows, false, 0, nullVector);
            }

            return(nullVector);
        }