/**
         * <p>
         * Creates a pivot matrix that exchanges the rows in a matrix:
         * <br>
         * A' = P*A<br>
         * </p>
         * <p>
         * For example, if element 0 in 'pivots' is 2 then the first row in A' will be the 3rd row in A.
         * </p>
         *
         * @param ret If null then a new matrix is declared otherwise the results are written to it.  Is modified.
         * @param pivots Specifies the new order of rows in a matrix.
         * @param numPivots How many elements in pivots are being used.
         * @param transposed If the transpose of the matrix is returned.
         * @return A pivot matrix.
         */
        public static ZMatrixRMaj pivotMatrix(ZMatrixRMaj ret, int[] pivots, int numPivots, bool transposed)
        {
            if (ret == null)
            {
                ret = new ZMatrixRMaj(numPivots, numPivots);
            }
            else
            {
                if (ret.numCols != numPivots || ret.numRows != numPivots)
                {
                    throw new ArgumentException("Unexpected matrix dimension");
                }
                CommonOps_ZDRM.fill(ret, 0, 0);
            }

            if (transposed)
            {
                for (int i = 0; i < numPivots; i++)
                {
                    ret.set(pivots[i], i, 1, 0);
                }
            }
            else
            {
                for (int i = 0; i < numPivots; i++)
                {
                    ret.set(i, pivots[i], 1, 0);
                }
            }

            return(ret);
        }
        /**
         * Computes the householder vector used in QR decomposition.
         *
         * u = x / max(x)
         * u(0) = u(0) + |u|
         * u = u / u(0)
         *
         * @param x Input vector.  Unmodified.
         * @return The found householder reflector vector
         */
        public static ZMatrixRMaj householderVector(ZMatrixRMaj x)
        {
            ZMatrixRMaj u = (ZMatrixRMaj)x.copy();

            double max = CommonOps_ZDRM.elementMaxAbs(u);

            CommonOps_ZDRM.elementDivide(u, max, 0, u);

            double      nx = NormOps_ZDRM.normF(u);
            Complex_F64 c  = new Complex_F64();

            u.get(0, 0, c);

            double realTau, imagTau;

            if (c.getMagnitude() == 0)
            {
                realTau = nx;
                imagTau = 0;
            }
            else
            {
                realTau = c.real / c.getMagnitude() * nx;
                imagTau = c.imaginary / c.getMagnitude() * nx;
            }

            u.set(0, 0, c.real + realTau, c.imaginary + imagTau);
            CommonOps_ZDRM.elementDivide(u, u.getReal(0, 0), u.getImag(0, 0), u);

            return(u);
        }
        /**
         * <p>
         * Creates a reflector from the provided vector and gamma.<br>
         * <br>
         * Q = I - &gamma; u u<sup>H</sup><br>
         * </p>
         *
         * @param u A vector.  Not modified.
         * @param gamma To produce a reflector gamma needs to be equal to 2/||u||.
         * @return An orthogonal reflector.
         */
        public static ZMatrixRMaj createReflector(ZMatrixRMaj u, double gamma)
        {
            if (!MatrixFeatures_ZDRM.isVector(u))
            {
                throw new ArgumentException("u must be a vector");
            }

            ZMatrixRMaj Q = CommonOps_ZDRM.identity(u.getNumElements());

            CommonOps_ZDRM.multAddTransB(-gamma, 0, u, u, Q);

            return(Q);
        }
        /**
         * <p>
         * Creates a reflector from the provided vector.<br>
         * <br>
         * Q = I - &gamma; u u<sup>T</sup><br>
         * &gamma; = 2/||u||<sup>2</sup>
         * </p>
         *
         * @param u A vector. Not modified.
         * @return An orthogonal reflector.
         */
        public static ZMatrixRMaj createReflector(ZMatrixRMaj u)
        {
            if (!MatrixFeatures_ZDRM.isVector(u))
            {
                throw new ArgumentException("u must be a vector");
            }

            double norm  = NormOps_ZDRM.normF(u);
            double gamma = -2.0 / (norm * norm);

            ZMatrixRMaj Q = CommonOps_ZDRM.identity(u.getNumElements());

            CommonOps_ZDRM.multAddTransB(gamma, 0, u, u, Q);

            return(Q);
        }
        /**
         * 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 ZMatrixRMaj hermitianPosDef(int width, IMersenneTwister rand)
        {
            // This is not formally proven to work.  It just seems to work.
            ZMatrixRMaj a = RandomMatrices_ZDRM.rectangle(width, 1, rand);
            ZMatrixRMaj b = new ZMatrixRMaj(1, width);
            ZMatrixRMaj c = new ZMatrixRMaj(width, width);

            CommonOps_ZDRM.transposeConjugate(a, b);
            CommonOps_ZDRM.mult(a, b, c);

            for (int i = 0; i < width; i++)
            {
                c.data[2 * (i * width + i)] += 1;
            }

            return(c);
        }
        /**
         * Q = I - gamma*u*u<sup>H</sup>
         */
        public static ZMatrixRMaj householder(ZMatrixRMaj u, double gamma)
        {
            int N = u.getDataLength() / 2;
            // u*u^H
            ZMatrixRMaj uut = new ZMatrixRMaj(N, N);

            VectorVectorMult_ZDRM.outerProdH(u, u, uut);
            // foo = -gamma*u*u^H
            CommonOps_ZDRM.elementMultiply(uut, -gamma, 0, uut);

            // I + foo
            for (int i = 0; i < N; i++)
            {
                int index = (i * uut.numCols + i) * 2;
                uut.data[index] = 1 + uut.data[index];
            }

            return(uut);
        }
        /**
         * <p>
         * Unitary matrices have the following properties:<br><br>
         * Q*Q<sup>H</sup> = I
         * </p>
         * <p>
         * This is the complex equivalent of orthogonal matrix.
         * </p>
         * @param Q The matrix being tested. Not modified.
         * @param tol Tolerance.
         * @return True if it passes the test.
         */
        public static bool isUnitary(ZMatrixRMaj 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");
            }

            Complex_F64 prod = new Complex_F64();

            ZMatrixRMaj[] u = CommonOps_ZDRM.columnsToVector(Q, null);

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

                VectorVectorMult_ZDRM.innerProdH(a, a, prod);

                if (Math.Abs(prod.real - 1) > tol)
                {
                    return(false);
                }
                if (Math.Abs(prod.imaginary) > tol)
                {
                    return(false);
                }

                for (int j = i + 1; j < u.Length; j++)
                {
                    VectorVectorMult_ZDRM.innerProdH(a, u[j], prod);

                    if (!(prod.getMagnitude2() <= tol * tol))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Exemple #8
0
        /**
         * <p>
         * Computes the Frobenius matrix norm:<br>
         * <br>
         * normF = Sqrt{  &sum;<sub>i=1:m</sub> &sum;<sub>j=1:n</sub> { a<sub>ij</sub><sup>2</sup>}   }
         * </p>
         * <p>
         * This is equivalent to the element wise p=2 norm.
         * </p>
         *
         * @param a The matrix whose norm is computed.  Not modified.
         * @return The norm's value.
         */
        public static double normF(ZMatrixRMaj a)
        {
            double total = 0;

            double scale = CommonOps_ZDRM.elementMaxAbs(a);

            if (scale == 0.0)
            {
                return(0.0);
            }

            int size = a.getDataLength();

            for (int i = 0; i < size; i += 2)
            {
                double real = a.data[i] / scale;
                double imag = a.data[i + 1] / scale;

                total += real * real + imag * imag;
            }

            return(scale * Math.Sqrt(total));
        }