/****************************************************************************** * Compilation: javac GaussianEliminationLite.java * Execution: java GaussianEliminationLite * Dependencies: StdOut.java * * Gaussian elimination with partial pivoting. * * % java GaussianEliminationLite * -1.0 * 2.0 * 2.0 * ******************************************************************************/ /** * The {@code GaussianEliminationLite} class provides a static method to * solve a linear system of equations Ax = b, * where A is a nonsingular n-by-n matrix * and b is a length n vector. *

* This is a bare-bones implementation that uses Gaussian elimination * with partial pivoting. See {@link GaussianElimination} for a version * that also handles singular systems (in which there are either * infinitely many solutions or no solutions). * See {@link GaussJordanElimination} for an alternate implementation * that uses Gauss-Jordan elimination. * For an industrial-strength numerical linear algebra library, * see JAMA. *

* For additional documentation, see * Section 9.9 * Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne. * * @author Robert Sedgewick * @author Kevin Wayne */ public class GaussianEliminationLite { private static final double EPSILON = 1e-10; // Do not instantiate. private GaussianEliminationLite() { } /** * Returns the unique solution x to the specified linear system of * equation Ax = b, where A is a nonsingular matrix. * Warning: this implementation mutates the arguments A and b. * * @param A the nonsingular n-by-n constraint matrix * @param b the length n right-hand-side vector * @return the unique solution x to the linear system of equations * Ax = b * @throws ArithmeticException if the matrix is singular or nearly singular */ public static double[] lsolve(double[][] A, double[] b) { int n = b.length; for (int p = 0; p < n; p++) { // find pivot row and swap int max = p; for (int i = p + 1; i < n; i++) { if (Math.abs(A[i][p]) > Math.abs(A[max][p])) { max = i; } } swap(A, p, max); swap(b, p, max); // singular or nearly singular if (Math.abs(A[p][p]) <= EPSILON) { throw new ArithmeticException("Matrix is singular or nearly singular"); } // pivot within A and b for (int i = p + 1; i < n; i++) { double alpha = A[i][p] / A[p][p]; b[i] -= alpha * b[p]; for (int j = p; j < n; j++) { A[i][j] -= alpha * A[p][j]; } } } // back substitution double[] x = new double[n]; for (int i = n - 1; i >= 0; i--) { double sum = 0.0; for (int j = i + 1; j < n; j++) { sum += A[i][j] * x[j]; } x[i] = (b[i] - sum) / A[i][i]; } return x; } // swap entries a[i] and a[j] in array a[] private static void swap(double[] a, int i, int j) { double temp = a[i]; a[i] = a[j]; a[j] = temp; } // swap rows A[i][] and A[j][] in 2D array A[][] private static void swap(double[][] A, int i, int j) { double[] temp = A[i]; A[i] = A[j]; A[j] = temp; } /** * Unit tests the {@code GaussianEliminationLite} class. * * @param args the command-line arguments */ public static void main(String[] args) { int n = 3; double[][] A = { { 0, 1, 1 }, { 2, 4, -2 }, { 0, 3, 15 } }; double[] b = { 4, 2, 36 }; double[] x = lsolve(A, b); // print results for (int i = 0; i < n; i++) { StdOut.println(x[i]); } } }