forked from williamfiset/Algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MatrixInverse.java
96 lines (87 loc) · 3.08 KB
/
MatrixInverse.java
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
/**
* Use Gaussian elimination on an augmented matrix to find the inverse of a matrix.
*
* <p>Time Complexity: O(n^3)
*/
package com.williamfiset.algorithms.linearalgebra;
class MatrixInverse {
// Define a small value of epsilon to compare double values
static final double EPS = 0.00000001;
// Invert the specified matrix. Assumes invertibility. Time Complexity: O(r²c)
static double[][] inverse(double[][] matrix) {
if (matrix.length != matrix[0].length) return null;
int n = matrix.length;
double[][] augmented = new double[n][n * 2];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) augmented[i][j] = matrix[i][j];
augmented[i][i + n] = 1;
}
solve(augmented);
double[][] inv = new double[n][n];
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) inv[i][j] = augmented[i][j + n];
return inv;
}
// Solves a system of linear equations as an augmented matrix
// with the rightmost column containing the constants. The answers
// will be stored on the rightmost column after the algorithm is done.
// NOTE: make sure your matrix is consistent and does not have multiple
// solutions before you solve the system if you want a unique valid answer.
// Time Complexity: O(r²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;
int i = r;
while (Math.abs(augmentedMatrix[i][lead]) < EPS) {
if (++i == nRows) {
i = r;
if (++lead == nCols) return;
}
}
double[] temp = augmentedMatrix[r];
augmentedMatrix[r] = augmentedMatrix[i];
augmentedMatrix[i] = temp;
double lv = augmentedMatrix[r][lead];
for (int j = 0; j < nCols; j++) augmentedMatrix[r][j] /= lv;
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 matrix is inconsistent
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;
}
// Make sure your matrix is consistent as well
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) {
// Check this matrix is invertable
double[][] matrix = {
{2, -4, 0},
{0, 6, 0},
{2, 2, -2}
};
double[][] inv = inverse(matrix);
for (double[] row : inv) System.out.println(java.util.Arrays.toString(row));
}
}