/** * <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)); } } } }
/** * @see CommonOps_DDRM#multAdd(double, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multAdd_small(double alpha, DMatrix1Row A, DMatrix1Row B, DMatrix1Row C) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numCols, B.numRows, "The 'A' and 'B' matrices do not have compatible dimensions"); UtilEjml.assertShape(A.numRows == C.numRows && B.numCols == C.numCols, "C is not compatible with A and B"); //CONCURRENT_BELOW EjmlConcurrency.loopFor(0, A.numRows, i -> { for (int i = 0; i < A.numRows; i++) { int cIndex = i * B.numCols; int aIndexStart = i * A.numCols; for (int j = 0; j < B.numCols; j++) { double total = 0; int indexA = aIndexStart; int indexB = j; int end = indexA + B.numRows; while (indexA < end) { total += A.data[indexA++] * B.data[indexB]; indexB += B.numCols; } C.plus(cIndex++, alpha * total); } } //CONCURRENT_ABOVE }); }
//CONCURRENT_OMIT_END /** * @see CommonOps_DDRM#multAddTransB(org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multAddTransB(DMatrix1Row A, DMatrix1Row B, DMatrix1Row C) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numCols, B.numCols, "The 'A' and 'B' matrices do not have compatible dimensions"); UtilEjml.assertShape(A.numRows == C.numRows && B.numRows == C.numCols, "C is not compatible with A and B"); //CONCURRENT_BELOW EjmlConcurrency.loopFor(0, A.numRows, xA -> { for (int xA = 0; xA < A.numRows; xA++) { int cIndex = xA * B.numRows; int aIndexStart = xA * B.numCols; int end = aIndexStart + B.numCols; int indexB = 0; for (int xB = 0; xB < B.numRows; xB++) { int indexA = aIndexStart; double total = 0; while (indexA < end) { total += A.data[indexA++] * B.data[indexB++]; } C.plus(cIndex++, total); } } //CONCURRENT_ABOVE }); }
//CONCURRENT_OMIT_BEGIN /** * @see CommonOps_DDRM#multAdd(org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multAdd_aux(DMatrix1Row A, DMatrix1Row B, DMatrix1Row C, double[] aux) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numCols, B.numRows, "The 'A' and 'B' matrices do not have compatible dimensions"); UtilEjml.assertShape(A.numRows == C.numRows && B.numCols == C.numCols, "C is not compatible with A and B"); if (aux == null) { aux = new double[B.numRows]; } for (int j = 0; j < B.numCols; j++) { // create a copy of the column in B to avoid cache issues for (int k = 0; k < B.numRows; k++) { aux[k] = B.unsafe_get(k, j); } int indexA = 0; for (int i = 0; i < A.numRows; i++) { double total = 0; for (int k = 0; k < B.numRows;) { total += A.data[indexA++] * aux[k++]; } C.plus(i * C.numCols + j, total); } } }
/** * @see CommonOps_DDRM#multAdd(double, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multAdd_reorder(double alpha, DMatrix1Row A, DMatrix1Row B, DMatrix1Row C) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numCols, B.numRows, "The 'A' and 'B' matrices do not have compatible dimensions"); UtilEjml.assertShape(A.numRows == C.numRows && B.numCols == C.numCols, "C is not compatible with A and B"); if (A.numCols == 0 || A.numRows == 0) { return; } int endOfKLoop = B.numRows * B.numCols; //CONCURRENT_BELOW EjmlConcurrency.loopFor(0, A.numRows, i -> { for (int i = 0; i < A.numRows; i++) { int indexCbase = i * C.numCols; int indexA = i * A.numCols; // need to assign C.data to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + B.numCols; double valA = alpha * A.data[indexA++]; while (indexB < end) { C.plus(indexC++, valA * B.data[indexB++]); } // now add to it while (indexB != endOfKLoop) { // k loop indexC = indexCbase; end = indexB + B.numCols; valA = alpha * A.data[indexA++]; while (indexB < end) { // j loop C.data[indexC++] += valA * B.data[indexB++]; } } } //CONCURRENT_ABOVE }); }
//CONCURRENT_OMIT_END /** * @see CommonOps_DDRM#multAddTransA(org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multAddTransA_reorder(DMatrix1Row A, DMatrix1Row B, DMatrix1Row C) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numRows, B.numRows, "The 'A' and 'B' matrices do not have compatible dimensions"); UtilEjml.assertShape(A.numCols == C.numRows && B.numCols == C.numCols, "C is not compatible with A and B"); if (A.numCols == 0 || A.numRows == 0) { return; } //CONCURRENT_BELOW EjmlConcurrency.loopFor(0, A.numRows, i -> { for (int i = 0; i < A.numCols; i++) { int indexC_start = i * C.numCols; // first assign R double valA = A.data[i]; int indexB = 0; int end = indexB + B.numCols; int indexC = indexC_start; while (indexB < end) { C.plus(indexC++, valA * B.data[indexB++]); } // now increment it for (int k = 1; k < A.numRows; k++) { valA = A.unsafe_get(k, i); end = indexB + B.numCols; indexC = indexC_start; // this is the loop for j while (indexB < end) { C.data[indexC++] += valA * B.data[indexB++]; } } } //CONCURRENT_ABOVE }); }
//CONCURRENT_OMIT_BEGIN /** * @see CommonOps_DDRM#multAddTransAB(org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multAddTransAB_aux(DMatrix1Row A, DMatrix1Row B, DMatrix1Row C, double[] aux) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numRows, B.numCols, "The 'A' and 'B' matrices do not have compatible dimensions"); UtilEjml.assertShape(A.numCols == C.numRows && B.numRows == C.numCols, "C is not compatible with A and B"); if (aux == null) { aux = new double[A.numRows]; } if (A.numCols == 0 || A.numRows == 0) { return; } int indexC = 0; for (int i = 0; i < A.numCols; i++) { for (int k = 0; k < B.numCols; k++) { aux[k] = A.unsafe_get(k, i); } for (int j = 0; j < B.numRows; j++) { double total = 0; for (int k = 0; k < B.numCols; k++) { total += aux[k] * B.unsafe_get(j, k); } C.plus(indexC++, total); } } }