1 package org.djunits.vecmat.dn;
2
3 import java.util.Objects;
4
5 import org.djunits.quantity.SIQuantity;
6 import org.djunits.quantity.def.Quantity;
7 import org.djunits.unit.Unit;
8 import org.djunits.unit.si.SIUnit;
9 import org.djunits.util.ArrayMath;
10 import org.djunits.util.MatrixMath;
11 import org.djunits.vecmat.NonInvertibleMatrixException;
12 import org.djunits.vecmat.d1.Matrix1x1;
13 import org.djunits.vecmat.d2.Matrix2x2;
14 import org.djunits.vecmat.d3.Matrix3x3;
15 import org.djunits.vecmat.def.SquareMatrix;
16 import org.djunits.vecmat.storage.DataGridSi;
17 import org.djunits.vecmat.storage.DenseDoubleDataSi;
18 import org.djutils.exceptions.Throw;
19
20
21
22
23
24
25
26
27
28
29
30 public class MatrixNxN<Q extends Quantity<Q>> extends SquareMatrix<Q, MatrixNxN<Q>, MatrixNxN<SIQuantity>, MatrixNxN<?>>
31 {
32
33 private static final long serialVersionUID = 600L;
34
35
36 private final DataGridSi<?> dataGridSi;
37
38
39
40
41
42
43
44 public MatrixNxN(final DataGridSi<?> dataGridSi, final Unit<?, Q> displayUnit)
45 {
46 super(displayUnit);
47 Throw.whenNull(dataGridSi, "dataGridSi");
48 Throw.when(dataGridSi.rows() != dataGridSi.cols(), IllegalArgumentException.class,
49 "Data for the NxN matrix is not square");
50 this.dataGridSi = dataGridSi;
51 }
52
53 @Override
54 public MatrixNxN<Q> instantiateSi(final double[] siNew)
55 {
56 return new MatrixNxN<Q>(this.dataGridSi.instantiateNew(siNew), getDisplayUnit().getBaseUnit())
57 .setDisplayUnit(getDisplayUnit());
58 }
59
60 @Override
61 public double[] unsafeSiArray()
62 {
63 return this.dataGridSi.unsafeSiArray();
64 }
65
66 @Override
67 public double[] getSiArray()
68 {
69 return this.dataGridSi.getSiArray();
70 }
71
72 @Override
73 public double si(final int row, final int col)
74 {
75 return this.dataGridSi.get(row, col);
76 }
77
78 @Override
79 public int rows()
80 {
81 return this.dataGridSi.rows();
82 }
83
84 @Override
85 public int cols()
86 {
87 return this.dataGridSi.cols();
88 }
89
90 @Override
91 public int nonZeroCount()
92 {
93 return this.dataGridSi.nonZeroCount();
94 }
95
96
97
98
99
100 public DataGridSi<?> getDataGrid()
101 {
102 return this.dataGridSi;
103 }
104
105 @Override
106 public MatrixNxN<SIQuantity> instantiateSi(final double[] siNew, final SIUnit siUnit)
107 {
108 return new MatrixNxN<SIQuantity>(this.dataGridSi.instantiateNew(siNew), siUnit);
109 }
110
111 @Override
112 public VectorN.Row<Q> getRowVector(final int row)
113 {
114 checkRow(row);
115 return VectorN.Row.ofSi(this.dataGridSi.getRowArray(row), getDisplayUnit());
116 }
117
118 @Override
119 public VectorN.Row<Q> mgetRowVector(final int mRow)
120 {
121 mcheckRow(mRow);
122 return VectorN.Row.ofSi(this.dataGridSi.getRowArray(mRow - 1), getDisplayUnit());
123 }
124
125 @Override
126 public VectorN.Col<Q> getColumnVector(final int col)
127 {
128 checkCol(col);
129 return VectorN.Col.ofSi(this.dataGridSi.getColArray(col), getDisplayUnit());
130 }
131
132 @Override
133 public VectorN.Col<Q> mgetColumnVector(final int mCol)
134 {
135 mcheckCol(mCol);
136 return VectorN.Col.ofSi(this.dataGridSi.getColArray(mCol - 1), getDisplayUnit());
137 }
138
139 @Override
140 public VectorN.Col<Q> getDiagonalVector() throws IllegalStateException
141 {
142 final int n = rows();
143 final double[] data = new double[n];
144 for (int i = 0; i < n; i++)
145 {
146 data[i] = si(i, i);
147 }
148
149 return VectorN.Col.ofSi(data, getDisplayUnit());
150 }
151
152 @Override
153 public double[] getRowSi(final int row)
154 {
155 checkRow(row);
156 return this.dataGridSi.getRowArray(row);
157 }
158
159 @Override
160 public double[] getColumnSi(final int col)
161 {
162 checkCol(col);
163 return this.dataGridSi.getColArray(col);
164 }
165
166 @Override
167 public MatrixNxN<SIQuantity> inverse() throws NonInvertibleMatrixException
168 {
169 double[] invData = MatrixMath.inverse(unsafeSiArray(), order());
170 return new MatrixNxN<SIQuantity>(this.dataGridSi.instantiateNew(invData), getDisplayUnit().siUnit().invert());
171 }
172
173 @Override
174 public MatrixNxN<SIQuantity> adjugate()
175 {
176 double[] invData = MatrixMath.adjugate(unsafeSiArray(), order());
177 return new MatrixNxN<SIQuantity>(this.dataGridSi.instantiateNew(invData), getDisplayUnit().siUnit().pow(order() - 1));
178 }
179
180 @Override
181 public MatrixNxN<SIQuantity> invertEntries()
182 {
183 SIUnit siUnit = getDisplayUnit().siUnit().invert();
184 return new MatrixNxN<SIQuantity>(this.dataGridSi.instantiateNew(ArrayMath.reciprocal(unsafeSiArray())), siUnit);
185 }
186
187 @Override
188 public MatrixNxN<SIQuantity> multiplyEntries(final MatrixNxN<?> other)
189 {
190 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
191 return new MatrixNxN<SIQuantity>(
192 this.dataGridSi.instantiateNew(ArrayMath.multiply(unsafeSiArray(), other.unsafeSiArray())), siUnit);
193 }
194
195 @Override
196 public MatrixNxN<SIQuantity> divideEntries(final MatrixNxN<?> other)
197 {
198 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
199 return new MatrixNxN<SIQuantity>(
200 this.dataGridSi.instantiateNew(ArrayMath.divide(unsafeSiArray(), other.unsafeSiArray())), siUnit);
201 }
202
203 @Override
204 public MatrixNxN<SIQuantity> multiplyEntries(final Quantity<?> quantity)
205 {
206 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
207 return new MatrixNxN<SIQuantity>(this.dataGridSi.instantiateNew(ArrayMath.scaleBy(unsafeSiArray(), quantity.si())),
208 siUnit);
209 }
210
211 @Override
212 public int hashCode()
213 {
214 return Objects.hash(this.dataGridSi);
215 }
216
217 @SuppressWarnings("checkstyle:needbraces")
218 @Override
219 public boolean equals(final Object obj)
220 {
221 if (this == obj)
222 return true;
223 if (obj == null)
224 return false;
225 if (getClass() != obj.getClass())
226 return false;
227 MatrixNxN<?> other = (MatrixNxN<?>) obj;
228 return Objects.equals(this.dataGridSi, other.dataGridSi);
229 }
230
231
232
233
234
235
236
237
238
239
240
241 public MatrixNxN<SIQuantity> multiply(final MatrixNxN<?> otherMat)
242 {
243 checkMultiply(otherMat);
244 final int n = order();
245 final double[] resultData = MatrixMath.multiply(unsafeSiArray(), otherMat.unsafeSiArray(), n, n, n);
246 final SIUnit resultUnit = getDisplayUnit().siUnit().plus(otherMat.getDisplayUnit().siUnit());
247 return new MatrixNxN<SIQuantity>(this.dataGridSi.instantiateNew(resultData), resultUnit);
248 }
249
250
251
252
253
254
255
256
257
258
259 public VectorN.Col<SIQuantity> multiply(final VectorN.Col<?> otherVec)
260 {
261 checkMultiply(otherVec);
262 final int n = order();
263 final double[] resultData = MatrixMath.multiply(unsafeSiArray(), otherVec.unsafeSiArray(), n, n, 1);
264 final SIUnit resultUnit = getDisplayUnit().siUnit().plus(otherVec.getDisplayUnit().siUnit());
265 return VectorN.Col.ofSi(resultData, resultUnit);
266 }
267
268
269
270
271
272
273
274
275
276 protected static int checkSquare(final int length)
277 {
278 int n = (int) Math.sqrt(length);
279 Throw.when(length != n * n, IllegalArgumentException.class,
280 "dataInUnit does not contain a square number of entries (%d)", length);
281 return n;
282 }
283
284
285
286
287
288
289
290
291
292 public static <Q extends Quantity<Q>> MatrixNxN<Q> of(final double[] dataInUnit, final Unit<?, Q> unit)
293 {
294 Throw.whenNull(dataInUnit, "dataInUnit");
295 int n = checkSquare(dataInUnit.length);
296 return new MatrixNxN<Q>(DenseDoubleDataSi.of(dataInUnit, n, n, unit), unit);
297 }
298
299
300
301
302
303
304
305
306
307 public static <Q extends Quantity<Q>> MatrixNxN<Q> ofSi(final double[] dataSi, final Unit<?, Q> displayUnit)
308 {
309 Throw.whenNull(dataSi, "dataSi");
310 int n = checkSquare(dataSi.length);
311 return new MatrixNxN<Q>(DenseDoubleDataSi.ofSi(dataSi, n, n), displayUnit);
312 }
313
314
315
316
317
318
319
320
321
322 public static <Q extends Quantity<Q>> MatrixNxN<Q> of(final Q[] data)
323 {
324 Throw.whenNull(data, "data");
325 Throw.when(data.length == 0, IllegalArgumentException.class, "data.length = 0");
326 int n = checkSquare(data.length);
327 return new MatrixNxN<Q>(DenseDoubleDataSi.of(data, n, n), data[0].getDisplayUnit());
328 }
329
330
331
332
333
334
335
336
337
338 @SuppressWarnings("checkstyle:needbraces")
339 public static <Q extends Quantity<Q>> MatrixNxN<Q> ofSi(final double[][] gridSi, final Unit<?, Q> displayUnit)
340 {
341 return new MatrixNxN<>(DenseDoubleDataSi.ofSi(gridSi), displayUnit);
342 }
343
344
345
346
347
348
349
350
351
352 @SuppressWarnings("checkstyle:needbraces")
353 public static <Q extends Quantity<Q>> MatrixNxN<Q> of(final double[][] gridInUnit, final Unit<?, Q> unit)
354 {
355 return new MatrixNxN<>(DenseDoubleDataSi.of(gridInUnit, unit), unit);
356 }
357
358
359
360
361
362
363
364
365
366
367 public static <Q extends Quantity<Q>> MatrixNxN<Q> of(final Q[][] grid)
368 {
369 Throw.whenNull(grid, "grid");
370 Throw.when(grid.length == 0, IllegalArgumentException.class, "grid.length = 0");
371 Throw.whenNull(grid[0], "grid[0] = null");
372 Throw.when(grid[0].length == 0, IllegalArgumentException.class, "grid[0].length = 0");
373 Throw.whenNull(grid[0][0], "grid[0][0] = null");
374 return new MatrixNxN<>(DenseDoubleDataSi.of(grid), grid[0][0].getDisplayUnit());
375 }
376
377
378
379
380
381
382
383
384
385
386
387
388
389 public <TQ extends Quantity<TQ>> MatrixNxN<TQ> as(final Unit<?, TQ> targetUnit)
390 {
391 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
392 "MatrixNxN.as(%s) called, but units do not match: %s <> %s", targetUnit,
393 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
394 return new MatrixNxN<TQ>(this.dataGridSi.instantiateNew(unsafeSiArray()), targetUnit);
395 }
396
397
398
399
400
401
402 public Matrix1x1<Q> asMatrix1x1()
403 {
404 Throw.when(order() != 1, IllegalStateException.class, "asMatrix1x1() called, but matrix is no 1x1 but %dx%d", rows(),
405 cols());
406 return Matrix1x1.ofSi(unsafeSiArray(), getDisplayUnit());
407 }
408
409
410
411
412
413
414 public Matrix2x2<Q> asMatrix2x2()
415 {
416 Throw.when(order() != 2, IllegalStateException.class, "asMatrix2x2() called, but matrix is no 2x2 but %dx%d", rows(),
417 cols());
418 return Matrix2x2.ofSi(unsafeSiArray(), getDisplayUnit());
419 }
420
421
422
423
424
425
426 public Matrix3x3<Q> asMatrix3x3()
427 {
428 Throw.when(order() != 3, IllegalStateException.class, "asMatrix3x3() called, but matrix is no 3x3 but %dx%d", rows(),
429 cols());
430 return Matrix3x3.ofSi(unsafeSiArray(), getDisplayUnit());
431 }
432
433 }