-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Samuel Abramov
committed
Oct 11, 2023
1 parent
d5f45ec
commit 462dd79
Showing
8 changed files
with
251 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
lib/src/main/java/de/edux/util/math/ConcurrentMatrixMultiplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package de.edux.util.math; | ||
|
||
public interface ConcurrentMatrixMultiplication { | ||
|
||
/** | ||
* Multiplies two matrices and returns the resulting matrix. | ||
* | ||
* @param a The first matrix. | ||
* @param b The second matrix. | ||
* @return The product of the two matrices. | ||
* @throws IllegalArgumentException If the matrices cannot be multiplied due to incompatible dimensions. | ||
*/ | ||
double[][] multiplyMatrices(double[][] a, double[][] b) throws IllegalArgumentException, IncompatibleDimensionsException; | ||
|
||
|
||
|
||
} |
7 changes: 7 additions & 0 deletions
7
lib/src/main/java/de/edux/util/math/IncompatibleDimensionsException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package de.edux.util.math; | ||
|
||
public class IncompatibleDimensionsException extends Exception{ | ||
public IncompatibleDimensionsException(String message) { | ||
super(message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package de.edux.util.math; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.Future; | ||
|
||
public class MathMatrix implements ConcurrentMatrixMultiplication { | ||
private static final Logger LOG = LoggerFactory.getLogger(MathMatrix.class); | ||
|
||
@Override | ||
public double[][] multiplyMatrices(double[][] a, double[][] b) throws IncompatibleDimensionsException { | ||
LOG.info("Multiplying matrices of size {}x{} and {}x{}", a.length, a[0].length, b.length, b[0].length); | ||
int aRows = a.length; | ||
int aCols = a[0].length; | ||
int bCols = b[0].length; | ||
|
||
if (aCols != b.length) { | ||
throw new IncompatibleDimensionsException("Cannot multiply matrices with incompatible dimensions"); | ||
} | ||
|
||
double[][] result = new double[aRows][bCols]; | ||
|
||
try(var executor = Executors.newVirtualThreadPerTaskExecutor()) { | ||
List<Future<Void>> futures = new ArrayList<>(aRows); | ||
|
||
for (int i = 0; i < aRows; i++) { | ||
final int rowIndex = i; | ||
futures.add(executor.submit(() -> { | ||
for (int colIndex = 0; colIndex < bCols; colIndex++) { | ||
result[rowIndex][colIndex] = multiplyMatrixRowByColumn(a, b, rowIndex, colIndex); | ||
} | ||
return null; | ||
})); | ||
} | ||
for (var future : futures) { | ||
future.get(); | ||
} | ||
} catch (ExecutionException | InterruptedException e) { | ||
LOG.error("Error while multiplying matrices", e); | ||
} | ||
|
||
LOG.info("Finished multiplying matrices"); | ||
return result; | ||
} | ||
|
||
private double multiplyMatrixRowByColumn(double[][] a, double[][] b, int row, int col) { | ||
double sum = 0; | ||
for (int i = 0; i < a[0].length; i++) { | ||
sum += a[row][i] * b[i][col]; | ||
} | ||
return sum; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package de.edux.util.math; | ||
|
||
public interface MatrixOperations { | ||
/** | ||
* Adds two matrices and returns the resulting matrix. | ||
* | ||
* @param a The first matrix. | ||
* @param b The second matrix. | ||
* @return The sum of the two matrices. | ||
* @throws IllegalArgumentException If the matrices are not of the same dimension. | ||
*/ | ||
double[][] addMatrices(double[][] a, double[][] b) throws IllegalArgumentException; | ||
|
||
/** | ||
* Subtracts matrix b from matrix a and returns the resulting matrix. | ||
* | ||
* @param a The first matrix. | ||
* @param b The second matrix. | ||
* @return The result of a - b. | ||
* @throws IllegalArgumentException If the matrices are not of the same dimension. | ||
*/ | ||
double[][] subtractMatrices(double[][] a, double[][] b) throws IllegalArgumentException; | ||
|
||
/** | ||
* Transposes the given matrix and returns the resulting matrix. | ||
* | ||
* @param a The matrix to transpose. | ||
* @return The transposed matrix. | ||
*/ | ||
double[][] transposeMatrix(double[][] a); | ||
|
||
/** | ||
* Inverts the given matrix and returns the resulting matrix. | ||
* | ||
* @param a The matrix to invert. | ||
* @return The inverted matrix. | ||
* @throws IllegalArgumentException If the matrix is not invertible. | ||
*/ | ||
double[][] invertMatrix(double[][] a) throws IllegalArgumentException; | ||
|
||
/** | ||
* Calculates and returns the determinant of the given matrix. | ||
* | ||
* @param a The matrix. | ||
* @return The determinant of the matrix. | ||
* @throws IllegalArgumentException If the matrix is not square. | ||
*/ | ||
double determinant(double[][] a) throws IllegalArgumentException; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
lib/src/test/java/de/edux/util/math/MathMatrixTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package de.edux.util.math; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.Future; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
class MathMatrixTest { | ||
private static final long someMaximumValue = 1_000_000_000; // Example value | ||
private static final Logger LOG = LoggerFactory.getLogger(MathMatrixTest.class); | ||
|
||
@Test | ||
void multiplyMatrices() throws IncompatibleDimensionsException { | ||
long startTime = System.currentTimeMillis(); | ||
int size = 500; | ||
|
||
double[][] matrixA = generateMatrix(size); | ||
double[][] matrixB = generateMatrix(size); | ||
|
||
ConcurrentMatrixMultiplication matrixMultiplier = new MathMatrix(); | ||
double[][] resultMatrix = matrixMultiplier.multiplyMatrices(matrixA, matrixB); | ||
|
||
assertEquals(size, resultMatrix.length); | ||
assertEquals(size, resultMatrix[0].length); | ||
|
||
long endTime = System.currentTimeMillis(); | ||
long timeElapsed = endTime - startTime; | ||
LOG.info("Time elapsed: " + timeElapsed / 1000 + " seconds"); | ||
} | ||
|
||
@Test | ||
void multiplyMatricesSmall() throws IncompatibleDimensionsException { | ||
double[][] matrixA = { | ||
{1, 2}, | ||
{3, 4} | ||
}; | ||
|
||
double[][] matrixB = { | ||
{2, 0}, | ||
{1, 3} | ||
}; | ||
|
||
ConcurrentMatrixMultiplication matrixMultiplier = new MathMatrix(); | ||
double[][] resultMatrix = matrixMultiplier.multiplyMatrices(matrixA, matrixB); | ||
|
||
double[][] expectedMatrix = { | ||
{4, 6}, | ||
{10, 12} | ||
}; | ||
|
||
assertArrayEquals(expectedMatrix, resultMatrix); | ||
} | ||
|
||
static void assertArrayEquals(double[][] expected, double[][] actual) { | ||
assertEquals(expected.length, actual.length); | ||
|
||
for (int i = 0; i < expected.length; i++) { | ||
assertArrayEquals(expected[i], actual[i]); | ||
} | ||
} | ||
|
||
static void assertArrayEquals(double[] expected, double[] actual) { | ||
assertEquals(expected.length, actual.length); | ||
|
||
for (int i = 0; i < expected.length; i++) { | ||
assertEquals(expected[i], actual[i]); | ||
} | ||
} | ||
|
||
double[][] generateMatrix(int size) { | ||
double[][] matrix = new double[size][size]; | ||
final int MAX_THREADS = 32; | ||
|
||
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); | ||
List<Future<Void>> futures = new ArrayList<>(); | ||
|
||
try { | ||
int rowsPerThread = Math.max(size / MAX_THREADS, 1); | ||
|
||
for (int i = 0; i < MAX_THREADS && i * rowsPerThread < size; i++) { | ||
final int startRow = i * rowsPerThread; | ||
final int endRow = Math.min((i + 1) * rowsPerThread, size); | ||
|
||
futures.add(executor.submit(() -> { | ||
for (int row = startRow; row < endRow; row++) { | ||
for (int col = 0; col < size; col++) { | ||
matrix[row][col] = Math.random() * 10; // Random values between 0 and 10 | ||
} | ||
} | ||
return null; | ||
})); | ||
} | ||
|
||
for (Future<Void> future : futures) { | ||
future.get(); | ||
} | ||
} catch (InterruptedException | ExecutionException e) { | ||
e.printStackTrace(); | ||
} finally { | ||
executor.shutdown(); | ||
} | ||
|
||
LOG.info("Generated matrix with size: " + size); | ||
return matrix; | ||
} | ||
|
||
} |