Skip to content

Commit ddee4e8

Browse files
authored
Merge pull request #51 from StaticBeagle/adding-solve-to-matrix-sparse
Integrating decomposition and solve methods to matrix classes
2 parents 145b7b7 + a463205 commit ddee4e8

File tree

8 files changed

+132
-49
lines changed

8 files changed

+132
-49
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ Maven
3636
<dependency>
3737
<groupId>com.wildbitsfoundry</groupId>
3838
<artifactId>etk4j</artifactId>
39-
<version>2.2.0</version>
39+
<version>2.2.1</version>
4040
</dependency>
4141
```
4242
Gradle
4343
```bash
44-
implementation 'com.wildbitsfoundry:etk4j:2.2.0'
44+
implementation 'com.wildbitsfoundry:etk4j:2.2.1'
4545
```
4646

4747
Requirements

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>com.wildbitsfoundry</groupId>
44
<artifactId>etk4j</artifactId>
5-
<version>2.2.0</version>
5+
<version>2.2.1</version>
66
<name>Engineering Toolkit for Java</name>
77
<description>Tools and implementation of mathematical methods or backing math for engineering problems and
88
applications.

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/ComplexLUDecompositionDense.java

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@
44

55
import java.util.Arrays;
66

7-
public class ComplexLUDecompositionDense {
7+
public class ComplexLUDecompositionDense extends ComplexLUDecomposition<ComplexMatrix> {
88
protected Complex[] _data;
9-
protected final int _rows;
10-
protected final int _cols;
119

1210
protected int _pivotsign = 1;
1311
protected int[] _pivot;
1412

1513
public ComplexLUDecompositionDense(ComplexMatrixDense matrix) {
16-
final int rows = matrix.getRowCount();
14+
super(matrix);
15+
final int rows = matrix.getRowCount();
1716
final int cols = matrix.getColumnCount();
1817
Complex[] data = matrix.getArrayCopy();
1918

@@ -67,28 +66,26 @@ public ComplexLUDecompositionDense(ComplexMatrixDense matrix) {
6766
}
6867
}
6968
_data = data;
70-
_rows = rows;
71-
_cols = cols;
7269
}
7370

74-
public boolean isNonSingular() {
75-
for (int j = 0; j < _cols; ++j) {
76-
if (_data[j * _cols + j].equals(new Complex())) {
77-
return false;
71+
@Override
72+
public boolean isSingular() {
73+
for (int j = 0; j < cols; ++j) {
74+
if (_data[j * cols + j].equals(new Complex())) {
75+
return true;
7876
}
7977
}
80-
return true;
78+
return false;
8179
}
8280

81+
8382
/**
8483
* Return lower triangular factor
8584
*
8685
* @return L
8786
*/
8887

8988
public ComplexMatrixDense getL() {
90-
final int rows = _rows;
91-
final int cols = _cols;
9289
Complex[] L = new Complex[rows * cols];
9390
for (int i = 0; i < rows; ++i) {
9491
for (int j = 0; j < cols; ++j) {
@@ -111,8 +108,6 @@ public ComplexMatrixDense getL() {
111108
*/
112109

113110
public ComplexMatrixDense getU() {
114-
final int rows = _rows;
115-
final int cols = _cols;
116111
Complex[] U = new Complex[rows * cols];
117112
for (int i = 0; i < cols; i++) {
118113
for (int j = 0; j < cols; j++) {
@@ -126,6 +121,11 @@ public ComplexMatrixDense getU() {
126121
return new ComplexMatrixDense(U, rows, cols);
127122
}
128123

124+
@Override
125+
public ComplexMatrix solve(double[] b) {
126+
return solve(ComplexMatrixDense.fromRealMatrix(new MatrixDense(b, b.length)));
127+
}
128+
129129
/**
130130
* Return pivot permutation vector
131131
*
@@ -143,7 +143,6 @@ public int[] getPivot() {
143143
*/
144144

145145
public double[] getPivotAsDouble() {
146-
final int rows = _rows;
147146
double[] vals = new double[rows];
148147
for (int i = 0; i < rows; i++) {
149148
vals[i] = (double) _pivot[i];
@@ -152,12 +151,12 @@ public double[] getPivotAsDouble() {
152151
}
153152

154153
public Complex det() {
155-
if (_rows != _cols) {
154+
if (rows != cols) {
156155
throw new IllegalArgumentException("Matrix must be square.");
157156
}
158157
Complex det = Complex.fromReal(_pivotsign);
159-
for (int i = 0; i < _cols; i++) {
160-
det.multiplyEquals(this._data[i * _cols + i]);
158+
for (int i = 0; i < cols; i++) {
159+
det.multiplyEquals(this._data[i * cols + i]);
161160
}
162161
return det;
163162
}
@@ -190,10 +189,10 @@ public ComplexMatrixDense solve(MatrixDense B) {
190189
* Matrix is singular.
191190
*/
192191
public ComplexMatrixDense solve(ComplexMatrixDense B) {
193-
if (B.getRowCount() != _rows) {
192+
if (B.getRowCount() != rows) {
194193
throw new IllegalArgumentException("Matrix row dimensions must agree.");
195194
}
196-
if (!this.isNonSingular()) {
195+
if (this.isSingular()) {
197196
throw new RuntimeException("Matrix is singular.");
198197
}
199198

@@ -202,8 +201,6 @@ public ComplexMatrixDense solve(ComplexMatrixDense B) {
202201
ComplexMatrixDense Xmat = B.subMatrix(_pivot, 0, nx - 1);
203202
Complex[] X = Xmat.getArray();
204203

205-
final int cols = _cols;
206-
207204
// Solve L * Y = B(_pivot,:)
208205
for (int k = 0; k < cols; ++k) {
209206
for (int i = k + 1; i < cols; ++i) {
@@ -229,8 +226,8 @@ public ComplexMatrixDense solve(ComplexMatrixDense B) {
229226
@Override
230227
public String toString() {
231228
StringBuilder sb = new StringBuilder();
232-
for (int i = 0; i < _rows * _cols; ++i) {
233-
if (i > 0 && i % _cols == 0) {
229+
for (int i = 0; i < rows * cols; ++i) {
230+
if (i > 0 && i % cols == 0) {
234231
sb.append(System.lineSeparator());
235232
}
236233
sb.append(String.format("%.4f", _data[i])).append(" ");

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/ComplexMatrix.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public boolean isSquare() {
113113
* @return The {@link CholeskyDecompositionDense} of the {@code Matrix}.
114114
* @see <a href="https://en.wikipedia.org/wiki/Cholesky_decomposition">Cholesky Decomposition</a>
115115
*/
116-
//public abstract ComplexCholeskyDecomposition<?> Chol();
116+
public abstract ComplexCholeskyDecomposition<?> Chol();
117117
// endregion
118118

119119
/***

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/ComplexMatrixDense.java

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,41 @@ public double det() {
112112
}
113113

114114
@Override
115-
public ComplexLUDecomposition<?> LU() {
116-
return null;
115+
public ComplexLUDecompositionDense LU() {
116+
return new ComplexLUDecompositionDense(this);
117117
}
118118

119119
@Override
120-
public ComplexQRDecomposition<?> QR() {
121-
return null;
120+
public ComplexQRDecompositionDense QR() {
121+
return new ComplexQRDecompositionDense(this);
122+
}
123+
124+
@Override
125+
public ComplexCholeskyDecompositionDense Chol() {
126+
return new ComplexCholeskyDecompositionDense(this);
127+
}
128+
129+
public ComplexSingularValueDecompositionDense SVD() {
130+
return new ComplexSingularValueDecompositionDense(this);
131+
}
132+
133+
/**
134+
* Eigenvalue decomposition. The {@link Matrix} is balanced ({@link MatrixDense#balance()}) prior to the decomposition.
135+
*
136+
* @return The {@link EigenvalueDecompositionDense} of the {@code Matrix}.
137+
*/
138+
public ComplexEigenvalueDecompositionDense eig() {
139+
return new ComplexEigenvalueDecompositionDense(this);
140+
}
141+
142+
/**
143+
* Schur Decomposition of the {@code Matrix}.
144+
*
145+
* @return The {@link SchurDecompositionDense} of the {@code Matrix}.
146+
* @see <a href="https://en.wikipedia.org/wiki/Schur_decomposition">Schur Decomposition</a>
147+
*/
148+
public ComplexSchurDecompositionDense Schur() {
149+
return new ComplexSchurDecompositionDense(this);
122150
}
123151

124152
public Complex[] getArray() {
@@ -285,7 +313,7 @@ public ComplexMatrixDense transpose() {
285313
}
286314

287315
public ComplexMatrixDense inv() {
288-
return this.solve(MatrixDense.Factory.identity(rows));
316+
return this.solve(ComplexMatrixDense.Factory.identity(rows));
289317
}
290318

291319
// region solve
@@ -509,10 +537,6 @@ public ComplexMatrixDense balance() {
509537
return new ComplexMatrixDense(data, rows, cols);
510538
}
511539

512-
public ComplexSingularValueDecompositionDense SVD() {
513-
return new ComplexSingularValueDecompositionDense(this);
514-
}
515-
516540
public ComplexMatrixDense pinv() {
517541
int rows = this.rows;
518542
int cols = this.cols;

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/MatrixDense.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,16 @@ public CholeskyDecompositionDense Chol() {
530530
public SingularValueDecompositionDense SVD() {
531531
return new SingularValueDecompositionDense(this);
532532
}
533+
534+
/**
535+
* Schur Decomposition of the {@code Matrix}.
536+
*
537+
* @return The {@link SchurDecompositionDense} of the {@code Matrix}.
538+
* @see <a href="https://en.wikipedia.org/wiki/Schur_decomposition">Schur Decomposition</a>
539+
*/
540+
public SchurDecompositionDense Schur() {
541+
return new SchurDecompositionDense(this);
542+
}
533543
// endregion
534544

535545
/***

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/MatrixSparse.java

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ public MatrixSparse(int rows, int cols, int arrayLength) {
6363

6464
public MatrixSparse(MatrixSparse original) {
6565
this(original.rows, original.cols, original.nz_length);
66-
66+
nz_values = original.nz_values;
67+
nz_rows = original.nz_rows;
6768
setTo(original);
6869
}
6970

@@ -76,14 +77,13 @@ public MatrixSparse createLike() {
7677
}
7778

7879
public void setTo(MatrixSparse original) {
79-
MatrixSparse o = original;
80-
reshape(o.rows, o.cols, o.nz_length);
81-
this.nz_length = o.nz_length;
80+
reshape(original.rows, original.cols, original.nz_length);
81+
this.nz_length = original.nz_length;
8282

83-
System.arraycopy(o.nz_values, 0, nz_values, 0, nz_length);
84-
System.arraycopy(o.nz_rows, 0, nz_rows, 0, nz_length);
85-
System.arraycopy(o.col_idx, 0, col_idx, 0, cols + 1);
86-
this.indicesSorted = o.indicesSorted;
83+
System.arraycopy(original.nz_values, 0, nz_values, 0, nz_length);
84+
System.arraycopy(original.nz_rows, 0, nz_rows, 0, nz_length);
85+
System.arraycopy(original.col_idx, 0, col_idx, 0, cols + 1);
86+
this.indicesSorted = original.indicesSorted;
8787
}
8888

8989
// public void print() {
@@ -182,6 +182,46 @@ public void set(int row, int col, double val) {
182182
unsafeSet(row, col, val);
183183
}
184184

185+
/**
186+
* Solve system of linear equations. Three different algorithms are used depending on the shape of the matrix:
187+
* <pre>
188+
* LU Decomposition if the matrix is squared.
189+
* QR if the matrix is thin in other words it has more rows than columns. (Overdetermined system)
190+
* Pseudo inverse * b if the matrix is short and wide in other words it has more columns than rows. (Under-determined system)
191+
* </pre>
192+
*
193+
* @param b The solution {@link Matrix}.
194+
* @return The solution to {@code Ax = b}
195+
*/
196+
public MatrixSparse solve(MatrixSparse b) {
197+
if (rows == cols) { // Matrix is Squared
198+
return new LUDecompositionSparse(this).solve(b);
199+
} else if (rows > cols) { // Matrix is tall and narrow (Overdetermined system)
200+
return new QRDecompositionSparse(this).solve(b);
201+
} else { // Matrix is short and wide (Under-determined system)
202+
throw new UnsupportedOperationException("This operation is not supported for system with more columns than rows");
203+
}
204+
}
205+
206+
/**
207+
* Solve system of linear equations. Three different algorithms are used depending on the shape of the matrix:
208+
* <pre>
209+
* LU Decomposition if the matrix is squared.
210+
* QR if the matrix is thin in other words it has more rows than columns. (Overdetermined system)
211+
* Pseudo inverse * b if the matrix is short and wide in other words it has more columns than rows. (Under-determined system)
212+
* </pre>
213+
*
214+
* @param b The solution {@link Matrix}.
215+
* @return The solution to {@code Ax = b}
216+
*/
217+
public MatrixSparse solve(double[] b) {
218+
double[][] matrix = new double[b.length][1];
219+
for(int i = 0; i < b.length; i++) {
220+
matrix[i][0] = b[i];
221+
}
222+
return solve(from2DArray(matrix));
223+
}
224+
185225
@Override
186226
public double det() {
187227
throw new UnsupportedOperationException("Not implemented yet");
@@ -198,9 +238,7 @@ public QRDecompositionSparse QR() {
198238
}
199239

200240
@Override
201-
public CholeskyDecompositionSparse Chol() {
202-
throw new UnsupportedOperationException("Not implemented yet");
203-
}
241+
public CholeskyDecompositionSparse Chol() { return new CholeskyDecompositionSparse(this); }
204242

205243
@Override
206244
public boolean isEmpty() {

src/test/java/com/wildbitsfoundry/etk4j/math/linearalgebra/MatrixSparseTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,20 @@ public void testLUDecomposition() {
127127
solution.get(1, 0), solution.get(2, 0)}, 1e-12);
128128
}
129129

130+
@Test
131+
public void testSolveArrayRHS() {
132+
double[][] matrix = {
133+
{1, 4, 7},
134+
{2, 5, 8},
135+
{3, 6, 10},
136+
};
137+
MatrixSparse sparseCSC = MatrixSparse.from2DArray(matrix, ConstantsETK.DOUBLE_EPS);
138+
double[] b = {1, 2, 0};
139+
MatrixSparse solution = sparseCSC.solve(b);
140+
assertArrayEquals(new double[]{-2, 6.000000000000005, -3.0000000000000027}, new double[]{solution.get(0, 0),
141+
solution.get(1, 0), solution.get(2, 0)}, 1e-12);
142+
}
143+
130144
@Test
131145
public void testLUDecompositionSparseMatrixRHS() {
132146
double[][] matrix = {

0 commit comments

Comments
 (0)