/** * <p> * Adds to A ∈ ℜ <sup>m × n</sup> the results of an outer product multiplication * of the two vectors. This is also known as a rank 1 update.<br> * <br> * A = A + γ x * y<sup>T</sup> * where x ∈ ℜ <sup>m</sup> and y ∈ ℜ <sup>n</sup> are vectors. * </p> * <p> * Which is equivalent to: A<sub>ij</sub> = A<sub>ij</sub> + γ x<sub>i</sub>*y<sub>j</sub> * </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 gamma A multiplication factor for the outer product. * @param x A vector with m elements. Not modified. * @param y A vector with n elements. Not modified. * @param A A Matrix with m by n elements. Modified. */ public static void addOuterProd(double gamma, DMatrixD1 x, DMatrixD1 y, DMatrix1Row A) { int m = A.numRows; int n = A.numCols; int index = 0; if (gamma == 1.0) { for (int i = 0; i < m; i++) { double xdat = x.get(i); for (int j = 0; j < n; j++) { A.plus(index++, xdat * y.get(j)); } } } else { for (int i = 0; i < m; i++) { double xdat = x.get(i); for (int j = 0; j < n; j++) { A.plus(index++, gamma * xdat * y.get(j)); } } } }
public static double elementMin(DMatrixD1 a, ElementLocation loc) { int size = a.NumElements; int bestIndex = 0; double min = a.get(0); for (int i = 1; i < size; i++) { double val = a.get(i); if (val < min) { bestIndex = i; min = val; } } if (loc != null) { loc.row = bestIndex / a.numCols; loc.col = bestIndex % a.numCols; } return(min); }
/** * An alternative implementation of {@link #multTransA_small} that performs well on large * matrices. There is a relative performance hit when used on small matrices. * * @param A A matrix that is m by n. Not modified. * @param B A Vector that has length m. Not modified. * @param C A column vector that has length n. Modified. */ public static void multTransA_reorder(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (C.numCols != 1) { throw new MatrixDimensionException("C is not a column vector"); } else if (C.numRows != A.numCols) { throw new MatrixDimensionException("C is not the expected length"); } if (B.numRows == 1) { if (A.numRows != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numRows != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if (A.numRows == 0) { CommonOps_DDRM.fill(C, 0); return; } double B_val = B.get(0); for (int i = 0; i < A.numCols; i++) { C.set(i, A.get(i) * B_val); } int indexA = A.numCols; for (int i = 1; i < A.numRows; i++) { B_val = B.get(i); for (int j = 0; j < A.numCols; j++) { C.plus(j, A.get(indexA++) * B_val); } } }
/** * <p> * Performs a matrix vector multiply.<br> * <br> * c = A * b <br> * and<br> * c = A * b<sup>T</sup> <br> * <br> * c<sub>i</sub> = Sum{ j=1:n, a<sub>ij</sub> * b<sub>j</sub>}<br> * <br> * where A is a matrix, b is a column or transposed row vector, and c is a column vector. * </p> * * @param A A matrix that is m by n. Not modified. * @param B A vector that has length n. Not modified. * @param C A column vector that has length m. Modified. */ public static void mult(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (C.numCols != 1) { throw new MatrixDimensionException("C is not a column vector"); } else if (C.numRows != A.numRows) { throw new MatrixDimensionException("C is not the expected length"); } if (B.numRows == 1) { if (A.numCols != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numCols != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if (A.numCols == 0) { CommonOps_DDRM.fill(C, 0); return; } int indexA = 0; int cIndex = 0; double b0 = B.get(0); for (int i = 0; i < A.numRows; i++) { double total = A.get(indexA++) * b0; for (int j = 1; j < A.numCols; j++) { total += A.get(indexA++) * B.get(j); } C.set(cIndex++, total); } }
public static double elementMaxAbs(DMatrixD1 a, ElementLocation loc) { int size = a.NumElements; int bestIndex = 0; double max = 0; for (int i = 0; i < size; i++) { double val = Math.Abs(a.get(i)); if (val > max) { bestIndex = i; max = val; } } if (loc != null) { loc.row = bestIndex / a.numCols; loc.col = bestIndex % a.numCols; } return(max); }
/** * <p> * return = x<sup>T</sup>*A*y * </p> * * @param x A vector with n elements. Not modified. * @param A A matrix with n by m elements. Not modified. * @param y A vector with m elements. Not modified. * @return The results. */ public static double innerProdA(DMatrixD1 x, DMatrixD1 A, DMatrixD1 y) { int n = A.numRows; int m = A.numCols; if (x.getNumElements() != n) { throw new ArgumentException("Unexpected number of elements in x"); } if (y.getNumElements() != m) { throw new ArgumentException("Unexpected number of elements in y"); } double result = 0; for (int i = 0; i < m; i++) { double total = 0; for (int j = 0; j < n; j++) { total += x.get(j) * A.unsafe_get(j, i); } result += total * y.get(i); } return(result); }
/** * <p> * x<sup>T</sup>A<sup>T</sup>y * </p> * * @param x A vector with n elements. Not modified. * @param A A matrix with n by n elements. Not modified. * @param y A vector with n elements. Not modified. * @return The results. */ // TODO better name for this public static double innerProdTranA(DMatrixD1 x, DMatrixD1 A, DMatrixD1 y) { int n = A.numRows; if (n != A.numCols) { throw new ArgumentException("A must be square"); } if (x.NumElements != n) { throw new ArgumentException("Unexpected number of elements in x"); } if (y.NumElements != n) { throw new ArgumentException("Unexpected number of elements in y"); } double result = 0; for (int i = 0; i < n; i++) { double total = 0; for (int j = 0; j < n; j++) { total += x.get(j) * A.unsafe_get(i, j); } result += total * y.get(i); } return(result); }
/** * <p> * Multiplies a householder reflection against a vector:<br> * <br> * y = (I + γ u u<sup>T</sup>)x<br> * </p> * <p> * The Householder reflection is used in some implementations of QR decomposition. * </p> * * @param u A vector. Not modified. * @param x a vector. Not modified. * @param y Vector where the result are written to. */ public static void householder(double gamma, DMatrixD1 u, DMatrixD1 x, DMatrixD1 y) { int n = u.NumElements; double sum = 0; for (int i = 0; i < n; i++) { sum += u.get(i) * x.get(i); } for (int i = 0; i < n; i++) { y.set(i, x.get(i) + gamma * u.get(i) * sum); } }
/** * <p> * Performs a matrix vector multiply.<br> * <br> * C = C + A * B <br> * or<br> * C = C + A * B<sup>T</sup> <br> * <br> * c<sub>i</sub> = Sum{ j=1:n, c<sub>i</sub> + a<sub>ij</sub> * b<sub>j</sub>}<br> * <br> * where A is a matrix, B is a column or transposed row vector, and C is a column vector. * </p> * * @param A A matrix that is m by n. Not modified. * @param B A vector that has length n. Not modified. * @param C A column vector that has length m. Modified. */ public static void multAdd(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (B.numRows == 1) { if (A.numCols != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numCols != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if (A.numRows != C.NumElements) { throw new MatrixDimensionException("C is not compatible with A"); } if (A.numCols == 0) { return; } int indexA = 0; int cIndex = 0; for (int i = 0; i < A.numRows; i++) { double total = A.get(indexA++) * B.get(0); for (int j = 1; j < A.numCols; j++) { total += A.get(indexA++) * B.get(j); } C.plus(cIndex++, total); } }
public static void elementDiv(DMatrixD1 A, DMatrixD1 B) { UtilEjml.checkSameShape(A, B, true); int length = A.NumElements; for (int i = 0; i < length; i++) { A.div(i, B.get(i)); } }
/** * Checks to see if any element in the matrix is NaN. * * @param m A matrix. Not modified. * @return True if any element in the matrix is NaN. */ public static bool hasNaN(DMatrixD1 m) { int length = m.NumElements; for (int i = 0; i < length; i++) { if (Double.IsNaN(m.get(i))) { return(true); } } return(false); }
/** * <p> * Computes the inner product of the two vectors. In geometry this is known as the dot product.<br> * <br> * ∑<sub>k=1:n</sub> x<sub>k</sub> * 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 double innerProd(DMatrixD1 x, DMatrixD1 y) { int m = x.NumElements; double total = 0; for (int i = 0; i < m; i++) { total += x.get(i) * y.get(i); } return(total); }
public static double elementSumAbs(DMatrixD1 mat) { double total = 0; int size = mat.NumElements; for (int i = 0; i < size; i++) { total += Math.Abs(mat.get(i)); } return(total); }
/** * Checks to see all the elements in the matrix are zeros * * @param m A matrix. Not modified. * @return True if all elements are zeros or false if not */ public static bool isZeros(DMatrixD1 m, double tol) { int length = m.NumElements; for (int i = 0; i < length; i++) { if (Math.Abs(m.get(i)) > tol) { return(false); } } return(true); }
/** * Checks to see if any element in the matrix is NaN of Infinite. * * @param m A matrix. Not modified. * @return True if any element in the matrix is NaN of Infinite. */ public static bool hasUncountable(DMatrixD1 m) { int length = m.NumElements; for (int i = 0; i < length; i++) { double a = m.get(i); if (Double.IsNaN(a) || Double.IsInfinity(a)) { return(true); } } return(false); }
/** * <p> * This implementation of the Frobenius norm is a straight forward implementation and can * be susceptible for overflow/underflow issues. A more resilient implementation is * {@link #normF}. * </p> * * @param a The matrix whose norm is computed. Not modified. */ public static double fastNormF(DMatrixD1 a) { double total = 0; int size = a.getNumElements(); for (int i = 0; i < size; i++) { double val = a.get(i); total += val * val; } return(Math.Sqrt(total)); }
/** * <p> * Sets A ∈ ℜ <sup>m × n</sup> equal to an outer product multiplication of the two * vectors. This is also known as a rank-1 operation.<br> * <br> * A = x * y' * where x ∈ ℜ <sup>m</sup> and y ∈ ℜ <sup>n</sup> are vectors. * </p> * <p> * Which is equivalent to: A<sub>ij</sub> = x<sub>i</sub>*y<sub>j</sub> * </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 m elements. Not modified. * @param y A vector with n elements. Not modified. * @param A A Matrix with m by n elements. Modified. */ public static void outerProd(DMatrixD1 x, DMatrixD1 y, DMatrix1Row A) { int m = A.numRows; int n = A.numCols; int index = 0; for (int i = 0; i < m; i++) { double xdat = x.get(i); for (int j = 0; j < n; j++) { A.set(index++, xdat * y.get(j)); } } }
/** * <p> * Computes the F norm of the difference between the two Matrices:<br> * <br> * Sqrt{∑<sub>i=1:m</sub> ∑<sub>j=1:n</sub> ( a<sub>ij</sub> - b<sub>ij</sub>)<sup>2</sup>} * </p> * <p> * This is often used as a cost function. * </p> * * @see NormOps_DDRM#fastNormF * * @param a m by n matrix. Not modified. * @param b m by n matrix. Not modified. * * @return The F normal of the difference matrix. */ public static double diffNormF(DMatrixD1 a, DMatrixD1 b) { if (a.numRows != b.numRows || a.numCols != b.numCols) { throw new ArgumentException("Both matrices must have the same shape."); } int size = a.getNumElements(); DMatrixRMaj diff = new DMatrixRMaj(size, 1); for (int i = 0; i < size; i++) { diff.set(i, b.get(i) - a.get(i)); } return(NormOps_DDRM.normF(diff)); }
/** * <p> * Computes the p=1 p-norm of the difference between the two Matrices:<br> * <br> * ∑<sub>i=1:m</sub> ∑<sub>j=1:n</sub> | a<sub>ij</sub> - b<sub>ij</sub>| <br> * <br> * where |x| is the absolute value of x. * </p> * <p> * This is often used as a cost function. * </p> * * @param a m by n matrix. Not modified. * @param b m by n matrix. Not modified. * * @return The p=1 p-norm of the difference matrix. */ public static double diffNormP1(DMatrixD1 a, DMatrixD1 b) { if (a.numRows != b.numRows || a.numCols != b.numCols) { throw new ArgumentException("Both matrices must have the same shape."); } int size = a.getNumElements(); double total = 0; for (int i = 0; i < size; i++) { total += Math.Abs(b.get(i) - a.get(i)); } return(total); }
/** * <p> * Returns the absolute value of the digonal element in the matrix that has the largest absolute value.<br> * <br> * Max{ |a<sub>ij</sub>| } for all i and j<br> * </p> * * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementDiagonalMaxAbs(DMatrixD1 a) { int size = Math.Min(a.numRows, a.numCols); double max = 0; for (int i = 0; i < size; i++) { double val = Math.Abs(a.get(i, i)); if (val > max) { max = val; } } return(max); }
/** * <p> * Performs a matrix vector multiply.<br> * <br> * C = C + A<sup>T</sup> * B <br> * or<br> * C = C<sup>T</sup> + A<sup>T</sup> * B<sup>T</sup> <br> * <br> * c<sub>i</sub> = Sum{ j=1:n, c<sub>i</sub> + a<sub>ji</sub> * b<sub>j</sub>}<br> * <br> * where A is a matrix, B is a column or transposed row vector, and C is a column vector. * </p> * <p> * This implementation is optimal for small matrices. There is a huge performance hit when * used on large matrices due to CPU cache issues. * </p> * * @param A A matrix that is m by n. Not modified. * @param B A vector that has length m. Not modified. * @param C A column vector that has length n. Modified. */ public static void multAddTransA_small(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (C.numCols != 1) { throw new MatrixDimensionException("C is not a column vector"); } else if (C.numRows != A.numCols) { throw new MatrixDimensionException("C is not the expected length"); } if (B.numRows == 1) { if (A.numRows != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numRows != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } int cIndex = 0; for (int i = 0; i < A.numCols; i++) { double total = 0.0; int indexA = i; for (int j = 0; j < A.numRows; j++) { total += A.get(indexA) * B.get(j); indexA += A.numCols; } C.plus(cIndex++, total); } }
public static double diffNormF_fast(DMatrixD1 a, DMatrixD1 b) { if (a.numRows != b.numRows || a.numCols != b.numCols) { throw new ArgumentException("Both matrices must have the same shape."); } int size = a.NumElements; double total = 0; for (int i = 0; i < size; i++) { double diff = b.get(i) - a.get(i); total += diff * diff; } return(Math.Sqrt(total)); }
/** * <p> * Checks to see if each element in the two matrices are equal: * a<sub>ij</sub> == b<sub>ij</sub> * <p> * * <p> * NOTE: If any of the elements are NaN then false is returned. If two corresponding * elements are both positive or negative infinity then they are equal. * </p> * * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @return true if identical and false otherwise. */ public static bool isEquals(DMatrixD1 a, DMatrixD1 b) { if (a.numRows != b.numRows || a.numCols != b.numCols) { return(false); } int length = a.NumElements; for (int i = 0; i < length; i++) { if (!(a.get(i) == b.get(i))) { return(false); } } return(true); }
/** * <p> * Checks to see if the two matrices are the negative of each other:<br> * <br> * a<sub>ij</sub> = -b<sub>ij</sub> * </p> * * @param a First matrix. Not modified. * @param b Second matrix. Not modified. * @param tol Numerical tolerance. * @return True if they are the negative of each other within tolerance. */ public static bool isNegative(DMatrixD1 a, DMatrixD1 b, double tol) { if (a.numRows != b.numRows || a.numCols != b.numCols) { throw new ArgumentException("Matrix dimensions must match"); } int length = a.NumElements; for (int i = 0; i < length; i++) { if (!(Math.Abs(a.get(i) + b.get(i)) <= 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. See {@link #fastNormF} for another implementation * that is faster, but more prone to underflow/overflow errors. * </p> * * @param a The matrix whose norm is computed. Not modified. * @return The norm's value. */ public static double normF(DMatrixD1 a) { double total = 0; double scale = CommonOps_DDRM.elementMaxAbs(a); if (scale == 0.0) { return(0.0); } int size = a.getNumElements(); for (int i = 0; i < size; i++) { double val = a.get(i) / scale; total += val * val; } return(scale * Math.Sqrt(total)); }
/** * <p> * Performs a matrix vector multiply.<br> * <br> * C = A<sup>T</sup> * B <br> * where B is a column vector.<br> * or<br> * C = A<sup>T</sup> * B<sup>T</sup> <br> * where B is a row vector. <br> * <br> * c<sub>i</sub> = Sum{ j=1:n, a<sub>ji</sub> * b<sub>j</sub>}<br> * <br> * where A is a matrix, B is a column or transposed row vector, and C is a column vector. * </p> * <p> * This implementation is optimal for small matrices. There is a huge performance hit when * used on large matrices due to CPU cache issues. * </p> * * @param A A matrix that is m by n. Not modified. * @param B A that has length m and is a column. Not modified. * @param C A column vector that has length n. Modified. */ public static void multTransA_small(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (B.numRows == 1) { if (A.numRows != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numRows != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } C.reshape(A.numCols, 1); int cIndex = 0; for (int i = 0; i < A.numCols; i++) { double total = 0.0; int indexA = i; for (int j = 0; j < A.numRows; j++) { total += A.get(indexA) * B.get(j); indexA += A.numCols; } C.set(cIndex++, total); } }
/** * Same as {@link #elementP} but runs faster by not mitigating overflow/underflow related problems. * * @param A Matrix. Not modified. * @param p p value. * @return The norm's value. */ public static double fastElementP(DMatrixD1 A, double p) { if (p == 2) { return(fastNormF(A)); } else { double total = 0; int size = A.getNumElements(); for (int i = 0; i < size; i++) { double a = A.get(i); total += Math.Pow(Math.Abs(a), p); } return(Math.Pow(total, 1.0 / p)); } }
/** * <p> * Checks to see if each element in the two matrices are within tolerance of * each other: tol ≥ |a<sub>ij</sub> - b<sub>ij</sub>|. * <p> * * <p> * NOTE: If any of the elements are not countable then false is returned.<br> * NOTE: If a tolerance of zero is passed in this is equivalent to calling * {@link #isEquals(DMatrixD1, DMatrixD1)} * </p> * * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @param tol How close to being identical each element needs to be. * @return true if equals and false otherwise. */ public static bool isEquals(DMatrixD1 a, DMatrixD1 b, double tol) { if (a.numRows != b.numRows || a.numCols != b.numCols) { return(false); } if (tol == 0.0) { return(isEquals(a, b)); } int length = a.NumElements; for (int i = 0; i < length; i++) { if (!(tol >= Math.Abs(a.get(i) - b.get(i)))) { return(false); } } return(true); }
/** * <p> * Checks to see if each corresponding element in the two matrices are * within tolerance of each other or have the some symbolic meaning. This * can handle NaN and Infinite numbers. * <p> * * <p> * If both elements are countable then the following equality test is used:<br> * |a<sub>ij</sub> - b<sub>ij</sub>| ≤ tol.<br> * Otherwise both numbers must both be Double.NaN, Double.POSITIVE_INFINITY, or * Double.NEGATIVE_INFINITY to be identical. * </p> * * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @param tol Tolerance for equality. * @return true if identical and false otherwise. */ public static bool isIdentical(DMatrixD1 a, DMatrixD1 b, double tol) { if (a.numRows != b.numRows || a.numCols != b.numCols) { return(false); } if (tol < 0) { throw new ArgumentException("Tolerance must be greater than or equal to zero."); } int length = a.NumElements; for (int i = 0; i < length; i++) { if (!UtilEjml.isIdentical(a.get(i), b.get(i), tol)) { return(false); } } return(true); }
/** * An alternative implementation of {@link #multAddTransA_small} that performs well on large * matrices. There is a relative performance hit when used on small matrices. * * @param A A matrix that is m by n. Not modified. * @param B A vector that has length m. Not modified. * @param C A column vector that has length n. Modified. */ public static void multAddTransA_reorder(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (B.numRows == 1) { if (A.numRows != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numRows != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if (A.numCols != C.NumElements) { throw new MatrixDimensionException("C is not compatible with A"); } int indexA = 0; for (int j = 0; j < A.numRows; j++) { double B_val = B.get(j); for (int i = 0; i < A.numCols; i++) { C.plus(i, A.get(indexA++) * B_val); } } }