math - Java 8 Stream Matrix Multiplication 10X Slower Than For Loop? -
i have created module performs matrix multiplication using streams. can found here: https://github.com/firefly-math/firefly-math-linear-real/
i've attempted write benchmark in order compare stream loop implementation corresponding loop implementation in apache commons math.
the benchmark module here: https://github.com/firefly-math/firefly-math-benchmark
and actual benchmark here: https://github.com/firefly-math/firefly-math-benchmark/blob/master/src/main/java/com/fireflysemantics/benchmark/multiplybenchmark.java
when run benchmark on matrices sized 100x100 , 1000x1000 turns out apache commons math (uses loop) 10x faster (roughly) corresponding stream implementation.
# run complete. total time: 00:14:10 benchmark mode cnt score error units multiplybenchmark.multiplycm1000_1000 avgt 30 1040.804 ± 11.796 ms/op multiplybenchmark.multiplycm100_100 avgt 30 0.790 ± 0.010 ms/op multiplybenchmark.multiplyfm1000_1000 avgt 30 11981.228 ± 405.812 ms/op multiplybenchmark.multiplyfm100_100 avgt 30 7.224 ± 0.685 ms/op
did wrong in benchmark (hopefully :) )?
i'm adding methods tested such can see being compared. apache commons math array2drowrealmatrix.multiply() method:
/** * returns result of postmultiplying {@code this} {@code m}. * * @param m matrix postmultiply * @return {@code * m} * @throws dimensionmismatchexception if * {@code columndimension(this) != rowdimension(m)} */ public array2drowrealmatrix multiply(final array2drowrealmatrix m) throws dimensionmismatchexception { matrixutils.checkmultiplicationcompatible(this, m); final int nrows = this.getrowdimension(); final int ncols = m.getcolumndimension(); final int nsum = this.getcolumndimension(); final double[][] outdata = new double[nrows][ncols]; // hold column of "m". final double[] mcol = new double[nsum]; final double[][] mdata = m.data; // multiply. (int col = 0; col < ncols; col++) { // copy elements of column "col" of "m" // in contiguous memory. (int mrow = 0; mrow < nsum; mrow++) { mcol[mrow] = mdata[mrow][col]; } (int row = 0; row < nrows; row++) { final double[] datarow = data[row]; double sum = 0; (int = 0; < nsum; i++) { sum += datarow[i] * mcol[i]; } outdata[row][col] = sum; } } return new array2drowrealmatrix(outdata, false); }
and corresponding stream implementation:
/** * returns {@link binaryoperator} multiplies {@link simplematrix} * {@code m1} times {@link simplematrix} {@code m2} (m1 x m2). * * example {@code multiply(true).apply(m1, m2);} * * @param parallel * whether perform operation concurrently. * * @throws mathexception * of type {@code matrix_dimension_mismatch__multiplication} if * {@code m} not same size {@code this}. * * @return {@link binaryoperator} performs operation. */ public static binaryoperator<simplematrix> multiply(boolean parallel) { return (m1, m2) -> { checkmultiplicationcompatible(m1, m2); double[][] a1 = m1.toarray(); double[][] a2 = m2.toarray(); stream<double[]> stream = arrays.stream(a1); stream = parallel ? stream.parallel() : stream; final double[][] result = stream.map(r -> range(0, a2[0].length) .maptodouble(i -> range(0, a2.length).maptodouble(j -> r[j] * a2[j][i]).sum()) .toarray()).toarray(double[][]::new); return new simplematrix(result); }; }
tia, ole
take @ doublepipeline.toarray
:
public final double[] toarray() { return nodes.flattendouble((node.ofdouble) evaluatetoarraynode(double[]::new)) .asprimitivearray(); }
it seems boxed array created first converted primitive array.
Comments
Post a Comment