/** * Computes the p=∞ norm. If A is a matrix then the induced norm is computed. * * @param A Matrix or vector. * @return The norm. */ public static float normPInf(FMatrixRMaj A) { if (MatrixFeatures_FDRM.isVector(A)) { return(CommonOps_FDRM.elementMaxAbs(A)); } else { return(inducedPInf(A)); } }
/** * Computes the p=2 norm. If A is a matrix then the induced norm is computed. This * implementation is faster, but more prone to buffer overflow or underflow problems. * * @param A Matrix or vector. * @return The norm. */ public static float fastNormP2(FMatrixRMaj A) { if (MatrixFeatures_FDRM.isVector(A)) { return(fastNormF(A)); } else { return(inducedP2(A)); } }
/** * <p> * Creates a reflector from the provided vector and gamma.<br> * <br> * Q = I - γ u u<sup>T</sup><br> * </p> * * <p> * In practice {@link VectorVectorMult_FDRM#householder(float, FMatrixD1, FMatrixD1, FMatrixD1)} multHouseholder} * should be used for performance reasons since there is no need to calculate Q explicitly. * </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 FMatrixRMaj createReflector(FMatrixRMaj u, float gamma) { if (!MatrixFeatures_FDRM.isVector(u)) { throw new ArgumentException("u must be a vector"); } FMatrixRMaj Q = CommonOps_FDRM.identity(u.getNumElements()); CommonOps_FDRM.multAddTransB(-gamma, 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> * * <p> * In practice {@link VectorVectorMult_FDRM#householder(float, FMatrixD1, FMatrixD1, FMatrixD1)} multHouseholder} * should be used for performance reasons since there is no need to calculate Q explicitly. * </p> * * @param u A vector. Not modified. * @return An orthogonal reflector. */ public static FMatrixRMaj createReflector(FMatrix1Row u) { if (!MatrixFeatures_FDRM.isVector(u)) { throw new ArgumentException("u must be a vector"); } float norm = NormOps_FDRM.fastNormF(u); float gamma = -2.0f / (norm * norm); FMatrixRMaj Q = CommonOps_FDRM.identity(u.getNumElements()); CommonOps_FDRM.multAddTransB(gamma, u, u, Q); return(Q); }
/** * Performs a variety of tests to see if the provided matrix is a valid * covariance matrix. * * @return 0 = is valid 1 = failed positive diagonal, 2 = failed on symmetry, 2 = failed on positive definite */ public static int isValid(FMatrixRMaj cov) { if (!MatrixFeatures_FDRM.isDiagonalPositive(cov)) { return(1); } if (!MatrixFeatures_FDRM.isSymmetric(cov, TOL)) { return(2); } if (!MatrixFeatures_FDRM.isPositiveSemidefinite(cov)) { return(3); } return(0); }
/** * An unsafe but faster version of {@link #normP} that calls routines which are faster * but more prone to overflow/underflow problems. * * @param A Vector or matrix whose norm is to be computed. * @param p The p value of the p-norm. * @return The computed norm. */ public static float fastNormP(FMatrixRMaj A, float p) { if (p == 1) { return(normP1(A)); } else if (p == 2) { return(fastNormP2(A)); } else if (float.IsInfinity(p)) { return(normPInf(A)); } if (MatrixFeatures_FDRM.isVector(A)) { return(fastElementP(A, p)); } else { throw new ArgumentException("Doesn't support induced norms yet."); } }
/** * <p> * Given an eigenvalue it computes an eigenvector using inverse iteration: * <br> * for i=1:MAX {<br> * (A - μI)z<sup>(i)</sup> = q<sup>(i-1)</sup><br> * q<sup>(i)</sup> = z<sup>(i)</sup> / ||z<sup>(i)</sup>||<br> * λ<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 FEigenpair computeEigenVector(FMatrixRMaj A, float eigenvalue) { if (A.numRows != A.numCols) { throw new ArgumentException("Must be a square matrix."); } FMatrixRMaj M = new FMatrixRMaj(A.numRows, A.numCols); FMatrixRMaj x = new FMatrixRMaj(A.numRows, 1); FMatrixRMaj b = new FMatrixRMaj(A.numRows, 1); CommonOps_FDRM.fill(b, 1); // perturb the eigenvalue slightly so that its not an exact solution the first time // eigenvalue -= eigenvalue*UtilEjml.F_EPS*10; float origEigenvalue = eigenvalue; SpecializedOps_FDRM.addIdentity(A, M, -eigenvalue); float threshold = NormOps_FDRM.normPInf(A) * UtilEjml.F_EPS; float prevError = float.MaxValue; bool hasWorked = false; LinearSolverDense <FMatrixRMaj> solver = LinearSolverFactory_FDRM.linear(M.numRows); float perp = 0.0001f; 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_FDRM.hasUncountable(x)) { failed = true; } if (failed) { if (!hasWorked) { // if it failed on the first trial try perturbing it some more float val = i % 2 == 0 ? 1.0f - perp : 1.0f + perp; // maybe this should be turn into a parameter allowing the user // to configure the wise of each step eigenvalue = origEigenvalue * (float)Math.Pow(val, i / 2 + 1); SpecializedOps_FDRM.addIdentity(A, M, -eigenvalue); } else { // otherwise assume that it was so accurate that the matrix was singular // and return that result return(new FEigenpair(eigenvalue, b)); } } else { hasWorked = true; b.set(x); NormOps_FDRM.normalizeF(b); // compute the residual CommonOps_FDRM.mult(M, b, x); float error = NormOps_FDRM.normPInf(x); if (error - prevError > UtilEjml.F_EPS * 10) { // if the error increased it is probably converging towards a different // eigenvalue // CommonOps.set(b,1); prevError = float.MaxValue; hasWorked = false; float val = i % 2 == 0 ? 1.0f - perp : 1.0f + perp; eigenvalue = origEigenvalue * (float)Math.Pow(val, 1); } else { // see if it has converged if (error <= threshold || Math.Abs(prevError - error) <= UtilEjml.F_EPS) { return(new FEigenpair(eigenvalue, b)); } // update everything prevError = error; eigenvalue = VectorVectorMult_FDRM.innerProdA(b, A, b); } SpecializedOps_FDRM.addIdentity(A, M, -eigenvalue); } } return(null); }
/** * This is a fairly light weight check to see of a covariance matrix is valid. * It checks to see if the diagonal elements are all positive, which they should be * if it is valid. Not all invalid covariance matrices will be caught by this method. * * @return true if valid and false if invalid */ public static bool isValidFast(FMatrixRMaj cov) { return(MatrixFeatures_FDRM.isDiagonalPositive(cov)); }