예제 #1
0
        /**
         * <p>
         * Checks to see if a matrix is orthogonal or isometric.
         * </p>
         *
         * @param Q The matrix being tested. Not modified.
         * @param tol Tolerance.
         * @return True if it passes the test.
         */
        public static bool isOrthogonal(DMatrixRMaj Q, double tol)
        {
            if (Q.numRows < Q.numCols)
            {
                throw new ArgumentException("The number of rows must be more than or equal to the number of columns");
            }

            DMatrixRMaj[] u = CommonOps_DDRM.columnsToVector(Q, null);

            for (int i = 0; i < u.Length; i++)
            {
                DMatrixRMaj a = u[i];

                for (int j = i + 1; j < u.Length; j++)
                {
                    double val = VectorVectorMult_DDRM.innerProd(a, u[j]);

                    if (!(Math.Abs(val) <= tol))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #2
0
        /**
         * <p>
         * Given matrix A and an eigen vector of A, compute the corresponding eigen value.  This is
         * the Rayleigh quotient.<br>
         * <br>
         * x<sup>T</sup>Ax / x<sup>T</sup>x
         * </p>
         *
         *
         * @param A Matrix. Not modified.
         * @param eigenVector An eigen vector of A. Not modified.
         * @return The corresponding eigen value.
         */
        public static double computeEigenValue(DMatrixRMaj A, DMatrixRMaj eigenVector)
        {
            double bottom = VectorVectorMult_DDRM.innerProd(eigenVector, eigenVector);
            double top    = VectorVectorMult_DDRM.innerProdA(eigenVector, A, eigenVector);

            return(top / bottom);
        }
예제 #3
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 DMatrixRMaj[] 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");
            }

            DMatrixRMaj[] u = new DMatrixRMaj[numVectors];

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

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

                for (int j = 0; j < i; j++)
                {
//                Console.WriteLine("j = "+j);
                    if (j == 0)
                    {
                        r = RandomMatrices_DDRM.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_DDRM.householder(-2.0, u[j], r, a);
                    CommonOps_DDRM.add(r, a, a);
                    CommonOps_DDRM.scale(0.5, a);

//                UtilEjml.print(a);

                    DMatrixRMaj t = a;
                    a = r;
                    r = t;

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

                u[i] = r;
            }

            return(u);
        }
예제 #4
0
        /// <summary>
        /// Computes the dot product (a.k.a. inner product) between this vector and vector 'v'.
        /// </summary>
        /// <param name="v">The second vector in the dot product.  Not modified.</param>
        public override double dot(SimpleMatrixD v)
        {
            if (!isVector())
            {
                throw new ArgumentException("'this' matrix is not a vector.");
            }
            else if (!v.isVector())
            {
                throw new ArgumentException("'v' matrix is not a vector.");
            }

            var vm = v.getMatrix();

            return(VectorVectorMult_DDRM.innerProd(mat, vm));
        }
예제 #5
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 DEigenpair computeEigenVector(DMatrixRMaj A, double eigenvalue)
        {
            if (A.numRows != A.numCols)
            {
                throw new ArgumentException("Must be a square matrix.");
            }

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

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

            CommonOps_DDRM.fill(b, 1);

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

            double origEigenvalue = eigenvalue;

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

            double threshold = NormOps_DDRM.normPInf(A) * UtilEjml.EPS;

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

            LinearSolverDense <DMatrixRMaj> solver = LinearSolverFactory_DDRM.linear(M.numRows);

            double perp = 0.0001;

            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_DDRM.hasUncountable(x))
                {
                    failed = true;
                }

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

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

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

                    // compute the residual
                    CommonOps_DDRM.mult(M, b, x);
                    double error = NormOps_DDRM.normPInf(x);

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

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

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

            return(null);
        }