forked from williamfiset/Algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGaussianElimination.java
More file actions
125 lines (113 loc) · 3.77 KB
/
GaussianElimination.java
File metadata and controls
125 lines (113 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.williamfiset.algorithms.linearalgebra;
/**
* Gaussian Elimination for Solving Linear Systems
*
* Solves a system of linear equations by reducing an augmented matrix
* [A | b] to reduced row echelon form (RREF). After reduction, the
* solution (if unique) appears in the rightmost column.
*
* The algorithm uses partial pivoting (row swaps) for numerical stability
* and eliminates both above and below each pivot to produce RREF directly.
*
* Use cases:
* - Solving systems of linear equations
* - Checking for inconsistency or infinite solutions
*
* Time: O(r^2*c) where r = rows, c = columns
* Space: O(1) (in-place)
*
* @author William Fiset, william.alexandre.fiset@gmail.com
*/
class GaussianElimination {
private static final double EPS = 0.00000001;
/**
* Reduces an augmented matrix to RREF in-place. After solving, the
* rightmost column contains the solution values (if the system is
* consistent with a unique solution).
*
* @param augmentedMatrix the [A | b] matrix to reduce
*
* Time: O(r^2*c)
*/
static void solve(double[][] augmentedMatrix) {
int nRows = augmentedMatrix.length, nCols = augmentedMatrix[0].length, lead = 0;
for (int r = 0; r < nRows; r++) {
if (lead >= nCols) break;
// Find pivot: row with non-zero entry in the lead column
int i = r;
while (Math.abs(augmentedMatrix[i][lead]) < EPS) {
if (++i == nRows) {
i = r;
if (++lead == nCols) return;
}
}
// Swap pivot row into position
double[] temp = augmentedMatrix[r];
augmentedMatrix[r] = augmentedMatrix[i];
augmentedMatrix[i] = temp;
// Scale pivot row so leading entry becomes 1
double lv = augmentedMatrix[r][lead];
for (int j = 0; j < nCols; j++)
augmentedMatrix[r][j] /= lv;
// Eliminate all other rows in this column
for (i = 0; i < nRows; i++) {
if (i != r) {
lv = augmentedMatrix[i][lead];
for (int j = 0; j < nCols; j++)
augmentedMatrix[i][j] -= lv * augmentedMatrix[r][j];
}
}
lead++;
}
}
/**
* Checks if the reduced matrix represents an inconsistent system
* (a row of all zeros on the left with a non-zero constant on the right).
*/
static boolean isInconsistent(double[][] arr) {
int nCols = arr[0].length;
outer:
for (int y = 0; y < arr.length; y++) {
if (Math.abs(arr[y][nCols - 1]) > EPS) {
for (int x = 0; x < nCols - 1; x++) if (Math.abs(arr[y][x]) > EPS) continue outer;
return true;
}
}
return false;
}
/**
* Checks if the reduced matrix has more unknowns than non-empty rows,
* indicating infinitely many solutions. Call after verifying consistency.
*/
static boolean hasMultipleSolutions(double[][] arr) {
int nCols = arr[0].length, nEmptyRows = 0;
outer:
for (int y = 0; y < arr.length; y++) {
for (int x = 0; x < nCols; x++) if (Math.abs(arr[y][x]) > EPS) continue outer;
nEmptyRows++;
}
return nCols - 1 > arr.length - nEmptyRows;
}
public static void main(String[] args) {
// Suppose we want to solve the following system for
// the variables x, y, z:
//
// 2x - 3y + 5z = 10
// x + 2y - z = 18
// 6x - y + 0 = 12
// Then we would setup the following augment matrix:
double[][] augmentedMatrix = {
{2, -3, 5, 10},
{1, 2, -1, 18},
{6, -1, 0, 12}
};
solve(augmentedMatrix);
if (!hasMultipleSolutions(augmentedMatrix) && !isInconsistent(augmentedMatrix)) {
double x = augmentedMatrix[0][3];
double y = augmentedMatrix[1][3];
double z = augmentedMatrix[2][3];
// x ~ 3.755, y ~ 10.531, z ~ 6.816
System.out.printf("x = %.3f, y = %.3f, z = %.3f\n", x, y, z);
}
}
}