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