MatrixMultiply
Contents
Motivation
We gain experience using the parallel for loop constructs.
Background
Matrix multiplication is a simple mathematical operation which we will replicate in this studio. For our purposes, we will only deal with square matrices (same number of rows and columns). However, we will approach this problem with several different parallel constructs and approaches.
For those unfamiliar on how to multiply two matrices, take a look at these overviews:
If is an matrix and is an matrix
for each i=[0..n) and for each j=[0..p)
source: Matrix Multiplication on Wikipedia
Code To Investigate
Demo Video
SequentialMatrixMultiplier
class: | SequentialMatrixMultiplier.java | DEMO: |
methods: | multiply | |
package: | matrixmultiply.demo | |
source folder: | src//java |
SequentialMatrixMultiplierClient
class: | SequentialMatrixMultiplierClient.java | DEMO: |
methods: | main | |
package: | matrixmultiply.client | |
source folder: | src//java |
The Core Questions
- What are the tasks?
- What is the data?
- Is the data mutable?
- If so, how is it shared?
Code To Implement
There are three methods you will need to implement, all of which are different ways to use parallel for loops to solve the problem. To assist you, the sequential implementation has already been completed for you. We recommend starting from the top and working your way down. There is also an optional recursive implementation and a manual grouping implementation which has been done for you (this is just to demonstrate how chunking works behind the scenes).
LoopLoopMatrixMultiplier
class: | LoopLoopMatrixMultiplier.java | |
methods: | multiply | |
package: | matrixmultiply.exercise | |
source folder: | student/src/main/java |
method: public double[][] multiply(double[][] a, double[][] b)
(parallel implementation required)
In this implementation, you will simply convert the sequential solution into a parallel one using parallel fork loops.
Loop2dMatrixMultiplier
class: | Loop2dMatrixMultiplier.java | |
methods: | multiply | |
package: | matrixmultiply.exercise | |
source folder: | student/src/main/java |
method: public double[][] multiply(double[][] a, double[][] b)
(parallel implementation required)
Forall2dChunkedMatrixMultiplier
class: | Loop2dAutoCoarsenMatrixMultiplier.java | |
methods: | multiply | |
package: | matrixmultiply.exercise | |
source folder: | student/src/main/java |
method: public double[][] multiply(double[][] a, double[][] b)
(parallel implementation required)
Optional Divide and Conquer Challenges
In this implementation, you will solve the matrix multiply problem sequentially and in parallel using recursion. Although this class should be able to take in a matrix of any size, try to imagine this as a 2x2 matrix in order to make it easier to solve. Once you solve the sequential method, the parallel method should look very similar with exception of an async/finish block.
In order to obtain the desired result matrix, you will need to recursively call the correct submatrices for each of the four result submatrices. Imagining this as a 2x2 matrix, remember that the dot products of the rows of the first matrix and the columns of the second matrix create the result matrix.
Hint: Each result submatrix should have two recursive calls, for a total of eight recursive calls.
OffsetSubMatrix
class: | OffsetSubMatrix.java | |
methods: | sequentialMultiply parallelMultiply |
|
package: | matrixmultiply.challenge | |
source folder: | student/src/main/java |
sequentialMultiply(a, b)
method: void sequentialMultiply(OffsetSubMatrix a, OffsetSubMatrix b)
(sequential implementation only)
In class OffsetSubMatrix
, method sequentialMultiply
you will find your base case and the sub matrices prepared for you.
void sequentialMultiply(OffsetSubMatrix a, OffsetSubMatrix b) { if (size == 1) { values[row][col] += (a.values[a.row][a.col] * b.values[b.row][b.col]); } else { OffsetSubMatrix result11 = sub11(); OffsetSubMatrix result12 = sub12(); OffsetSubMatrix result21 = sub21(); OffsetSubMatrix result22 = sub22(); OffsetSubMatrix a11 = a.sub11(); OffsetSubMatrix a12 = a.sub12(); OffsetSubMatrix a21 = a.sub21(); OffsetSubMatrix a22 = a.sub22(); OffsetSubMatrix b11 = b.sub11(); OffsetSubMatrix b12 = b.sub12(); OffsetSubMatrix b21 = b.sub21(); OffsetSubMatrix b22 = b.sub22(); // https://en.wikipedia.org/wiki/Matrix_multiplication_algorithm#Divide_and_conquer_algorithm throw new NotYetImplementedException(); } }
You simply need to make the appropriate recursive calls to compute the result on the right:
source: Wikipedia Parallel Matrix Multiplication
parallelMultiply(a, b, isParallelPredicate)
method: void parallelMultiply(OffsetSubMatrix a, OffsetSubMatrix b, IntPredicate isParallelPredicate)
(parallel implementation required)
Again, given the following:
source: Wikipedia Parallel Matrix Multiplication
What computation can be done in parallel? What computation must be performed sequentially?
Warning: The resulting data (this.values) is mutated and shared. |
void parallelMultiply(OffsetSubMatrix a, OffsetSubMatrix b, IntPredicate isParallelPredicate) throws InterruptedException, ExecutionException { if (size > 1 && isParallelPredicate.test(size)) { OffsetSubMatrix result11 = sub11(); OffsetSubMatrix result12 = sub12(); OffsetSubMatrix result21 = sub21(); OffsetSubMatrix result22 = sub22(); OffsetSubMatrix a11 = a.sub11(); OffsetSubMatrix a12 = a.sub12(); OffsetSubMatrix a21 = a.sub21(); OffsetSubMatrix a22 = a.sub22(); OffsetSubMatrix b11 = b.sub11(); OffsetSubMatrix b12 = b.sub12(); OffsetSubMatrix b21 = b.sub21(); OffsetSubMatrix b22 = b.sub22(); throw new NotYetImplementedException(); } else { sequentialMultiply(a, b); } }
Testing Your Solution
Correctness
class: | MatrixMultiplyTestSuite.java | |
package: | matrixmultiply.studio | |
source folder: | testing/src/test/java |
Optional Fun Divide And Conquer Matrix Multiply Correctness
class: | DivideAndConquerMatrixMultiplyTestSuite.java | |
package: | matrixmultiply.challenge | |
source folder: | testing/src/test/java |
Performance
class: | MatrixMultiplicationTiming.java | |
package: | matrixmultiply.studio | |
source folder: | src/main/java |