问题
I'm wondering what the most compact and efficient way to multiple 2 double[][]
arrays matrices using streams. The approach should follow matrix multiplication rules as illustrated here:
http://www.mathwarehouse.com/algebra/matrix/multiply-matrix.php
Here's one way to do it using for loops ('this' is the first matrix'):
final int nRows = this.getRowDimension();
final int nCols = m.getColumnDimension();
final int nSum = this.getColumnDimension();
final double[][] outData = new double[nRows][nCols];
// Will hold a column of "m".
final double[] mCol = new double[nSum];
final double[][] mData = m.data;
// Multiply.
for (int col = 0; col < nCols; col++) {
// Copy all elements of column "col" of "m" so that
// will be in contiguous memory.
for (int mRow = 0; mRow < nSum; mRow++) {
mCol[mRow] = mData[mRow][col];
}
for (int row = 0; row < nRows; row++) {
final double[] dataRow = data[row];
double sum = 0;
for (int i = 0; i < nSum; i++) {
sum += dataRow[i]
* mCol[i];
}
outData[row][col] = sum;
}
}
The procedure should fit the following test data:
double[][] md1 = { { 4d, 8d }, { 0d, 2d }, { 1d, 6d } };
double[][] md2 = { { 5d, 2d, 5d, 5d }, { 9d, 4d, 5d, 5d } };
double[][] md1 = { { 4d, 8d }, { 0d, 2d }, { 1d, 6d } };
double[][] md2 = { { 5d }, { 9d } };
回答1:
A more compact and readable solution is to create a Stream over the rows of the first matrix, map each row to the result of multiplying it with the second matrix column and collect that back into a double[][]
.
public static void main(String[] args) {
double[][] m1 = { { 4, 8 }, { 0, 2 }, { 1, 6 } };
double[][] m2 = { { 5, 2 }, { 9, 4 } };
double[][] result = Arrays.stream(m1).map(r ->
IntStream.range(0, m2[0].length).mapToDouble(i ->
IntStream.range(0, m2.length).mapToDouble(j -> r[j] * m2[j][i]).sum()
).toArray()).toArray(double[][]::new);
System.out.println(Arrays.deepToString(result));
}
This will calculate m1 * m2
and the result will be in result
. For the multiplication of each row, we can't create a Stream with Arrays.stream
of the second matrix since this would create a Stream over the rows when we need a Stream over the columns. To counteract that, we simply go back to using an IntStream
over the indexes.
回答2:
I created a BiFunction that performs the multiplication using IntStream.range(). If anyone has anything more compact I would love to see it. Here it is:
public static BiFunction<ArrayMatrix, ArrayMatrix, ArrayMatrix> multiply(boolean parallel) {
return (m1, m2) -> {
// checkMultiplicationCompatible(m1, m2);
final int m1Rows = m1.getRowDimension();
final int m2Rows = m2.getRowDimension();
final int m1Cols = m1.getColumnDimension();
final int m2Cols = m2.getColumnDimension();
double[][] a1 = m1.getData();
double[][] a2 = m2.getData();
final double[][] result = new double[m1Rows][m2Cols];
// Buffer for the tranpose of each md2 column
final double[] transpose = new double[m1Rows];
range(0, m2Cols).forEach(m2Col -> {
range(0, m2Rows).forEach(m2Row -> {
transpose[m2Row] = a2[m2Row][m2Col];
});
range(0, m1Rows).forEach(row -> {
final double[] dataRow = a1[row];
double sum = 0;
for (int m1Col = 0; m1Col < m1Cols; m1Col++) {
sum += dataRow[m1Col]
* transpose[m1Col];
}
result[row][m2Col] = sum;
});
});
return new ArrayMatrix(result, false);
};
}
来源:https://stackoverflow.com/questions/34774384/multiply-2-double-matrices-using-streams