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