/** * Checks to see if the provided matrix is within tolerance to an identity matrix. * * @param mat Matrix being examined. Not modified. * @param tol Tolerance. * @return True if it is within tolerance to an identify matrix. */ public static bool isIdentity(FMatrixRMaj mat, float tol) { // see if the result is an identity matrix int index = 0; for (int i = 0; i < mat.numRows; i++) { for (int j = 0; j < mat.numCols; j++) { if (i == j) { if (!(Math.Abs(mat.get(index++) - 1) <= tol)) { return(false); } } else { if (!(Math.Abs(mat.get(index++)) <= tol)) { return(false); } } } } return(true); }
/** * <p> * Returns true if the matrix is symmetric within the tolerance. Only square matrices can be * symmetric. * </p> * <p> * A matrix is symmetric if:<br> * |a<sub>ij</sub> - a<sub>ji</sub>| ≤ tol * </p> * * @param m A matrix. Not modified. * @param tol Tolerance for how similar two elements need to be. * @return true if it is symmetric and false if it is not. */ public static bool isSymmetric(FMatrixRMaj m, float tol) { if (m.numCols != m.numRows) { return(false); } float max = CommonOps_FDRM.elementMaxAbs(m); for (int i = 0; i < m.numRows; i++) { for (int j = 0; j < i; j++) { float a = m.get(i, j) / max; float b = m.get(j, i) / max; float diff = Math.Abs(a - b); if (!(diff <= tol)) { return(false); } } } return(true); }
private static void swapRowOrCol(FMatrixRMaj M, bool tran, int i, int bigIndex) { float tmp; if (tran) { // swap the rows for (int col = 0; col < M.numCols; col++) { tmp = M.get(i, col); M.set(i, col, M.get(bigIndex, col)); M.set(bigIndex, col, tmp); } } else { // swap the columns for (int row = 0; row < M.numRows; row++) { tmp = M.get(row, i); M.set(row, i, M.get(row, bigIndex)); M.set(row, bigIndex, tmp); } } }
/** * <p> * Adjusts the matrices so that the singular values are in descending order. * </p> * * <p> * In most implementations of SVD the singular values are automatically arranged in in descending * order. In EJML this is not the case since it is often not needed and some computations can * be saved by not doing that. * </p> * * @param U Matrix. Modified. * @param tranU is U transposed or not. * @param W Diagonal matrix with singular values. Modified. * @param V Matrix. Modified. * @param tranV is V transposed or not. */ // TODO the number of copies can probably be reduced here public static void descendingOrder(FMatrixRMaj U, bool tranU, FMatrixRMaj W, FMatrixRMaj V, bool tranV) { int numSingular = Math.Min(W.numRows, W.numCols); checkSvdMatrixSize(U, tranU, W, V, tranV); for (int i = 0; i < numSingular; i++) { float bigValue = -1; int bigIndex = -1; // find the smallest singular value in the submatrix for (int j = i; j < numSingular; j++) { float v = W.get(j, j); if (v > bigValue) { bigValue = v; bigIndex = j; } } // only swap if the current index is not the smallest if (bigIndex == i) { continue; } if (bigIndex == -1) { // there is at least one uncountable singular value. just stop here break; } float tmp = W.get(i, i); W.set(i, i, bigValue); W.set(bigIndex, bigIndex, tmp); if (V != null) { swapRowOrCol(V, tranV, i, bigIndex); } if (U != null) { swapRowOrCol(U, tranU, i, bigIndex); } } }
/** * <p> * Puts all the real eigenvectors into the columns of a matrix. If an eigenvalue is imaginary * then the corresponding eigenvector will have zeros in its column. * </p> * * @param eig An eigenvalue decomposition which has already decomposed a matrix. * @return An m by m matrix containing eigenvectors in its columns. */ public static FMatrixRMaj createMatrixV(EigenDecomposition_F32 <FMatrixRMaj> eig) { int N = eig.getNumberOfEigenvalues(); FMatrixRMaj V = new FMatrixRMaj(N, N); for (int i = 0; i < N; i++) { Complex_F32 c = eig.getEigenvalue(i); if (c.isReal()) { FMatrixRMaj v = eig.getEigenVector(i); if (v != null) { for (int j = 0; j < N; j++) { V.set(j, i, v.get(j, 0)); } } } } return(V); }
private void replaceZeros(FSubmatrixD1 subU) { int N = Math.Min(A.blockLength, subU.col1 - subU.col0); for (int i = 0; i < N; i++) { // save the zeros for (int j = 0; j <= i; j++) { subU.set(i, j, zerosM.get(i, j)); } // save the one if (subU.col0 + i + 1 < subU.original.numCols) { subU.set(i, i + 1, zerosM.get(i, i + 1)); } } }
/** * Extracts the tridiagonal matrix found in the decomposition. * * @param T If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted T matrix. */ public FMatrixRMaj getT(FMatrixRMaj T) { T = UtilDecompositons_FDRM.checkZeros(T, N, N); T.data[0] = QT.data[0]; T.data[1] = QT.data[1]; for (int i = 1; i < N - 1; i++) { T.set(i, i, QT.get(i, i)); T.set(i, i + 1, QT.get(i, i + 1)); T.set(i, i - 1, QT.get(i - 1, i)); } T.data[(N - 1) * N + N - 1] = QT.data[(N - 1) * N + N - 1]; T.data[(N - 1) * N + N - 2] = QT.data[(N - 2) * N + N - 1]; return(T); }
/** * Checks to see if all the diagonal elements in the matrix are positive. * * @param a A matrix. Not modified. * @return true if all the diagonal elements are positive, false otherwise. */ public static bool isDiagonalPositive(FMatrixRMaj a) { for (int i = 0; i < a.numRows; i++) { if (!(a.get(i, i) >= 0)) { return(false); } } return(true); }
public override void solve(FMatrixRMaj B, FMatrixRMaj X) { if (X.numRows != numCols) { throw new ArgumentException("Unexpected dimensions for X"); } else if (B.numRows != numRows || B.numCols != X.numCols) { throw new ArgumentException("Unexpected dimensions for B"); } int BnumCols = B.numCols; // get the pivots and transpose them int[] pivots = decomposition.getColPivots(); // solve each column one by one for (int colB = 0; colB < BnumCols; colB++) { x_basic.reshape(numRows, 1); Y.reshape(numRows, 1); // make a copy of this column in the vector for (int i = 0; i < numRows; i++) { Y.data[i] = B.get(i, colB); } // Solve Q*a=b => a = Q'*b CommonOps_FDRM.multTransA(Q, Y, x_basic); // solve for Rx = b using the standard upper triangular solver TriangularSolver_FDRM.solveU(R11.data, x_basic.data, rank); // finish the basic solution by filling in zeros x_basic.reshape(numCols, 1, true); for (int i = rank; i < numCols; i++) { x_basic.data[i] = 0; } if (norm2Solution && rank < numCols) { upgradeSolution(x_basic); } // save the results for (int i = 0; i < numCols; i++) { X.set(pivots[i], colB, x_basic.data[i]); } } }
/** * Computes the likelihood of the random draw * * @return The likelihood. */ public float computeLikelihoodP() { float ret = 1.0f; for (int i = 0; i < r.numRows; i++) { float a = r.get(i, 0); ret *= (float)Math.Exp(-a * a / 2.0f); } return(ret); }
/** * Multiplied a transpose orthogonal matrix Q by the specified rotator. This is used * to update the U and V matrices. Updating the transpose of the matrix is faster * since it only modifies the rows. * * * @param Q Orthogonal matrix * @param m Coordinate of rotator. * @param n Coordinate of rotator. * @param c cosine of rotator. * @param s sine of rotator. */ protected void updateRotator(FMatrixRMaj Q, int m, int n, float c, float s) { int rowA = m * Q.numCols; int rowB = n * Q.numCols; // for( int i = 0; i < Q.numCols; i++ ) { // float a = Q.get(rowA+i); // float b = Q.get(rowB+i); // Q.set( rowA+i, c*a + s*b); // Q.set( rowB+i, -s*a + c*b); // } // Console.WriteLine("------ AFter Update Rotator "+m+" "+n); // Q.print(); // Console.WriteLine(); int endA = rowA + Q.numCols; for (; rowA != endA; rowA++, rowB++) { float a = Q.get(rowA); float b = Q.get(rowB); Q.set(rowA, c * a + s * b); Q.set(rowB, -s * a + c * b); } }
/** * <p> * Checks to see if a matrix is skew symmetric with in tolerance:<br> * <br> * -A = A<sup>T</sup><br> * or<br> * |a<sub>ij</sub> + a<sub>ji</sub>| ≤ tol * </p> * * @param A The matrix being tested. * @param tol Tolerance for being skew symmetric. * @return True if it is skew symmetric and false if it is not. */ public static bool isSkewSymmetric(FMatrixRMaj A, float tol) { if (A.numCols != A.numRows) { return(false); } for (int i = 0; i < A.numRows; i++) { for (int j = 0; j < i; j++) { float a = A.get(i, j); float b = A.get(j, i); float diff = Math.Abs(a + b); if (!(diff <= tol)) { return(false); } } } return(true); }
/** * <p> * Generates a bound for the largest eigen value of the provided matrix using Perron-Frobenius * theorem. This function only applies to non-negative real matrices. * </p> * * <p> * For "stochastic" matrices (Markov process) this should return one for the upper and lower bound. * </p> * * @param A Square matrix with positive elements. Not modified. * @param bound Where the results are stored. If null then a matrix will be declared. Modified. * @return Lower and upper bound in the first and second elements respectively. */ public static float[] boundLargestEigenValue(FMatrixRMaj A, float[] bound) { if (A.numRows != A.numCols) { throw new ArgumentException("A must be a square matrix."); } float min = float.MaxValue; float max = 0; int n = A.numRows; for (int i = 0; i < n; i++) { float total = 0; for (int j = 0; j < n; j++) { float v = A.get(i, j); if (v < 0) { throw new ArgumentException("Matrix must be positive"); } total += v; } if (total < min) { min = total; } if (total > max) { max = total; } } if (bound == null) { bound = new float[2]; } bound[0] = min; bound[1] = max; return(bound); }
/** * <p> * Induced matrix p = infinity norm.<br> * <br> * ||A||<sub>∞</sub> = max(i=1 to m; sum(j=1 to n; |a<sub>ij</sub>|)) * </p> * * @param A A matrix. * @return the norm. */ public static float inducedPInf(FMatrixRMaj A) { float max = 0; int m = A.numRows; int n = A.numCols; for (int i = 0; i < m; i++) { float total = 0; for (int j = 0; j < n; j++) { total += Math.Abs(A.get(i, j)); } if (total > max) { max = total; } } return(max); }
public override /**/ double quality() { return(SpecializedOps_FDRM.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. */ public override void solve(FMatrixRMaj B, FMatrixRMaj X) { if (X.numRows != numCols) { throw new ArgumentException("Unexpected dimensions for X"); } else if (B.numRows != numRows || B.numCols != X.numCols) { throw new ArgumentException("Unexpected dimensions for B"); } int BnumCols = B.numCols; Y.reshape(numRows, 1, false); Z.reshape(numRows, 1, false); // 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++) { Y.data[i] = B.get(i, colB); } // Solve Qa=b // a = Q'b CommonOps_FDRM.multTransA(Q, Y, Z); // solve for Rx = b using the standard upper triangular solver TriangularSolver_FDRM.solveU(R.data, Z.data, numCols); // save the results for (int i = 0; i < numCols; i++) { X.set(i, colB, Z.data[i]); } } }
/** * Checks to see if the two matrices are inverses of each other. * * @param a A matrix. Not modified. * @param b A matrix. Not modified. */ public static bool isInverse(FMatrixRMaj a, FMatrixRMaj b, float tol) { if (a.numRows != b.numRows || a.numCols != b.numCols) { return(false); } int numRows = a.numRows; int numCols = a.numCols; for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { float total = 0; for (int k = 0; k < numCols; k++) { total += a.get(i, k) * b.get(k, j); } if (i == j) { if (!(Math.Abs(total - 1) <= tol)) { return(false); } } else if (!(Math.Abs(total) <= tol)) { return(false); } } } return(true); }
public override void solve(FMatrixRMaj B, FMatrixRMaj X) { if (X.numRows != numCols) { throw new ArgumentException("Unexpected dimensions for X"); } else if (B.numRows != numRows || B.numCols != X.numCols) { throw new ArgumentException("Unexpected dimensions for B"); } int BnumCols = B.numCols; // get the pivots and transpose them int[] pivots = decomposition.getColPivots(); float[][] qr = decomposition.getQR(); float[] gammas = decomposition.getGammas(); // solve each column one by one for (int colB = 0; colB < BnumCols; colB++) { x_basic.reshape(numRows, 1); Y.reshape(numRows, 1); // make a copy of this column in the vector for (int i = 0; i < numRows; i++) { x_basic.data[i] = B.get(i, colB); } // Solve Q*x=b => x = Q'*b // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for (int i = 0; i < rank; i++) { float[] u = qr[i]; float vv = u[i]; u[i] = 1; QrHelperFunctions_FDRM.rank1UpdateMultR(x_basic, u, gammas[i], 0, i, numRows, Y.data); u[i] = vv; } // solve for Rx = b using the standard upper triangular solver TriangularSolver_FDRM.solveU(R11.data, x_basic.data, rank); // finish the basic solution by filling in zeros x_basic.reshape(numCols, 1, true); for (int i = rank; i < numCols; i++) { x_basic.data[i] = 0; } if (norm2Solution && rank < numCols) { upgradeSolution(x_basic); } // save the results for (int i = 0; i < numCols; i++) { X.set(pivots[i], colB, x_basic.data[i]); } } }
public bool isZero(int x1, int x2) { // this provides a relative threshold for when dealing with very large/small numbers float target = Math.Abs(A.get(x1, x2)); float above = Math.Abs(A.get(x1 - 1, x2)); // according to Matrix Computations page 352 this is what is done in Eispack float right = Math.Abs(A.get(x1, x2 + 1)); return(target <= 0.5f * UtilEjml.F_EPS * (above + right)); }