forked from williamfiset/Algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMatrixInverse.java
More file actions
121 lines (110 loc) · 3.39 KB
/
MatrixInverse.java
File metadata and controls
121 lines (110 loc) · 3.39 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
package com.williamfiset.algorithms.linearalgebra;
import java.util.Arrays;
/**
* Matrix Inverse via Gaussian Elimination
*
* Finds the inverse of an n x n matrix by augmenting it with the identity
* matrix [A | I] and reducing to RREF. If A is invertible, the result is
* [I | A^(-1)].
*
* Time: O(n^3)
* Space: O(n^2)
*
* @author William Fiset, william.alexandre.fiset@gmail.com
*/
class MatrixInverse {
private static final double EPS = 0.00000001;
/**
* Computes the inverse of a square matrix using Gaussian elimination.
*
* @param matrix the n x n matrix to invert
* @return the inverse matrix, or null if the matrix is not square
*
* Time: O(n^3)
*/
static double[][] inverse(double[][] matrix) {
if (matrix.length != matrix[0].length) return null;
int n = matrix.length;
// Build augmented matrix [A | I]
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);
// Extract the inverse from the right half
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;
}
/** Reduces an augmented matrix to RREF in-place. */
private 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 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) {
double[][] matrix = {
{2, -4, 0},
{0, 6, 0},
{2, 2, -2}
};
double[][] inv = inverse(matrix);
for (double[] row : inv) System.out.println(Arrays.toString(row));
}
}