简体   繁体   English

如何使用流将 2 个 double[][] 矩阵相乘?

[英]How to multiply 2 double[][] matrices using streams?

I'm wondering what the most compact and efficient way to multiple 2 double[][] arrays matrices using streams.我想知道使用流处理多个 2 double[][]数组矩阵的最紧凑和最有效的方法是什么。 The approach should follow matrix multiplication rules as illustrated here:该方法应遵循矩阵乘法规则,如下所示:

Matrix Multiplication: How to Multiply Two Matrices Together 矩阵乘法:如何将两个矩阵相乘

Here's one way to do it using for loops ( this is the first matrix):这是使用 for 循环的一种方法( this是第一个矩阵):

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[][] mb1 = {{4d, 8d}, {0d, 2d}, {1d, 6d}};
double[][] mb2 = {{5d}, {9d}};

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[][] .一个更紧凑和可读的解决方案是在第一个矩阵的行上创建一个 Stream ,将每一行映射到将它与第二个矩阵列相乘的结果并将其收集回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));
    // [[92.0, 40.0], [18.0, 8.0], [59.0, 26.0]]
}

This will calculate m1 * m2 and the result will be in result .这将计算m1 * m2并且结果将在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.对于每一行的乘法,我们不能用第二个矩阵的Arrays.stream创建一个 Stream,因为当我们需要一个 Stream 在列上时,这会在行上创建一个 Stream。 To counteract that, we simply go back to using an IntStream over the indexes.为了解决这个问题,我们简单地回到对索引使用IntStream

I created a BiFunction that performs the multiplication using IntStream.range() .我创建了一个 BiFunction,它使用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);
    };
}

You can use three nested IntStream s to multiply two matrices.您可以使用三个嵌套的IntStream将两个矩阵相乘。 Outer stream iterates over the rows of the first matrix and the inner stream iterates over the columns of the second matrix to build the result matrix .外部流迭代第一个矩阵的行,内部流迭代第二个矩阵的列以构建结果矩阵 The innermost stream obtains the entries of the result matrix .最里面的流获得结果矩阵条目 Each entry is the sum of the products obtained by multiplying the i -th row of the first matrix and the j -th column of the second matrix :每个条目是通过将第一个矩阵i行和第二个矩阵的j列相乘获得的乘积之和:

/**
 * Matrix multiplication
 *
 * @param m rows of 'a' matrix
 * @param n columns of 'a' matrix
 *          and rows of 'b' matrix
 * @param p columns of 'b' matrix
 * @param a first matrix 'm×n'
 * @param b second matrix 'n×p'
 * @return result matrix 'm×p'
 */
public static double[][] matrixMultiplication(
        int m, int n, int p, double[][] a, double[][] b) {
    return IntStream.range(0, m)
            .mapToObj(i -> IntStream.range(0, p)
                    .mapToDouble(j -> IntStream.range(0, n)
                            .mapToDouble(k -> a[i][k] * b[k][j])
                            .sum())
                    .toArray())
            .toArray(double[][]::new);
}

// test
public static void main(String[] args) {
    double[][] md1 = {{4d, 8d}, {0d, 2d}, {1d, 6d}};
    double[][] md2 = {{5d, 2d, 5d, 5d}, {9d, 4d, 5d, 5d}};
    double[][] md3 = matrixMultiplication(3, 2, 4, md1, md2);

    Arrays.stream(md3).map(Arrays::toString).forEach(System.out::println);
    //[92.0, 40.0, 60.0, 60.0]
    //[18.0, 8.0, 10.0, 10.0]
    //[59.0, 26.0, 35.0, 35.0]

    //// //// //// //// //// //// //// ////

    double[][] mb1 = {{4d, 8d}, {0d, 2d}, {1d, 6d}};
    double[][] mb2 = {{5d}, {9d}};
    double[][] mb3 = matrixMultiplication(3, 2, 1, mb1, mb2);

    Arrays.stream(mb3).map(Arrays::toString).forEach(System.out::println);
    //[92.0]
    //[18.0]
    //[59.0]
}

See also: Parallelized Matrix Multiplication另请参阅:并行矩阵乘法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM