Skip to content

Added a linear system solver #6196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions src/main/java/com/thealgorithms/matrix/SolveSystem.java
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions src/test/java/com/thealgorithms/matrix/SolveSystemTest.java
Original file line number Diff line number Diff line change
@@ -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}));
}
}