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.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.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.AbstractFloatScalar;
16 import org.djunits.value.vfloat.scalar.base.FloatScalar;
17 import org.djunits.value.vfloat.vector.base.AbstractFloatVector;
18 import org.djunits.value.vfloat.vector.data.FloatVectorData;
19 import org.djutils.exceptions.Throw;
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 public abstract class AbstractFloatMatrix<U extends Unit<U>, S extends AbstractFloatScalar<U, S>,
35 V extends AbstractFloatVector<U, S, V>, M extends AbstractFloatMatrix<U, S, V, M>>
36 extends AbstractIndexedValue<U, S, M, FloatMatrixData> implements FloatMatrixInterface<U, S, V, M>
37 {
38
39 private static final long serialVersionUID = 20161015L;
40
41
42 @SuppressWarnings("checkstyle:visibilitymodifier")
43 protected FloatMatrixData data;
44
45
46
47
48
49
50 AbstractFloatMatrix(final FloatMatrixData 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 FloatMatrixData getData()
60 {
61 return this.data;
62 }
63
64
65 @Override
66 protected void setData(final FloatMatrixData data)
67 {
68 this.data = data;
69 }
70
71
72 @Override
73 public float 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 float getInUnit(final int row, final int column) throws ValueRuntimeException
82 {
83 checkIndex(row, column);
84 return (float) ValueUtil.expressAsUnit(this.data.getSI(row, column), getDisplayUnit());
85 }
86
87
88 @Override
89 public float getInUnit(final int row, final int column, final U targetUnit) throws ValueRuntimeException
90 {
91 checkIndex(row, column);
92 return (float) ValueUtil.expressAsUnit(this.data.getSI(row, column), targetUnit);
93 }
94
95
96 @Override
97 public void setSI(final int row, final int column, final float 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 float valueInUnit) throws ValueRuntimeException
107 {
108 setSI(row, column, (float) ValueUtil.expressAsSIUnit(valueInUnit, getDisplayUnit()));
109 }
110
111
112 @Override
113 public void setInUnit(final int row, final int column, final float valueInUnit, final U valueUnit)
114 throws ValueRuntimeException
115 {
116 setSI(row, column, (float) 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 float[] getRowSI(final int row) throws ValueRuntimeException
129 {
130 checkRowIndex(row);
131 float[] result = new float[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 float[] getColumnSI(final int column) throws ValueRuntimeException
142 {
143 checkColumnIndex(column);
144 float[] result = new float[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 float[] getDiagonalSI() throws ValueRuntimeException
155 {
156 checkSquare();
157 float[] result = new float[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 float[][] getValuesSI()
168 {
169 return this.data.getDenseMatrixSI();
170 }
171
172
173 @Override
174 public final float[][] getValuesInUnit()
175 {
176 return getValuesInUnit(getDisplayUnit());
177 }
178
179
180 @Override
181 public final float[][] getValuesInUnit(final U targetUnit)
182 {
183 float[][] 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] = (float) 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 FloatScalar.instantiateSI(getSI(row, column), getDisplayUnit());
232 }
233
234
235 @Override
236 public V getRow(final int row) throws ValueRuntimeException
237 {
238 checkRowIndex(row);
239 FloatVectorData dvd =
240 FloatVectorData.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 FloatVectorData dvd = FloatVectorData.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 FloatVectorData dvd =
260 FloatVectorData.instantiate(getDiagonalSI(), getDisplayUnit().getStandardUnit().getScale(), getStorageType());
261 return instantiateVector(dvd, getDisplayUnit());
262
263 }
264
265
266 @SuppressWarnings("unchecked")
267 @Override
268 public S[] getRowScalars(final int row) throws ValueRuntimeException
269 {
270 checkRowIndex(row);
271 S[] array = (S[]) Array.newInstance(getScalarClass(), cols());
272 for (int col = 0; col < cols(); col++)
273 {
274 array[col] = get(row, col);
275 }
276 return array;
277 }
278
279
280 @SuppressWarnings("unchecked")
281 @Override
282 public S[] getColumnScalars(final int col) throws ValueRuntimeException
283 {
284 checkColumnIndex(col);
285 S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
286 for (int row = 0; row < rows(); row++)
287 {
288 array[row] = get(row, col);
289 }
290 return array;
291 }
292
293
294 @SuppressWarnings("unchecked")
295 @Override
296 public S[] getDiagonalScalars() throws ValueRuntimeException
297 {
298 checkSquare();
299 S[] array = (S[]) Array.newInstance(getScalarClass(), rows());
300 for (int row = 0; row < rows(); row++)
301 {
302 array[row] = get(row, row);
303 }
304 return array;
305 }
306
307
308 @SuppressWarnings("unchecked")
309 @Override
310 public M toSparse()
311 {
312 M result;
313 if (getStorageType().equals(StorageType.SPARSE))
314 {
315 result = (M) this;
316 result.setDisplayUnit(getDisplayUnit());
317 }
318 else
319 {
320 result = instantiateMatrix(this.data.toSparse(), getDisplayUnit());
321 }
322 result.setDisplayUnit(getDisplayUnit());
323 return result;
324 }
325
326
327 @SuppressWarnings("unchecked")
328 @Override
329 public M toDense()
330 {
331 M result;
332 if (getStorageType().equals(StorageType.DENSE))
333 {
334 result = (M) this;
335 result.setDisplayUnit(getDisplayUnit());
336 }
337 else
338 {
339 result = instantiateMatrix(this.data.toDense(), getDisplayUnit());
340 }
341 return result;
342 }
343
344
345 @SuppressWarnings("unchecked")
346 @Override
347 public final M assign(final FloatFunction floatFunction)
348 {
349 checkCopyOnWrite();
350 this.data.assign(floatFunction);
351 return (M) this;
352 }
353
354
355 @Override
356 public final M abs()
357 {
358 return assign(FloatMathFunctions.ABS);
359 }
360
361
362 @Override
363 public final M ceil()
364 {
365 return assign(FloatMathFunctions.CEIL);
366 }
367
368
369 @Override
370 public final M floor()
371 {
372 return assign(FloatMathFunctions.FLOOR);
373 }
374
375
376 @Override
377 public final M neg()
378 {
379 return assign(FloatMathFunctions.NEG);
380 }
381
382
383 @Override
384 public final M rint()
385 {
386 return assign(FloatMathFunctions.RINT);
387 }
388
389
390 @Override
391 public String toString()
392 {
393 return toString(getDisplayUnit(), false, true);
394 }
395
396
397 @Override
398 public String toString(final U displayUnit)
399 {
400 return toString(displayUnit, false, true);
401 }
402
403
404 @Override
405 public String toString(final boolean verbose, final boolean withUnit)
406 {
407 return toString(getDisplayUnit(), verbose, withUnit);
408 }
409
410
411 @Override
412 public String toString(final U displayUnit, final boolean verbose, final boolean withUnit)
413 {
414 StringBuffer buf = new StringBuffer();
415 if (verbose)
416 {
417 String ab = this instanceof Absolute ? "Abs " : "Rel ";
418 String ds = this.data.isDense() ? "Dense " : this.data.isSparse() ? "Sparse " : "?????? ";
419 if (isMutable())
420 {
421 buf.append("Mutable " + ab + ds);
422 }
423 else
424 {
425 buf.append("Immutable " + ab + ds);
426 }
427 }
428 for (int row = 0; row < rows(); row++)
429 {
430 buf.append("\r\n\t");
431 for (int col = 0; col < cols(); col++)
432 {
433 try
434 {
435 float d = (float) ValueUtil.expressAsUnit(getSI(row, col), displayUnit);
436 buf.append(" " + Format.format(d));
437 }
438 catch (ValueRuntimeException ve)
439 {
440 buf.append(" " + "********************".substring(0, Format.DEFAULTSIZE));
441 }
442 }
443 }
444 buf.append("\n");
445 if (withUnit)
446 {
447 buf.append(displayUnit.getLocalizedDisplayAbbreviation());
448 }
449 return buf.toString();
450 }
451
452
453
454
455
456
457
458 protected final void checkIndex(final int row, final int col) throws ValueRuntimeException
459 {
460 if (row < 0 || row >= rows() || col < 0 || col >= cols())
461 {
462 throw new ValueRuntimeException("index out of range (valid range is 0.." + (rows() - 1) + ", 0.." + (cols() - 1)
463 + ", got " + row + ", " + col + ")");
464 }
465 }
466
467
468
469
470
471
472 protected final void checkRowIndex(final int row) throws ValueRuntimeException
473 {
474 if (row < 0 || row >= rows())
475 {
476 throw new ValueRuntimeException("row index out of range (valid range is 0.." + (rows() - 1) + ", got " + row + ")");
477 }
478 }
479
480
481
482
483
484
485 protected final void checkColumnIndex(final int col) throws ValueRuntimeException
486 {
487 if (col < 0 || col >= cols())
488 {
489 throw new ValueRuntimeException(
490 "column index out of range (valid range is 0.." + (cols() - 1) + ", got " + col + ")");
491 }
492 }
493
494
495
496
497
498 protected final void checkSquare() throws ValueRuntimeException
499 {
500 Throw.when(rows() != cols(), ValueRuntimeException.class, "Matrix is not square, rows=%d, cols=%d", rows(), cols());
501 }
502
503
504 @Override
505 public final float determinantSI() throws ValueRuntimeException
506 {
507 checkSquare();
508 return det(getValuesSI());
509 }
510
511
512
513
514
515
516 private static float det(final float[][] mat)
517 {
518 if (mat.length == 1)
519 {
520 return mat[0][0];
521 }
522
523 float det = 0.0f;
524
525 for (int col = 0; col < mat.length; col++)
526 {
527 float sgn = (col % 2 == 0) ? 1 : -1;
528 float aij = mat[0][col];
529 float[][] matAij = new float[mat.length - 1][];
530 int r = 0;
531 for (int row = 1; row < mat.length; row++)
532 {
533 matAij[r] = new float[matAij.length];
534 int c = 0;
535 for (int j = 0; j < mat.length; j++)
536 {
537 if (j != col)
538 {
539 matAij[r][c++] = mat[row][j];
540 }
541 }
542 r++;
543 }
544 det += sgn * aij * det(matAij);
545 }
546 return det;
547 }
548
549
550 @Override
551 @SuppressWarnings("checkstyle:designforextension")
552 public int hashCode()
553 {
554 final int prime = 31;
555 int result = getDisplayUnit().getStandardUnit().hashCode();
556 result = prime * result + ((this.data == null) ? 0 : this.data.hashCode());
557 return result;
558 }
559
560
561 @Override
562 @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
563 public boolean equals(final Object obj)
564 {
565 if (this == obj)
566 return true;
567 if (obj == null)
568 return false;
569 if (getClass() != obj.getClass())
570 return false;
571 AbstractFloatMatrix<?, ?, ?, ?> other = (AbstractFloatMatrix<?, ?, ?, ?>) obj;
572 if (!getDisplayUnit().getStandardUnit().equals(other.getDisplayUnit().getStandardUnit()))
573 return false;
574 if (this.data == null)
575 {
576 if (other.data != null)
577 return false;
578 }
579 else if (!this.data.equals(other.data))
580 return false;
581 return true;
582 }
583 }