1 package org.djunits.value.vdouble.matrix.base;
2
3 import java.lang.reflect.Array;
4
5 import org.djunits.unit.Unit;
6 import org.djunits.value.Absolute;
7 import org.djunits.value.ValueRuntimeException;
8 import org.djunits.value.base.Matrix;
9 import org.djunits.value.formatter.Format;
10 import org.djunits.value.storage.StorageType;
11 import org.djunits.value.util.ValueUtil;
12 import org.djunits.value.vdouble.function.DoubleFunction;
13 import org.djunits.value.vdouble.function.DoubleMathFunctions;
14 import org.djunits.value.vdouble.matrix.data.DoubleMatrixData;
15 import org.djunits.value.vdouble.scalar.base.DoubleScalar;
16 import org.djunits.value.vdouble.vector.base.DoubleVector;
17 import org.djunits.value.vdouble.vector.data.DoubleVectorData;
18 import org.djutils.exceptions.Throw;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public abstract class DoubleMatrix<U extends Unit<U>, S extends DoubleScalar<U, S>, V extends DoubleVector<U, S, V>,
34 M extends DoubleMatrix<U, S, V, M>> extends Matrix<U, S, V, DoubleVectorData, M, DoubleMatrixData>
35 {
36
37 private static final long serialVersionUID = 20161015L;
38
39
40 @SuppressWarnings("checkstyle:visibilitymodifier")
41 protected DoubleMatrixData data;
42
43
44
45
46
47
48 public DoubleMatrix(final DoubleMatrixData data, final U unit)
49 {
50 super(unit);
51 Throw.whenNull(data, "data cannot be null");
52 this.data = data;
53 }
54
55
56
57
58
59
60
61
62
63 public abstract M instantiateMatrix(DoubleMatrixData dmd, U displayUnit);
64
65
66
67
68
69
70
71
72
73 public abstract V instantiateVector(DoubleVectorData dvd, U displayUnit);
74
75
76
77
78
79
80
81
82
83 public abstract S instantiateScalarSI(double valueSI, U displayUnit);
84
85 @Override
86 protected final DoubleMatrixData getData()
87 {
88 return this.data;
89 }
90
91 @Override
92 protected void setData(final DoubleMatrixData data)
93 {
94 this.data = data;
95 }
96
97
98
99
100
101
102
103
104
105 public double getSI(final int row, final int column) throws IndexOutOfBoundsException
106 {
107 checkIndex(row, column);
108 return this.data.getSI(row, column);
109 }
110
111
112
113
114
115
116
117
118
119 public double getInUnit(final int row, final int column) throws IndexOutOfBoundsException
120 {
121 checkIndex(row, column);
122 return ValueUtil.expressAsUnit(this.data.getSI(row, column), getDisplayUnit());
123 }
124
125
126
127
128
129
130
131
132
133
134 public double getInUnit(final int row, final int column, final U targetUnit) throws IndexOutOfBoundsException
135 {
136 checkIndex(row, column);
137 return ValueUtil.expressAsUnit(this.data.getSI(row, column), targetUnit);
138 }
139
140
141
142
143
144
145
146
147 public void setSI(final int row, final int column, final double valueSI) throws IndexOutOfBoundsException
148 {
149 checkIndex(row, column);
150 checkCopyOnWrite();
151 this.data.setSI(row, column, valueSI);
152 }
153
154
155
156
157
158
159
160
161 public void setInUnit(final int row, final int column, final double valueInUnit) throws IndexOutOfBoundsException
162 {
163 setSI(row, column, ValueUtil.expressAsSIUnit(valueInUnit, getDisplayUnit()));
164 }
165
166
167
168
169
170
171
172
173
174 public void setInUnit(final int row, final int column, final double valueInUnit, final U valueUnit)
175 throws IndexOutOfBoundsException
176 {
177 setSI(row, column, ValueUtil.expressAsSIUnit(valueInUnit, valueUnit));
178 }
179
180
181
182
183
184
185
186
187 public void set(final int row, final int column, final S value) throws IndexOutOfBoundsException
188 {
189 setSI(row, column, value.si);
190 }
191
192
193
194
195
196
197
198 public double[] getRowSI(final int row) throws IndexOutOfBoundsException
199 {
200 checkRowIndex(row);
201 double[] result = new double[this.data.cols()];
202 for (int col = 0; col < result.length; col++)
203 {
204 result[col] = this.data.getSI(row, col);
205 }
206 return result;
207 }
208
209
210
211
212
213
214
215 public double[] getColumnSI(final int column) throws IndexOutOfBoundsException
216 {
217 checkColumnIndex(column);
218 double[] result = new double[this.data.rows()];
219 for (int row = 0; row < result.length; row++)
220 {
221 result[row] = this.data.getSI(row, column);
222 }
223 return result;
224 }
225
226
227
228
229
230
231 public double[] getDiagonalSI() throws ValueRuntimeException
232 {
233 checkSquare();
234 double[] result = new double[this.data.rows()];
235 for (int row = 0; row < result.length; row++)
236 {
237 result[row] = this.data.getSI(row, row);
238 }
239 return result;
240 }
241
242
243
244
245
246 public final double[][] getValuesSI()
247 {
248 return this.data.getDenseMatrixSI();
249 }
250
251
252
253
254
255 public final double[][] getValuesInUnit()
256 {
257 return getValuesInUnit(getDisplayUnit());
258 }
259
260
261
262
263
264
265 public final double[][] getValuesInUnit(final U targetUnit)
266 {
267 double[][] values = getValuesSI();
268 for (int i = values.length; --i >= 0;)
269 {
270 for (int j = values[i].length; --j >= 0;)
271 {
272 values[i][j] = ValueUtil.expressAsUnit(values[i][j], targetUnit);
273 }
274 }
275 return values;
276 }
277
278 @Override
279 public int rows()
280 {
281 return this.data.rows();
282 }
283
284 @Override
285 public int cols()
286 {
287 return this.data.cols();
288 }
289
290 @SuppressWarnings("unchecked")
291 @Override
292 public S[][] getScalars()
293 {
294 S[][] array = (S[][]) Array.newInstance(getScalarClass(), rows(), cols());
295 for (int i = 0; i < rows(); i++)
296 {
297 S[] row = (S[]) Array.newInstance(getScalarClass(), cols());
298 array[i] = row;
299 for (int j = 0; j < cols(); j++)
300 {
301 row[j] = get(i, j);
302 }
303 }
304 return array;
305 }
306
307 @Override
308 public S get(final int row, final int column) throws IndexOutOfBoundsException
309 {
310 checkIndex(row, column);
311 return DoubleScalar.instantiateSI(getSI(row, column), getDisplayUnit());
312 }
313
314 @Override
315 public V getRow(final int row) throws IndexOutOfBoundsException
316 {
317 checkRowIndex(row);
318 DoubleVectorData dvd =
319 DoubleVectorData.instantiate(getRowSI(row), getDisplayUnit().getStandardUnit().getScale(), getStorageType());
320 return instantiateVector(dvd, getDisplayUnit());
321 }
322
323 @Override
324 public V getColumn(final int column) throws IndexOutOfBoundsException
325 {
326 checkColumnIndex(column);
327 DoubleVectorData dvd = DoubleVectorData.instantiate(getColumnSI(column), getDisplayUnit().getStandardUnit().getScale(),
328 getStorageType());
329 return instantiateVector(dvd, getDisplayUnit());
330 }
331
332 @Override
333 public V getDiagonal() throws ValueRuntimeException
334 {
335 checkSquare();
336 DoubleVectorData dvd =
337 DoubleVectorData.instantiate(getDiagonalSI(), getDisplayUnit().getStandardUnit().getScale(), getStorageType());
338 return instantiateVector(dvd, getDisplayUnit());
339 }
340
341 @SuppressWarnings("unchecked")
342 @Override
343 public S[] getRowScalars(final int row) throws IndexOutOfBoundsException
344 {
345 checkRowIndex(row);
346 S[] array = (S[]) Array.newInstance(getScalarClass(), cols());
347 for (int col = 0; col < cols(); col++)
348 {
349 array[col] = get(row, col);
350 }
351 return array;
352 }
353
354 @SuppressWarnings("unchecked")
355 @Override
356 public S[] getColumnScalars(final int col) throws IndexOutOfBoundsException
357 {
358 checkColumnIndex(col);
359 S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
360 for (int row = 0; row < rows(); row++)
361 {
362 array[row] = get(row, col);
363 }
364 return array;
365 }
366
367 @SuppressWarnings("unchecked")
368 @Override
369 public S[] getDiagonalScalars() throws ValueRuntimeException
370 {
371 checkSquare();
372 S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
373 for (int row = 0; row < rows(); row++)
374 {
375 array[row] = get(row, row);
376 }
377 return array;
378 }
379
380 @SuppressWarnings("unchecked")
381 @Override
382 public M toSparse()
383 {
384 M result;
385 if (getStorageType().equals(StorageType.SPARSE))
386 {
387 result = (M) this;
388 result.setDisplayUnit(getDisplayUnit());
389 }
390 else
391 {
392 result = instantiateMatrix(this.data.toSparse(), getDisplayUnit());
393 }
394 result.setDisplayUnit(getDisplayUnit());
395 return result;
396 }
397
398 @SuppressWarnings("unchecked")
399 @Override
400 public M toDense()
401 {
402 M result;
403 if (getStorageType().equals(StorageType.DENSE))
404 {
405 result = (M) this;
406 result.setDisplayUnit(getDisplayUnit());
407 }
408 else
409 {
410 result = instantiateMatrix(this.data.toDense(), getDisplayUnit());
411 }
412 return result;
413 }
414
415
416
417
418
419
420 @SuppressWarnings("unchecked")
421 public final M assign(final DoubleFunction doubleFunction)
422 {
423 checkCopyOnWrite();
424 this.data.assign(doubleFunction);
425 return (M) this;
426 }
427
428 @Override
429 public final M abs()
430 {
431 return assign(DoubleMathFunctions.ABS);
432 }
433
434 @Override
435 public final M ceil()
436 {
437 return assign(DoubleMathFunctions.CEIL);
438 }
439
440 @Override
441 public final M floor()
442 {
443 return assign(DoubleMathFunctions.FLOOR);
444 }
445
446 @Override
447 public final M neg()
448 {
449 return assign(DoubleMathFunctions.NEG);
450 }
451
452 @Override
453 public final M rint()
454 {
455 return assign(DoubleMathFunctions.RINT);
456 }
457
458 @Override
459 public String toString()
460 {
461 return toString(getDisplayUnit(), false, true);
462 }
463
464 @Override
465 public String toString(final U displayUnit)
466 {
467 return toString(displayUnit, false, true);
468 }
469
470 @Override
471 public String toString(final boolean verbose, final boolean withUnit)
472 {
473 return toString(getDisplayUnit(), verbose, withUnit);
474 }
475
476 @Override
477 public String toString(final U displayUnit, final boolean verbose, final boolean withUnit)
478 {
479 StringBuffer buf = new StringBuffer();
480 if (verbose)
481 {
482 String ab = this instanceof Absolute ? "Abs " : "Rel ";
483 String ds = this.data.isDense() ? "Dense " : this.data.isSparse() ? "Sparse " : "?????? ";
484 if (isMutable())
485 {
486 buf.append("Mutable " + ab + ds);
487 }
488 else
489 {
490 buf.append("Immutable " + ab + ds);
491 }
492 }
493 for (int row = 0; row < rows(); row++)
494 {
495 buf.append("\r\n\t");
496 for (int col = 0; col < cols(); col++)
497 {
498 try
499 {
500 double d = ValueUtil.expressAsUnit(getSI(row, col), displayUnit);
501 buf.append(" " + Format.format(d));
502 }
503 catch (IndexOutOfBoundsException ve)
504 {
505 buf.append(" " + "********************".substring(0, Format.DEFAULTSIZE));
506 }
507 }
508 }
509 buf.append("\n");
510 if (withUnit)
511 {
512 buf.append(displayUnit.getLocalizedDisplayAbbreviation());
513 }
514 return buf.toString();
515 }
516
517
518
519
520
521
522
523 protected final void checkIndex(final int row, final int col) throws IndexOutOfBoundsException
524 {
525 if (row < 0 || row >= rows() || col < 0 || col >= cols())
526 {
527 throw new IndexOutOfBoundsException("index out of range (valid range is 0.." + (rows() - 1) + ", 0.." + (cols() - 1)
528 + ", got " + row + ", " + col + ")");
529 }
530 }
531
532
533
534
535
536
537 protected final void checkRowIndex(final int row) throws IndexOutOfBoundsException
538 {
539 if (row < 0 || row >= rows())
540 {
541 throw new IndexOutOfBoundsException(
542 "row index out of range (valid range is 0.." + (rows() - 1) + ", got " + row + ")");
543 }
544 }
545
546
547
548
549
550
551 protected final void checkColumnIndex(final int col) throws IndexOutOfBoundsException
552 {
553 if (col < 0 || col >= cols())
554 {
555 throw new IndexOutOfBoundsException(
556 "column index out of range (valid range is 0.." + (cols() - 1) + ", got " + col + ")");
557 }
558 }
559
560
561
562
563
564 protected final void checkSquare() throws ValueRuntimeException
565 {
566 Throw.when(rows() != cols(), ValueRuntimeException.class, "Matrix is not square, rows=%d, cols=%d", rows(), cols());
567 }
568
569
570
571
572
573
574 public final double determinantSI() throws ValueRuntimeException
575 {
576 checkSquare();
577 return det(getValuesSI());
578 }
579
580
581
582
583
584
585 private static double det(final double[][] mat)
586 {
587 if (mat.length == 1)
588 {
589 return mat[0][0];
590 }
591
592 double det = 0.0;
593
594 for (int col = 0; col < mat.length; col++)
595 {
596 double sgn = (col % 2 == 0) ? 1 : -1;
597 double aij = mat[0][col];
598 double[][] matAij = new double[mat.length - 1][];
599 int r = 0;
600 for (int row = 1; row < mat.length; row++)
601 {
602 matAij[r] = new double[matAij.length];
603 int c = 0;
604 for (int j = 0; j < mat.length; j++)
605 {
606 if (j != col)
607 {
608 matAij[r][c++] = mat[row][j];
609 }
610 }
611 r++;
612 }
613 det += sgn * aij * det(matAij);
614 }
615 return det;
616 }
617
618 @Override
619 @SuppressWarnings("checkstyle:designforextension")
620 public int hashCode()
621 {
622 final int prime = 31;
623 int result = getDisplayUnit().getStandardUnit().hashCode();
624 result = prime * result + ((this.data == null) ? 0 : this.data.hashCode());
625 return result;
626 }
627
628 @Override
629 @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
630 public boolean equals(final Object obj)
631 {
632 if (this == obj)
633 return true;
634 if (obj == null)
635 return false;
636 if (getClass() != obj.getClass())
637 return false;
638 DoubleMatrix<?, ?, ?, ?> other = (DoubleMatrix<?, ?, ?, ?>) obj;
639 if (!getDisplayUnit().getStandardUnit().equals(other.getDisplayUnit().getStandardUnit()))
640 return false;
641 if (this.data == null)
642 {
643 if (other.data != null)
644 return false;
645 }
646 else if (!this.data.equals(other.data))
647 return false;
648 return true;
649 }
650
651 }