/** * Extracts the column of A and copies it into u while computing the magnitude of the * largest element and returning it. * * <pre> * u[ (offsetU+row0+i)*2 ] = A.getReal(row0+i,col) * u[ (offsetU+row0+i)*2 + 1] = A.getImag(row0+i,col) * </pre> * * @param A Complex matrix * @param row0 First row in A to be copied * @param row1 Last row in A + 1 to be copied * @param col Column in A * @param u Output array storage * @param offsetU first index in U * @return magnitude of largest element */ public static float extractColumnAndMax(CMatrixRMaj A, int row0, int row1, int col, float[] u, int offsetU) { int indexU = (offsetU + row0) * 2; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow float max = 0; int indexA = A.getIndex(row0, col); float[] h = A.data; for (int i = row0; i < row1; i++, indexA += A.numCols * 2) { // copy the householder vector to an array to reduce cache misses // big improvement on larger matrices and a relatively small performance hit on small matrices. float realVal = u[indexU++] = h[indexA]; float imagVal = u[indexU++] = h[indexA + 1]; float magVal = realVal * realVal + imagVal * imagVal; if (max < magVal) { max = magVal; } } return((float)Math.Sqrt(max)); }
/** * <p>Hermitian matrix is a square matrix with complex entries that are equal to its own conjugate transpose.</p> * * <p>a[i,j] = conj(a[j,i])</p> * * @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static bool isHermitian(CMatrixRMaj Q, float tol) { if (Q.numCols != Q.numRows) { return(false); } Complex_F32 a = new Complex_F32(); Complex_F32 b = new Complex_F32(); for (int i = 0; i < Q.numCols; i++) { for (int j = i; j < Q.numCols; j++) { Q.get(i, j, a); Q.get(j, i, b); if (Math.Abs(a.real - b.real) > tol) { return(false); } if (Math.Abs(a.imaginary + b.imaginary) > tol) { return(false); } } } return(true); }
public static void squareConjugate(CMatrixRMaj mat) { int index = 2; int rowStride = mat.getRowStride(); int indexEnd = rowStride; for (int i = 0; i < mat.numRows; i++, index += (i + 1) * 2, indexEnd += rowStride) { mat.data[index - 1] = -mat.data[index - 1]; int indexOther = (i + 1) * rowStride + i * 2; for (; index < indexEnd; index += 2, indexOther += rowStride) { float real = mat.data[index]; float img = mat.data[index + 1]; mat.data[index] = mat.data[indexOther]; mat.data[index + 1] = -mat.data[indexOther + 1]; mat.data[indexOther] = real; mat.data[indexOther + 1] = -img; } } }
/** * Performs QR decomposition on A * * @param A not modified. */ //@Override public override bool setA(CMatrixRMaj A) { if (A.numRows < A.numCols) { throw new ArgumentException("Can't solve for wide systems. More variables than equations."); } if (A.numRows > maxRows || A.numCols > maxCols) { setMaxSize(A.numRows, A.numCols); } R.reshape(A.numCols, A.numCols); a.reshape(A.numRows, 1); temp.reshape(A.numRows, 1); _setA(A); if (!decomposer.decompose(A)) { return(false); } gammas = decomposer.getGammas(); QR = decomposer.getQR(); decomposer.getR(R, true); return(true); }
/** * Creates a zeros matrix only if A does not already exist. If it does exist it will fill * the upper triangular portion with zeros. */ public static CMatrixRMaj checkZerosUT(CMatrixRMaj A, int numRows, int numCols) { if (A == null) { return(new CMatrixRMaj(numRows, numCols)); } else if (numRows != A.numRows || numCols != A.numCols) { throw new ArgumentException("Input is not " + numRows + " x " + numCols + " matrix"); } else { int maxRows = Math.Min(A.numRows, A.numCols); for (int i = 0; i < maxRows; i++) { int index = (i * A.numCols + i + 1) * 2; int end = (i * A.numCols + A.numCols) * 2; while (index < end) { A.data[index++] = 0; } } } return(A); }
/** * <p> * Computes the inner product between a vector and the conjugate of another one. * <br> * <br> * ∑<sub>k=1:n</sub> x<sub>k</sub> * conj(y<sub>k</sub>)<br> * where x and y are vectors with n elements. * </p> * * <p> * These functions are often used inside of highly optimized code and therefor sanity checks are * kept to a minimum. It is not recommended that any of these functions be used directly. * </p> * * @param x A vector with n elements. Not modified. * @param y A vector with n elements. Not modified. * @return The inner product of the two vectors. */ public static Complex_F32 innerProdH(CMatrixRMaj x, CMatrixRMaj y, Complex_F32 output) { if (output == null) { output = new Complex_F32(); } else { output.real = output.imaginary = 0; } int m = x.getDataLength(); for (int i = 0; i < m; i += 2) { float realX = x.data[i]; float imagX = x.data[i + 1]; float realY = y.data[i]; float imagY = -y.data[i + 1]; output.real += realX * realY - imagX * imagY; output.imaginary += realX * imagY + imagX * realY; } return(output); }
/** * <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 CMatrixRMaj pivotMatrix(CMatrixRMaj ret, int[] pivots, int numPivots, bool transposed) { if (ret == null) { ret = new CMatrixRMaj(numPivots, numPivots); } else { if (ret.numCols != numPivots || ret.numRows != numPivots) { throw new ArgumentException("Unexpected matrix dimension"); } CommonOps_CDRM.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); }
public override /**/ double quality() { return(SpecializedOps_CDRM.qualityTriangular(decomposer._getT())); } /** * <p> * Using the decomposition, finds the value of 'X' in the linear equation below:<br> * * A*x = b<br> * * where A has dimension of n by n, x and b are n by m dimension. * </p> * <p> * *Note* that 'b' and 'x' can be the same matrix instance. * </p> * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is writen to. Modified. */ //@Override public override void solve(CMatrixRMaj B, CMatrixRMaj X) { if (B.numCols != X.numCols || B.numRows != n || X.numRows != n) { throw new ArgumentException("Unexpected matrix size"); } int numCols = B.numCols; float[] dataB = B.data; float[] dataX = X.data; if (decomposer.isLower()) { for (int j = 0; j < numCols; j++) { for (int i = 0; i < n; i++) { vv[i * 2] = dataB[(i * numCols + j) * 2]; vv[i * 2 + 1] = dataB[(i * numCols + j) * 2 + 1]; } solveInternalL(); for (int i = 0; i < n; i++) { dataX[(i * numCols + j) * 2] = vv[i * 2]; dataX[(i * numCols + j) * 2 + 1] = vv[i * 2 + 1]; } } } else { throw new InvalidOperationException("Implement"); } }
/** * 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 CMatrixRMaj householderVector(CMatrixRMaj x) { CMatrixRMaj u = (CMatrixRMaj)x.copy(); float max = CommonOps_CDRM.elementMaxAbs(u); CommonOps_CDRM.elementDivide(u, max, 0, u); float nx = NormOps_CDRM.normF(u); Complex_F32 c = new Complex_F32(); u.get(0, 0, c); float 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_CDRM.elementDivide(u, u.getReal(0, 0), u.getImag(0, 0), u); return(u); }
/** * Computes the quality of a triangular matrix, where the quality of a matrix * is defined in {@link LinearSolverDense#quality()}. In * this situation the quality is the magnitude of the product of * each diagonal element divided by the magnitude of the largest diagonal element. * If all diagonal elements are zero then zero is returned. * * @return the quality of the system. */ public static float qualityTriangular(CMatrixRMaj T) { int N = Math.Min(T.numRows, T.numCols); float max = elementDiagMaxMagnitude2(T); if (max == 0.0f) { return(0.0f); } max = (float)Math.Sqrt(max); int rowStride = T.getRowStride(); float qualityR = 1.0f; float qualityI = 0.0f; for (int i = 0; i < N; i++) { int index = i * rowStride + i * 2; float real = T.data[index] / max; float imaginary = T.data[index] / max; float r = qualityR * real - qualityI * imaginary; float img = qualityR * imaginary + real * qualityI; qualityR = r; qualityI = img; } return((float)Math.Sqrt(qualityR * qualityR + qualityI * qualityI)); }
//@Override public override void invert(CMatrixRMaj A_inv) { float[] vv = decomp._getVV(); CMatrixRMaj LU = decomp.getLU(); if (A_inv.numCols != LU.numCols || A_inv.numRows != LU.numRows) { throw new ArgumentException("Unexpected matrix dimension"); } int n = A.numCols; float[] dataInv = A_inv.data; int strideAinv = A_inv.getRowStride(); for (int j = 0; j < n; j++) { // don't need to change inv into an identity matrix before hand Array.Clear(vv, 0, n * 2); vv[j * 2] = 1; vv[j * 2 + 1] = 0; decomp._solveVectorInternal(vv); // for( int i = 0; i < n; i++ ) dataInv[i* n +j] = vv[i]; int index = j * 2; for (int i = 0; i < n; i++, index += strideAinv) { dataInv[index] = vv[i * 2]; dataInv[index + 1] = vv[i * 2 + 1]; } } }
/** * Creates a random Hermitian matrix with elements from min to max value. * * @param length Width and height of the matrix. * @param min Minimum value an element can have. * @param max Maximum value an element can have. * @param rand Random number generator. * @return A symmetric matrix. */ public static CMatrixRMaj hermitian(int length, float min, float max, IMersenneTwister rand) { CMatrixRMaj A = new CMatrixRMaj(length, length); fillHermitian(A, min, max, rand); return(A); }
/** * <p> * Returns a matrix where all the elements are selected independently from * a uniform distribution between 'min' and 'max' inclusive. * </p> * * @param numRow Number of rows in the new matrix. * @param numCol Number of columns in the new matrix. * @param min The minimum value each element can be. * @param max The maximum value each element can be. * @param rand Random number generator used to fill the matrix. * @return The randomly generated matrix. */ public static CMatrixRMaj rectangle(int numRow, int numCol, float min, float max, IMersenneTwister rand) { CMatrixRMaj mat = new CMatrixRMaj(numRow, numCol); fillUniform(mat, min, max, rand); return(mat); }
public override /**/ double quality() { return(SpecializedOps_CDRM.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. */ //@Override public override void solve(CMatrixRMaj B, CMatrixRMaj X) { if (X.numRows != numCols) { throw new ArgumentException("Unexpected dimensions for X: X rows = " + X.numRows + " expected = " + numCols); } else if (B.numRows != numRows || B.numCols != X.numCols) { throw new ArgumentException("Unexpected dimensions for B"); } int BnumCols = B.numCols; // 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++) { int indexB = (i * BnumCols + colB) * 2; a.data[i * 2] = B.data[indexB]; a.data[i * 2 + 1] = B.data[indexB + 1]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for (int n = 0; n < numCols; n++) { float[] u = QR[n]; float realVV = u[n * 2]; float imagVV = u[n * 2 + 1]; u[n * 2] = 1; u[n * 2 + 1] = 0; QrHelperFunctions_CDRM.rank1UpdateMultR(a, u, 0, gammas[n], 0, n, numRows, temp.data); u[n * 2] = realVV; u[n * 2 + 1] = imagVV; } // solve for Rx = b using the standard upper triangular solver TriangularSolver_CDRM.solveU(R.data, a.data, numCols); // save the results for (int i = 0; i < numCols; i++) { int indexB = (i * BnumCols + colB) * 2; X.data[indexB] = a.data[i * 2]; X.data[indexB + 1] = a.data[i * 2 + 1]; } } }
/** * <p> * Performs the following operation:<br> * <br> * c = c + a<sup>H</sup> * b<sup>H</sup><br> * c<sub>ij</sub> = c<sub>ij</sub> + ∑<sub>k=1:n</sub> { a<sub>ki</sub> * b<sub>jk</sub>} * </p> * * @param a The left matrix in the multiplication operation. Not Modified. * @param b The right matrix in the multiplication operation. Not Modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB(CMatrixRMaj a, CMatrixRMaj b, CMatrixRMaj c) { if (a.numCols >= EjmlParameters.CMULT_TRANAB_COLUMN_SWITCH) { MatrixMatrixMult_CDRM.multAddTransAB_aux(a, b, c, null); } else { MatrixMatrixMult_CDRM.multAddTransAB(a, b, c); } }
public static void invert(LinearSolverDense <CMatrixRMaj> solver, CMatrixRMaj A, CMatrixRMaj A_inv) { if (A.numRows != A_inv.numRows || A.numCols != A_inv.numCols) { throw new ArgumentException("A and A_inv must have the same dimensions"); } CommonOps_CDRM.setIdentity(A_inv); solver.solve(A_inv, A_inv); }
/** * <p> * Creates an identity matrix of the specified size.<br> * <br> * a<sub>ij</sub> = 0+0i if i ≠ j<br> * a<sub>ij</sub> = 1+0i if i = j<br> * </p> * * @param width The width and height of the identity matrix. * @return A new instance of an identity matrix. */ public static CMatrixRMaj identity(int width) { CMatrixRMaj A = new CMatrixRMaj(width, width); for (int i = 0; i < width; i++) { A.set(i, i, 1, 0); } return(A); }
/** * <p> * Performs the following operation:<br> * <br> * c = c + α * a * b<br> * c<sub>ij</sub> = c<sub>ij</sub> + α * ∑<sub>k=1:n</sub> { a<sub>ik</sub> * b<sub>kj</sub>} * </p> * * @param realAlpha real component of scaling factor. * @param imgAlpha imaginary component of scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd(float realAlpha, float imgAlpha, CMatrixRMaj a, CMatrixRMaj b, CMatrixRMaj c) { if (b.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH) { MatrixMatrixMult_CDRM.multAdd_reorder(realAlpha, imgAlpha, a, b, c); } else { MatrixMatrixMult_CDRM.multAdd_small(realAlpha, imgAlpha, a, b, c); } }
/** * <p> * Performs the following operation:<br> * <br> * c = c + a * b<br> * c<sub>ij</sub> = c<sub>ij</sub> + ∑<sub>k=1:n</sub> { a<sub>ik</sub> * b<sub>kj</sub>} * </p> * * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd(CMatrixRMaj a, CMatrixRMaj b, CMatrixRMaj c) { if (b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) { MatrixMatrixMult_CDRM.multAdd_reorder(a, b, c); } else { MatrixMatrixMult_CDRM.multAdd_small(a, b, c); } }
/** * <p> * Performs the following operation:<br> * <br> * c = c + α * a<sup>H</sup> * b<sup>H</sup><br> * c<sub>ij</sub> = c<sub>ij</sub> + α * ∑<sub>k=1:n</sub> { a<sub>ki</sub> * b<sub>jk</sub>} * </p> * * @param realAlpha Real component of scaling factor. * @param imagAlpha Imaginary component of scaling factor. * @param a The left matrix in the multiplication operation. Not Modified. * @param b The right matrix in the multiplication operation. Not Modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB(float realAlpha, float imagAlpha, CMatrixRMaj a, CMatrixRMaj b, CMatrixRMaj c) { // TODO add a matrix vectory multiply here if (a.numCols >= EjmlParameters.CMULT_TRANAB_COLUMN_SWITCH) { MatrixMatrixMult_CDRM.multAddTransAB_aux(realAlpha, imagAlpha, a, b, c, null); } else { MatrixMatrixMult_CDRM.multAddTransAB(realAlpha, imagAlpha, a, b, c); } }
/** * <p>Performs the following operation:<br> * <br> * c = a<sup>H</sup> * b <br> * <br> * c<sub>ij</sub> = ∑<sub>k=1:n</sub> { a<sub>ki</sub> * b<sub>kj</sub>} * </p> * * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA(CMatrixRMaj a, CMatrixRMaj b, CMatrixRMaj c) { if (a.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH || b.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH) { MatrixMatrixMult_CDRM.multTransA_reorder(a, b, c); } else { MatrixMatrixMult_CDRM.multTransA_small(a, b, c); } }
/** * Changes the size of the matrix it can solve for * * @param maxRows Maximum number of rows in the matrix it will decompose. * @param maxCols Maximum number of columns in the matrix it will decompose. */ public void setMaxSize(int maxRows, int maxCols) { this.maxRows = maxRows; this.maxCols = maxCols; Q = new CMatrixRMaj(maxRows, maxRows); Qt = new CMatrixRMaj(maxRows, maxRows); R = new CMatrixRMaj(maxRows, maxCols); Y = new CMatrixRMaj(maxRows, 1); Z = new CMatrixRMaj(maxRows, 1); }
/** * <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 CMatrixRMaj createReflector(CMatrixRMaj u, float gamma) { if (!MatrixFeatures_CDRM.isVector(u)) { throw new ArgumentException("u must be a vector"); } CMatrixRMaj Q = CommonOps_CDRM.identity(u.getNumElements()); CommonOps_CDRM.multAddTransB(-gamma, 0, u, u, Q); return(Q); }
/** * <p> * Creates a matrix with diagonal elements set to 1 and the rest 0.<br> * <br> * a<sub>ij</sub> = 0+0i if i ≠ j<br> * a<sub>ij</sub> = 1+0i if i = j<br> * </p> * * @param width The width of the identity matrix. * @param height The height of the identity matrix. * @return A new instance of an identity matrix. */ public static CMatrixRMaj identity(int width, int height) { CMatrixRMaj A = new CMatrixRMaj(width, height); int m = Math.Min(width, height); for (int i = 0; i < m; i++) { A.set(i, i, 1, 0); } return(A); }
/** * Extracts a house holder vector from the rows of A and stores it in u * @param A Complex matrix with householder vectors stored in the upper right triangle * @param row Row in A * @param col0 first row in A (implicitly assumed to be r + i0) * @param col1 last row +1 in A * @param u Output array storage * @param offsetU first index in U */ public static void extractHouseholderRow(CMatrixRMaj A, int row, int col0, int col1, float[] u, int offsetU) { int indexU = (offsetU + col0) * 2; u[indexU] = 1; u[indexU + 1] = 0; int indexA = (row * A.numCols + (col0 + 1)) * 2; Array.Copy(A.data, indexA, u, indexU + 2, (col1 - col0 - 1) * 2); }
/** * <p> * Performs the following operation:<br> * <br> * c = c + α * a<sup>H</sup> * b<br> * c<sub>ij</sub> =c<sub>ij</sub> + α * ∑<sub>k=1:n</sub> { a<sub>ki</sub> * b<sub>kj</sub>} * </p> * * @param realAlpha Real component of scaling factor. * @param imagAlpha Imaginary component of scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA(float realAlpha, float imagAlpha, CMatrixRMaj a, CMatrixRMaj b, CMatrixRMaj c) { // TODO add a matrix vectory multiply here if (a.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH || b.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH) { MatrixMatrixMult_CDRM.multAddTransA_reorder(realAlpha, imagAlpha, a, b, c); } else { MatrixMatrixMult_CDRM.multAddTransA_small(realAlpha, imagAlpha, a, b, c); } }
/** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @param mat A square matrix. */ public static void setIdentity(CMatrixRMaj mat) { int width = mat.numRows < mat.numCols ? mat.numRows : mat.numCols; Array.Clear(mat.data, 0, mat.getDataLength()); int index = 0; int stride = mat.getRowStride(); for (int i = 0; i < width; i++, index += stride + 2) { mat.data[index] = 1; } }
/** * <p>Performs an "in-place" conjugate transpose.</p> * * @see #transpose(CMatrixRMaj) * * @param mat The matrix that is to be transposed. Modified. */ public static void transposeConjugate(CMatrixRMaj mat) { if (mat.numCols == mat.numRows) { TransposeAlgs_CDRM.squareConjugate(mat); } else { CMatrixRMaj b = new CMatrixRMaj(mat.numCols, mat.numRows); transposeConjugate(mat, b); mat.reshape(b.numRows, b.numCols); mat.set(b); } }
/** * <p> * Performs a matrix inversion operation on the specified matrix and stores the results * in the same matrix.<br> * <br> * a = a<sup>-1</sup> * </p> * * <p> * If the algorithm could not invert the matrix then false is returned. If it returns true * that just means the algorithm finished. The results could still be bad * because the matrix is singular or nearly singular. * </p> * * @param A The matrix that is to be inverted. Results are stored here. Modified. * @return true if it could invert the matrix false if it could not. */ public static bool invert(CMatrixRMaj A) { LinearSolverDense <CMatrixRMaj> solver = LinearSolverFactory_CDRM.lu(A.numRows); if (solver.setA(A)) { solver.invert(A); } else { return(false); } return(true); }
/** * Returns the determinant of the matrix. If the inverse of the matrix is also * needed, then using {@link LUDecompositionAlt_CDRM} directly (or any * similar algorithm) can be more efficient. * * @param mat The matrix whose determinant is to be computed. Not modified. * @return The determinant. */ public static Complex_F32 det(CMatrixRMaj mat) { LUDecompositionAlt_CDRM alg = new LUDecompositionAlt_CDRM(); if (alg.inputModified()) { mat = (CMatrixRMaj)mat.copy(); } if (!alg.decompose(mat)) { return(new Complex_F32()); } return(alg.computeDeterminant()); }