1 package org.djunits.vecmat.dnxm;
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.UnitInterface;
8 import org.djunits.unit.si.SIUnit;
9 import org.djunits.util.MatrixMath;
10 import org.djunits.vecmat.d1.Matrix1x1;
11 import org.djunits.vecmat.d1.Vector1;
12 import org.djunits.vecmat.d2.Matrix2x2;
13 import org.djunits.vecmat.d2.Vector2;
14 import org.djunits.vecmat.d3.Matrix3x3;
15 import org.djunits.vecmat.d3.Vector3;
16 import org.djunits.vecmat.def.Matrix;
17 import org.djunits.vecmat.dn.MatrixNxN;
18 import org.djunits.vecmat.dn.VectorN;
19 import org.djunits.vecmat.storage.DataGridSi;
20 import org.djunits.vecmat.storage.DenseDoubleDataSi;
21 import org.djunits.vecmat.storage.DenseFloatDataSi;
22 import org.djutils.exceptions.Throw;
23
24
25
26
27
28
29
30
31
32
33
34
35 public class MatrixNxM<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>>
36 extends Matrix<Q, U, MatrixNxM<Q, U>, MatrixNxM<SIQuantity, SIUnit>, MatrixNxM<?, ?>>
37 {
38
39 private static final long serialVersionUID = 600L;
40
41
42 private final DataGridSi<?> dataSi;
43
44
45
46
47
48
49
50 public MatrixNxM(final DataGridSi<?> dataSi, final U displayUnit)
51 {
52 super(displayUnit);
53 Throw.whenNull(dataSi, "dataSi");
54 this.dataSi = dataSi;
55 }
56
57
58
59
60
61
62
63
64
65
66
67
68
69 @SuppressWarnings("checkstyle:needbraces")
70 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> MatrixNxM<Q, U> of(final double[] valueArrayInUnit,
71 final int rows, final int cols, final U displayUnit)
72 {
73 Throw.whenNull(valueArrayInUnit, "valueArrayInUnit");
74 Throw.whenNull(displayUnit, "displayUnit");
75 Throw.when(rows <= 0, IllegalArgumentException.class, "rows <= 0");
76 Throw.when(cols <= 0, IllegalArgumentException.class, "cols <= 0");
77 Throw.when(rows * cols != valueArrayInUnit.length, IllegalArgumentException.class,
78 "valueArrayInUnit does not contain the correct number of entries (%d x %d != %d)", rows, cols,
79 valueArrayInUnit.length);
80 double[] aSi = new double[rows * cols];
81 for (int i = 0; i < valueArrayInUnit.length; i++)
82 aSi[i] = displayUnit.toBaseValue(valueArrayInUnit[i]);
83 return new MatrixNxM<Q, U>(new DenseDoubleDataSi(aSi, rows, cols), displayUnit);
84 }
85
86
87
88
89
90
91
92
93
94
95
96 @SuppressWarnings("checkstyle:needbraces")
97 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> MatrixNxM<Q, U> of(final double[][] valueGridInUnit,
98 final U displayUnit)
99 {
100 Throw.whenNull(valueGridInUnit, "valueGridInUnit");
101 Throw.whenNull(displayUnit, "displayUnit");
102 int rows = valueGridInUnit.length;
103 Throw.when(rows == 0, IllegalArgumentException.class, "valueGridInUnit has 0 rows");
104 int cols = valueGridInUnit[0].length;
105 Throw.when(cols == 0, IllegalArgumentException.class, "row 0 in valueGridInUnit has 0 columns");
106 double[] aSi = new double[rows * cols];
107 for (int r = 0; r < rows; r++)
108 {
109 Throw.when(valueGridInUnit[r].length != cols, IllegalArgumentException.class,
110 "valueGridInUnit is not a NxM array; row %d has a length of %d, not %d", r, valueGridInUnit[r].length,
111 cols);
112 for (int c = 0; c < cols; c++)
113 aSi[cols * r + c] = displayUnit.toBaseValue(valueGridInUnit[r][c]);
114 }
115 return new MatrixNxM<Q, U>(new DenseDoubleDataSi(aSi, rows, cols), displayUnit);
116 }
117
118
119
120
121
122
123
124
125
126
127
128 @SuppressWarnings("checkstyle:needbraces")
129 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> MatrixNxM<Q, U> of(final Q[][] quantityGrid,
130 final U displayUnit)
131 {
132 return new MatrixNxM<Q, U>(new DenseDoubleDataSi(quantityGrid), displayUnit);
133 }
134
135 @Override
136 public MatrixNxM<Q, U> instantiateSi(final double[] siNew)
137 {
138 return new MatrixNxM<Q, U>(this.dataSi.instantiateNew(siNew), getDisplayUnit().getBaseUnit())
139 .setDisplayUnit(getDisplayUnit());
140 }
141
142 @Override
143 public MatrixNxM<SIQuantity, SIUnit> instantiateSi(final double[] siNew, final SIUnit siUnit)
144 {
145 return new MatrixNxM<SIQuantity, SIUnit>(this.dataSi.instantiateNew(siNew), siUnit);
146 }
147
148
149
150
151
152 public DataGridSi<?> getDataGrid()
153 {
154 return this.dataSi;
155 }
156
157 @Override
158 public double[] si()
159 {
160 return this.dataSi.getDataArray();
161 }
162
163 @Override
164 public double si(final int row, final int col) throws IndexOutOfBoundsException
165 {
166 checkRow(row);
167 checkCol(col);
168 return this.dataSi.get(row, col);
169 }
170
171 @Override
172 public VectorN.Row<Q, U> getRowVector(final int row)
173 {
174 return VectorN.Row.ofSi(getRowSi(row), getDisplayUnit());
175 }
176
177 @Override
178 public VectorN.Row<Q, U> mgetRowVector(final int mRow)
179 {
180 return VectorN.Row.ofSi(mgetRowSi(mRow), getDisplayUnit());
181 }
182
183 @Override
184 public VectorN.Col<Q, U> getColumnVector(final int col)
185 {
186 return VectorN.Col.ofSi(getColumnSi(col), getDisplayUnit());
187 }
188
189 @Override
190 public VectorN.Col<Q, U> mgetColumnVector(final int mCol)
191 {
192 return VectorN.Col.ofSi(mgetColumnSi(mCol), getDisplayUnit());
193 }
194
195 @Override
196 public double[] getRowSi(final int row)
197 {
198 checkRow(row);
199 return this.dataSi.getRowArray(row);
200 }
201
202 @Override
203 public double[] getColumnSi(final int col)
204 {
205 checkCol(col);
206 return this.dataSi.getColArray(col);
207 }
208
209 @Override
210 public int rows()
211 {
212 return this.dataSi.rows();
213 }
214
215 @Override
216 public int cols()
217 {
218 return this.dataSi.cols();
219 }
220
221 @Override
222 public int hashCode()
223 {
224 return Objects.hash(this.dataSi);
225 }
226
227 @SuppressWarnings("checkstyle:needbraces")
228 @Override
229 public boolean equals(final Object obj)
230 {
231 if (this == obj)
232 return true;
233 if (obj == null)
234 return false;
235 if (getClass() != obj.getClass())
236 return false;
237 MatrixNxM<?, ?> other = (MatrixNxM<?, ?>) obj;
238 return Objects.equals(this.dataSi, other.dataSi);
239 }
240
241
242
243
244
245
246
247
248
249
250
251 public MatrixNxM<SIQuantity, SIUnit> multiply(final Matrix1x1<?, ?> matrix)
252 {
253 checkMultiply(matrix);
254 double[] result = MatrixMath.multiply(si(), matrix.si(), rows(), cols(), matrix.cols());
255 SIUnit siUnit = getDisplayUnit().siUnit().plus(matrix.getDisplayUnit().siUnit());
256 return new MatrixNxM<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), matrix.cols()), siUnit);
257 }
258
259
260
261
262
263
264
265
266
267 public MatrixNxM<SIQuantity, SIUnit> multiply(final Matrix2x2<?, ?> matrix)
268 {
269 checkMultiply(matrix);
270 double[] result = MatrixMath.multiply(si(), matrix.si(), rows(), cols(), matrix.cols());
271 SIUnit siUnit = getDisplayUnit().siUnit().plus(matrix.getDisplayUnit().siUnit());
272 return new MatrixNxM<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), matrix.cols()), siUnit);
273 }
274
275
276
277
278
279
280
281
282
283 public MatrixNxM<SIQuantity, SIUnit> multiply(final Matrix3x3<?, ?> matrix)
284 {
285 checkMultiply(matrix);
286 double[] result = MatrixMath.multiply(si(), matrix.si(), rows(), cols(), matrix.cols());
287 SIUnit siUnit = getDisplayUnit().siUnit().plus(matrix.getDisplayUnit().siUnit());
288 return new MatrixNxM<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), matrix.cols()), siUnit);
289 }
290
291
292
293
294
295
296
297
298
299 public MatrixNxM<SIQuantity, SIUnit> multiply(final MatrixNxN<?, ?> matrix)
300 {
301 checkMultiply(matrix);
302 double[] result = MatrixMath.multiply(si(), matrix.si(), rows(), cols(), matrix.cols());
303 SIUnit siUnit = getDisplayUnit().siUnit().plus(matrix.getDisplayUnit().siUnit());
304 if (matrix.getDataGrid().isDouble())
305 {
306 return new MatrixNxM<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), matrix.cols()), siUnit);
307 }
308 return new MatrixNxM<SIQuantity, SIUnit>(new DenseFloatDataSi(result, rows(), matrix.cols()), siUnit);
309 }
310
311
312
313
314
315
316
317
318
319 public MatrixNxM<SIQuantity, SIUnit> multiply(final Vector1<?, ?> vector)
320 {
321 checkMultiply(vector);
322 double[] result = MatrixMath.multiply(si(), vector.si(), rows(), cols(), vector.cols());
323 SIUnit siUnit = getDisplayUnit().siUnit().plus(vector.getDisplayUnit().siUnit());
324 return new MatrixNxM<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), vector.cols()), siUnit);
325 }
326
327
328
329
330
331
332
333
334
335 public VectorN.Col<SIQuantity, SIUnit> multiply(final Vector2.Col<?, ?> vector)
336 {
337 checkMultiply(vector);
338 double[] result = MatrixMath.multiply(si(), vector.si(), rows(), cols(), vector.cols());
339 SIUnit siUnit = getDisplayUnit().siUnit().plus(vector.getDisplayUnit().siUnit());
340 return new VectorN.Col<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), vector.cols()), siUnit);
341 }
342
343
344
345
346
347
348
349
350
351 public VectorN.Col<SIQuantity, SIUnit> multiply(final Vector3.Col<?, ?> vector)
352 {
353 checkMultiply(vector);
354 double[] result = MatrixMath.multiply(si(), vector.si(), rows(), cols(), vector.cols());
355 SIUnit siUnit = getDisplayUnit().siUnit().plus(vector.getDisplayUnit().siUnit());
356 return new VectorN.Col<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), vector.cols()), siUnit);
357 }
358
359
360
361
362
363
364
365
366
367 public VectorN.Col<SIQuantity, SIUnit> multiply(final VectorN.Col<?, ?> vector)
368 {
369 checkMultiply(vector);
370 double[] result = MatrixMath.multiply(si(), vector.si(), rows(), cols(), vector.cols());
371 SIUnit siUnit = getDisplayUnit().siUnit().plus(vector.getDisplayUnit().siUnit());
372 return new VectorN.Col<SIQuantity, SIUnit>(new DenseDoubleDataSi(result, rows(), vector.cols()), siUnit);
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386 public <TQ extends Quantity<TQ, TU>, TU extends UnitInterface<TU, TQ>> MatrixNxM<TQ, TU> as(final TU targetUnit)
387 throws IllegalArgumentException
388 {
389 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
390 "MatrixNxM.as(%s) called, but units do not match: %s <> %s", targetUnit,
391 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
392 return new MatrixNxM<TQ, TU>(this.dataSi.instantiateNew(si()), targetUnit.getBaseUnit()).setDisplayUnit(targetUnit);
393 }
394
395
396
397
398
399
400 public Matrix1x1<Q, U> asMatrix1x1()
401 {
402 Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class,
403 "asMatrix1x1() called, but matrix is no 1x1 but %dx%d", rows(), cols());
404 return Matrix1x1.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
405 }
406
407
408
409
410
411
412 public Matrix2x2<Q, U> asMatrix2x2()
413 {
414 Throw.when(rows() != 2 || cols() != 2, IllegalStateException.class,
415 "asMatrix2x2() called, but matrix is no 2x2 but %dx%d", rows(), cols());
416 return Matrix2x2.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
417 }
418
419
420
421
422
423
424 public Matrix3x3<Q, U> asMatrix3x3()
425 {
426 Throw.when(rows() != 3 || cols() != 3, IllegalStateException.class,
427 "asMatrix3x3() called, but matrix is no 3x3 but %dx%d", rows(), cols());
428 return Matrix3x3.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
429 }
430
431
432
433
434
435
436 public MatrixNxN<Q, U> asMatrixNxN()
437 {
438 Throw.when(rows() != cols(), IllegalStateException.class, "asMatrixNxN() called, but matrix is no square but %dx%d",
439 rows(), cols());
440 return new MatrixNxN<Q, U>(new DenseDoubleDataSi(si(), rows(), cols()), getDisplayUnit().getBaseUnit())
441 .setDisplayUnit(getDisplayUnit());
442 }
443
444
445
446
447
448
449 public Vector1<Q, U> asVector1()
450 {
451 Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class, "Matrix is not 1x1");
452 final double[] data = si();
453 return new Vector1<Q, U>(data[0], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
454 }
455
456
457
458
459
460
461 public Vector2.Col<Q, U> asVector2Col()
462 {
463 Throw.when(rows() != 2 || cols() != 1, IllegalStateException.class, "Matrix is not 2x1");
464 final double[] data = si();
465 return new Vector2.Col<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
466 }
467
468
469
470
471
472
473 public Vector3.Col<Q, U> asVector3Col()
474 {
475 Throw.when(rows() != 3 || cols() != 1, IllegalStateException.class, "Matrix is not 3x1");
476 final double[] data = si();
477 return new Vector3.Col<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
478 .setDisplayUnit(getDisplayUnit());
479 }
480
481
482
483
484
485
486 public VectorN.Col<Q, U> asVectorNCol()
487 {
488 Throw.when(cols() != 1, IllegalStateException.class, "Matrix is not Nx1");
489 return VectorN.Col.ofSi(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
490 }
491
492
493
494
495
496
497 public Vector2.Row<Q, U> asVector2Row()
498 {
499 Throw.when(rows() != 1 || cols() != 2, IllegalStateException.class, "Matrix is not 1x2");
500 final double[] data = si();
501 return new Vector2.Row<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
502 }
503
504
505
506
507
508
509 public Vector3.Row<Q, U> asVector3Row()
510 {
511 Throw.when(rows() != 1 || cols() != 3, IllegalStateException.class, "Matrix is not 1x3");
512 final double[] data = si();
513 return new Vector3.Row<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
514 .setDisplayUnit(getDisplayUnit());
515 }
516
517
518
519
520
521
522 public VectorN.Row<Q, U> asVectorNRow()
523 {
524 Throw.when(rows() != 1, IllegalStateException.class, "Matrix is not 1xN");
525 return VectorN.Row.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
526 }
527
528 }