/** * <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 - γ 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 - γ u u<sup>T</sup><br> * γ = 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); }
/** * <p> * Computes the Frobenius matrix norm:<br> * <br> * normF = Sqrt{ ∑<sub>i=1:m</sub> ∑<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)); }