mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-05 16:27:33 +08:00
Add a linear system solver (#6196)
This commit is contained in:
71
src/main/java/com/thealgorithms/matrix/SolveSystem.java
Normal file
71
src/main/java/com/thealgorithms/matrix/SolveSystem.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package com.thealgorithms.matrix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements an algorithm for solving a system of equations of the form Ax=b using gaussian elimination and back substitution.
|
||||||
|
*
|
||||||
|
* @link <a href="https://en.wikipedia.org/wiki/Gaussian_elimination">Gaussian Elimination Wiki</a>
|
||||||
|
* @see InverseOfMatrix finds the full of inverse of a matrice, but is not required to solve a system.
|
||||||
|
*/
|
||||||
|
public final class SolveSystem {
|
||||||
|
private SolveSystem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Problem: Given a matrix A and vector b, solve the linear system Ax = b for the vector x.\
|
||||||
|
* <p>
|
||||||
|
* <b>This OVERWRITES the input matrix to save on memory</b>
|
||||||
|
*
|
||||||
|
* @param matrix - a square matrix of doubles
|
||||||
|
* @param constants - an array of constant
|
||||||
|
* @return solutions
|
||||||
|
*/
|
||||||
|
public static double[] solveSystem(double[][] matrix, double[] constants) {
|
||||||
|
final double tol = 0.00000001; // tolerance for round off
|
||||||
|
for (int k = 0; k < matrix.length - 1; k++) {
|
||||||
|
// find the largest value in column (to avoid zero pivots)
|
||||||
|
double maxVal = Math.abs(matrix[k][k]);
|
||||||
|
int maxIdx = k;
|
||||||
|
for (int j = k + 1; j < matrix.length; j++) {
|
||||||
|
if (Math.abs(matrix[j][k]) > maxVal) {
|
||||||
|
maxVal = matrix[j][k];
|
||||||
|
maxIdx = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Math.abs(maxVal) < tol) {
|
||||||
|
// hope the matrix works out
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// swap rows
|
||||||
|
double[] temp = matrix[k];
|
||||||
|
matrix[k] = matrix[maxIdx];
|
||||||
|
matrix[maxIdx] = temp;
|
||||||
|
double tempConst = constants[k];
|
||||||
|
constants[k] = constants[maxIdx];
|
||||||
|
constants[maxIdx] = tempConst;
|
||||||
|
for (int i = k + 1; i < matrix.length; i++) {
|
||||||
|
// compute multipliers and save them in the column
|
||||||
|
matrix[i][k] /= matrix[k][k];
|
||||||
|
for (int j = k + 1; j < matrix.length; j++) {
|
||||||
|
matrix[i][j] -= matrix[i][k] * matrix[k][j];
|
||||||
|
}
|
||||||
|
constants[i] -= matrix[i][k] * constants[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// back substitution
|
||||||
|
double[] x = new double[constants.length];
|
||||||
|
System.arraycopy(constants, 0, x, 0, constants.length);
|
||||||
|
for (int i = matrix.length - 1; i >= 0; i--) {
|
||||||
|
double sum = 0;
|
||||||
|
for (int j = i + 1; j < matrix.length; j++) {
|
||||||
|
sum += matrix[i][j] * x[j];
|
||||||
|
}
|
||||||
|
x[i] = constants[i] - sum;
|
||||||
|
if (Math.abs(matrix[i][i]) > tol) {
|
||||||
|
x[i] /= matrix[i][i];
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Matrix was found to be singular");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
21
src/test/java/com/thealgorithms/matrix/SolveSystemTest.java
Normal file
21
src/test/java/com/thealgorithms/matrix/SolveSystemTest.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package com.thealgorithms.matrix;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
class SolveSystemTest {
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource({"matrixGenerator"})
|
||||||
|
void solveSystem(double[][] matrix, double[] constants, double[] solution) {
|
||||||
|
double[] expected = SolveSystem.solveSystem(matrix, constants);
|
||||||
|
assertArrayEquals(expected, solution, 1.0E-10, "Solution does not match expected");
|
||||||
|
}
|
||||||
|
private static Stream<Arguments> matrixGenerator() {
|
||||||
|
return Stream.of(Arguments.of(new double[][] {{-5, 8, -4}, {0, 6, 3}, {0, 0, -4}}, new double[] {38, -9, 20}, new double[] {-2, 1, -5}), Arguments.of(new double[][] {{-2, -1, -1}, {3, 4, 1}, {3, 6, 5}}, new double[] {-11, 19, 43}, new double[] {2, 2, 5}));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user