1 package org.djunits.value.vfloat.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.vfloat.function.FloatFunction;
13 import org.djunits.value.vfloat.function.FloatMathFunctions;
14 import org.djunits.value.vfloat.matrix.data.FloatMatrixData;
15 import org.djunits.value.vfloat.scalar.base.FloatScalar;
16 import org.djunits.value.vfloat.vector.base.FloatVector;
17 import org.djunits.value.vfloat.vector.data.FloatVectorData;
18 import org.djutils.exceptions.Throw;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public abstract class FloatMatrix<U extends Unit<U>, S extends FloatScalar<U, S>, V extends FloatVector<U, S, V>,
34 M extends FloatMatrix<U, S, V, M>> extends Matrix<U, S, V, FloatVectorData, M, FloatMatrixData>
35 {
36
37 private static final long serialVersionUID = 20161015L;
38
39
40 @SuppressWarnings("checkstyle:visibilitymodifier")
41 protected FloatMatrixData data;
42
43
44
45
46
47
48 public FloatMatrix(final FloatMatrixData 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(FloatMatrixData fmd, U displayUnit);
64
65
66
67
68
69
70
71
72
73 public abstract V instantiateVector(FloatVectorData fvd, U displayUnit);
74
75
76
77
78
79
80
81
82
83 public abstract S instantiateScalarSI(float valueSI, U displayUnit);
84
85 @Override
86 protected final FloatMatrixData getData()
87 {
88 return this.data;
89 }
90
91 @Override
92 protected void setData(final FloatMatrixData data)
93 {
94 this.data = data;
95 }
96
97
98
99
100
101
102
103
104
105 public float 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 float getInUnit(final int row, final int column) throws IndexOutOfBoundsException
120 {
121 checkIndex(row, column);
122 return (float) ValueUtil.expressAsUnit(this.data.getSI(row, column), getDisplayUnit());
123 }
124
125
126
127
128
129
130
131
132
133
134 public float getInUnit(final int row, final int column, final U targetUnit) throws IndexOutOfBoundsException
135 {
136 checkIndex(row, column);
137 return (float) 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 float 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 float valueInUnit) throws IndexOutOfBoundsException
162 {
163 setSI(row, column, (float) 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 float valueInUnit, final U valueUnit)
175 throws IndexOutOfBoundsException
176 {
177 setSI(row, column, (float) 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 float[] getRowSI(final int row) throws IndexOutOfBoundsException
199 {
200 checkRowIndex(row);
201 float[] result = new float[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 float[] getColumnSI(final int column) throws IndexOutOfBoundsException
216 {
217 checkColumnIndex(column);
218 float[] result = new float[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 float[] getDiagonalSI() throws ValueRuntimeException
232 {
233 checkSquare();
234 float[] result = new float[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 float[][] getValuesSI()
247 {
248 return this.data.getDenseMatrixSI();
249 }
250
251
252
253
254
255 public final float[][] getValuesInUnit()
256 {
257 return getValuesInUnit(getDisplayUnit());
258 }
259
260
261
262
263
264
265 public final float[][] getValuesInUnit(final U targetUnit)
266 {
267 float[][] 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] = (float) 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 FloatScalar.instantiateSI(getSI(row, column), getDisplayUnit());
312 }
313
314 @Override
315 public V getRow(final int row) throws IndexOutOfBoundsException
316 {
317 checkRowIndex(row);
318 FloatVectorData dvd =
319 FloatVectorData.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 FloatVectorData dvd = FloatVectorData.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 FloatVectorData dvd =
337 FloatVectorData.instantiate(getDiagonalSI(), getDisplayUnit().getStandardUnit().getScale(), getStorageType());
338 return instantiateVector(dvd, getDisplayUnit());
339
340 }
341
342 @SuppressWarnings("unchecked")
343 @Override
344 public S[] getRowScalars(final int row) throws IndexOutOfBoundsException
345 {
346 checkRowIndex(row);
347 S[] array = (S[]) Array.newInstance(getScalarClass(), cols());
348 for (int col = 0; col < cols(); col++)
349 {
350 array[col] = get(row, col);
351 }
352 return array;
353 }
354
355 @SuppressWarnings("unchecked")
356 @Override
357 public S[] getColumnScalars(final int col) throws IndexOutOfBoundsException
358 {
359 checkColumnIndex(col);
360 S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
361 for (int row = 0; row < rows(); row++)
362 {
363 array[row] = get(row, col);
364 }
365 return array;
366 }
367
368 @SuppressWarnings("unchecked")
369 @Override
370 public S[] getDiagonalScalars() throws ValueRuntimeException
371 {
372 checkSquare();
373 S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
374 for (int row = 0; row < rows(); row++)
375 {
376 array[row] = get(row, row);
377 }
378 return array;
379 }
380
381 @SuppressWarnings("unchecked")
382 @Override
383 public M toSparse()
384 {
385 M result;
386 if (getStorageType().equals(StorageType.SPARSE))
387 {
388 result = (M) this;
389 result.setDisplayUnit(getDisplayUnit());
390 }
391 else
392 {
393 result = instantiateMatrix(this.data.toSparse(), getDisplayUnit());
394 }
395 result.setDisplayUnit(getDisplayUnit());
396 return result;
397 }
398
399 @SuppressWarnings("unchecked")
400 @Override
401 public M toDense()
402 {
403 M result;
404 if (getStorageType().equals(StorageType.DENSE))
405 {
406 result = (M) this;
407 result.setDisplayUnit(getDisplayUnit());
408 }
409 else
410 {
411 result = instantiateMatrix(this.data.toDense(), getDisplayUnit());
412 }
413 return result;
414 }
415
416
417
418
419
420
421 @SuppressWarnings("unchecked")
422 public final M assign(final FloatFunction floatFunction)
423 {
424 checkCopyOnWrite();
425 this.data.assign(floatFunction);
426 return (M) this;
427 }
428
429 @Override
430 public final M abs()
431 {
432 return assign(FloatMathFunctions.ABS);
433 }
434
435 @Override
436 public final M ceil()
437 {
438 return assign(FloatMathFunctions.CEIL);
439 }
440
441 @Override
442 public final M floor()
443 {
444 return assign(FloatMathFunctions.FLOOR);
445 }
446
447 @Override
448 public final M neg()
449 {
450 return assign(FloatMathFunctions.NEG);
451 }
452
453 @Override
454 public final M rint()
455 {
456 return assign(FloatMathFunctions.RINT);
457 }
458
459 @Override
460 public String toString()
461 {
462 return toString(getDisplayUnit(), false, true);
463 }
464
465 @Override
466 public String toString(final U displayUnit)
467 {
468 return toString(displayUnit, false, true);
469 }
470
471 @Override
472 public String toString(final boolean verbose, final boolean withUnit)
473 {
474 return toString(getDisplayUnit(), verbose, withUnit);
475 }
476
477 @Override
478 public String toString(final U displayUnit, final boolean verbose, final boolean withUnit)
479 {
480 StringBuffer buf = new StringBuffer();
481 if (verbose)
482 {
483 String ab = this instanceof Absolute ? "Abs " : "Rel ";
484 String ds = this.data.isDense() ? "Dense " : this.data.isSparse() ? "Sparse " : "?????? ";
485 if (isMutable())
486 {
487 buf.append("Mutable " + ab + ds);
488 }
489 else
490 {
491 buf.append("Immutable " + ab + ds);
492 }
493 }
494 for (int row = 0; row < rows(); row++)
495 {
496 buf.append("\r\n\t");
497 for (int col = 0; col < cols(); col++)
498 {
499 try
500 {
501 float d = (float) ValueUtil.expressAsUnit(getSI(row, col), displayUnit);
502 buf.append(" " + Format.format(d));
503 }
504 catch (IndexOutOfBoundsException ve)
505 {
506 buf.append(" " + "********************".substring(0, Format.DEFAULTSIZE));
507 }
508 }
509 }
510 buf.append("\n");
511 if (withUnit)
512 {
513 buf.append(displayUnit.getLocalizedDisplayAbbreviation());
514 }
515 return buf.toString();
516 }
517
518
519
520
521
522
523
524 protected final void checkIndex(final int row, final int col) throws IndexOutOfBoundsException
525 {
526 if (row < 0 || row >= rows() || col < 0 || col >= cols())
527 {
528 throw new IndexOutOfBoundsException("index out of range (valid range is 0.." + (rows() - 1) + ", 0.." + (cols() - 1)
529 + ", got " + row + ", " + col + ")");
530 }
531 }
532
533
534
535
536
537
538 protected final void checkRowIndex(final int row) throws IndexOutOfBoundsException
539 {
540 if (row < 0 || row >= rows())
541 {
542 throw new IndexOutOfBoundsException(
543 "row index out of range (valid range is 0.." + (rows() - 1) + ", got " + row + ")");
544 }
545 }
546
547
548
549
550
551
552 protected final void checkColumnIndex(final int col) throws IndexOutOfBoundsException
553 {
554 if (col < 0 || col >= cols())
555 {
556 throw new IndexOutOfBoundsException(
557 "column index out of range (valid range is 0.." + (cols() - 1) + ", got " + col + ")");
558 }
559 }
560
561
562
563
564
565 protected final void checkSquare() throws ValueRuntimeException
566 {
567 Throw.when(rows() != cols(), ValueRuntimeException.class, "Matrix is not square, rows=%d, cols=%d", rows(), cols());
568 }
569
570
571
572
573
574
575 public final float determinantSI() throws ValueRuntimeException
576 {
577 checkSquare();
578 return det(getValuesSI());
579 }
580
581
582
583
584
585
586 private static float det(final float[][] mat)
587 {
588 if (mat.length == 1)
589 {
590 return mat[0][0];
591 }
592
593 float det = 0.0f;
594
595 for (int col = 0; col < mat.length; col++)
596 {
597 float sgn = (col % 2 == 0) ? 1 : -1;
598 float aij = mat[0][col];
599 float[][] matAij = new float[mat.length - 1][];
600 int r = 0;
601 for (int row = 1; row < mat.length; row++)
602 {
603 matAij[r] = new float[matAij.length];
604 int c = 0;
605 for (int j = 0; j < mat.length; j++)
606 {
607 if (j != col)
608 {
609 matAij[r][c++] = mat[row][j];
610 }
611 }
612 r++;
613 }
614 det += sgn * aij * det(matAij);
615 }
616 return det;
617 }
618
619 @Override
620 @SuppressWarnings("checkstyle:designforextension")
621 public int hashCode()
622 {
623 final int prime = 31;
624 int result = getDisplayUnit().getStandardUnit().hashCode();
625 result = prime * result + ((this.data == null) ? 0 : this.data.hashCode());
626 return result;
627 }
628
629 @Override
630 @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
631 public boolean equals(final Object obj)
632 {
633 if (this == obj)
634 return true;
635 if (obj == null)
636 return false;
637 if (getClass() != obj.getClass())
638 return false;
639 FloatMatrix<?, ?, ?, ?> other = (FloatMatrix<?, ?, ?, ?>) obj;
640 if (!getDisplayUnit().getStandardUnit().equals(other.getDisplayUnit().getStandardUnit()))
641 return false;
642 if (this.data == null)
643 {
644 if (other.data != null)
645 return false;
646 }
647 else if (!this.data.equals(other.data))
648 return false;
649 return true;
650 }
651
652 }