1 package org.djunits.value.vdouble.matrix.data;
2
3 import java.io.Serializable;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.stream.IntStream;
7
8 import org.djunits.unit.Unit;
9 import org.djunits.unit.scale.Scale;
10 import org.djunits.value.ValueRuntimeException;
11 import org.djunits.value.storage.Storage;
12 import org.djunits.value.storage.StorageType;
13 import org.djunits.value.vdouble.function.DoubleFunction;
14 import org.djunits.value.vdouble.function.DoubleFunction2;
15 import org.djunits.value.vdouble.matrix.base.DoubleSparseValue;
16 import org.djunits.value.vdouble.scalar.base.DoubleScalar;
17 import org.djutils.exceptions.Throw;
18
19
20
21
22
23
24
25
26
27
28 public abstract class DoubleMatrixData extends Storage<DoubleMatrixData> implements Serializable
29 {
30
31 private static final long serialVersionUID = 1L;
32
33
34 @SuppressWarnings("checkstyle:visibilitymodifier")
35 protected double[] matrixSI;
36
37
38 @SuppressWarnings("checkstyle:visibilitymodifier")
39 protected int rows;
40
41
42 @SuppressWarnings("checkstyle:visibilitymodifier")
43 protected int cols;
44
45
46
47
48
49 DoubleMatrixData(final StorageType storageType)
50 {
51 super(storageType);
52 }
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public static DoubleMatrixData instantiate(final double[][] values, final Scale scale, final StorageType storageType)
69 throws ValueRuntimeException
70 {
71 Throw.whenNull(scale, "DoubleMatrixData.instantiate: scale is null");
72 Throw.whenNull(storageType, "DoubleMatrixData.instantiate: storageType is null");
73 checkRectangularAndNonNull(values);
74
75 int rows = values.length;
76 final int cols = rows == 0 ? 0 : values[0].length;
77 if (cols == 0)
78 {
79 rows = 0;
80 }
81
82 switch (storageType)
83 {
84 case DENSE:
85 double[] valuesSI = new double[rows * cols];
86 IntStream.range(0, values.length).parallel().forEach(r -> IntStream.range(0, cols)
87 .forEach(c -> valuesSI[r * cols + c] = scale.toStandardUnit(values[r][c])));
88 return new DoubleMatrixDataDense(valuesSI, rows, cols);
89
90 case SPARSE:
91 return DoubleMatrixDataSparse.instantiate(values, scale);
92
93 default:
94 throw new ValueRuntimeException("Unknown storage type in DoubleMatrixData.instantiate: " + storageType);
95 }
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public static <U extends Unit<U>, S extends DoubleScalar<U, S>> DoubleMatrixData instantiate(
111 final Collection<DoubleSparseValue<U, S>> values, final int rows, final int cols, final StorageType storageType)
112 throws ValueRuntimeException
113 {
114 Throw.whenNull(values, "DoubleMatrixData.instantiate: values is null");
115 Throw.whenNull(storageType, "DoubleMatrixData.instantiate: storageType is null");
116 Throw.when(cols < 0, ValueRuntimeException.class, "cols must be >= 0");
117 Throw.when(rows < 0, ValueRuntimeException.class, "rows must be >= 0");
118 for (DoubleSparseValue<U, S> dsp : values)
119 {
120 Throw.whenNull(dsp, "null value in values");
121 Throw.when(dsp.getRow() < 0 || dsp.getRow() >= rows, ValueRuntimeException.class, "row out of range");
122 Throw.when(dsp.getColumn() < 0 || dsp.getColumn() >= cols, ValueRuntimeException.class, "column out of range");
123 }
124
125 switch (storageType)
126 {
127 case DENSE:
128 double[] valuesSI = new double[rows * cols];
129 values.stream().parallel().forEach(v -> valuesSI[v.getRow() * cols + v.getColumn()] = v.getValueSI());
130 return new DoubleMatrixDataDense(valuesSI, rows, cols);
131
132 case SPARSE:
133 return new DoubleMatrixDataSparse(values, rows, cols);
134
135 default:
136 throw new ValueRuntimeException("Unknown storage type in DoubleMatrixData.instantiate: " + storageType);
137 }
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151 public static <U extends Unit<U>, S extends DoubleScalar<U, S>> DoubleMatrixData instantiate(final S[][] values,
152 final StorageType storageType) throws ValueRuntimeException
153 {
154 Throw.whenNull(storageType, "DoubleMatrixData.instantiate: storageType is null");
155 checkRectangularAndNonNull(values);
156
157 int rows = values.length;
158 final int cols = rows == 0 ? 0 : values[0].length;
159 if (cols == 0)
160 {
161 rows = 0;
162 }
163
164 switch (storageType)
165 {
166 case DENSE:
167 double[] valuesSI = new double[rows * cols];
168 IntStream.range(0, rows).parallel()
169 .forEach(r -> IntStream.range(0, cols).forEach(c -> valuesSI[r * cols + c] = values[r][c].getSI()));
170 return new DoubleMatrixDataDense(valuesSI, rows, cols);
171
172 case SPARSE:
173 double[][] matrixSI = new double[rows][cols];
174 IntStream.range(0, values.length).parallel()
175 .forEach(r -> IntStream.range(0, cols).forEach(c -> matrixSI[r][c] = values[r][c].getSI()));
176 return DoubleMatrixDataSparse.instantiate(matrixSI);
177
178 default:
179 throw new ValueRuntimeException("Unknown storage type in DoubleMatrixData.instantiate: " + storageType);
180 }
181 }
182
183
184
185
186
187
188
189
190
191 public int rows()
192 {
193 return this.rows;
194 }
195
196
197
198
199
200 public int cols()
201 {
202 return this.cols;
203 }
204
205
206
207
208
209 public abstract DoubleMatrixDataDense toDense();
210
211
212
213
214
215 public abstract DoubleMatrixDataSparse toSparse();
216
217
218
219
220
221
222
223 public abstract double getSI(int row, int col);
224
225
226
227
228
229
230
231 public abstract void setSI(int row, int col, double valueSI);
232
233
234
235
236
237 public final double zSum()
238 {
239 return Arrays.stream(this.matrixSI).parallel().sum();
240 }
241
242
243
244
245
246
247 public abstract double[][] getDenseMatrixSI();
248
249
250
251
252
253
254
255
256 protected static double[][] checkRectangularAndNonNull(final double[][] values) throws ValueRuntimeException
257 {
258 Throw.when(null == values, NullPointerException.class, "Cannot create a matrix from a null double[][]");
259 for (int row = 0; row < values.length; row++)
260 {
261 Throw.when(null == values[row], ValueRuntimeException.class,
262 "Cannot create a matrix from double[][] containing null row(s)");
263 Throw.when(values[row].length != values[0].length, ValueRuntimeException.class,
264 "Cannot create a matrix from a jagged double[][]");
265 }
266 return values;
267 }
268
269
270
271
272
273
274
275
276
277
278 protected static <U extends Unit<U>, S extends DoubleScalar<U, S>> S[][] checkRectangularAndNonNull(
279 final S[][] values) throws ValueRuntimeException
280 {
281 Throw.when(null == values, NullPointerException.class, "Cannot create a matrix from a null Scalar[][]");
282 for (int row = 0; row < values.length; row++)
283 {
284 Throw.when(null == values[row], ValueRuntimeException.class,
285 "Cannot create a matrix from Scalar[][] containing null row(s)");
286 Throw.when(values[row].length != values[0].length, ValueRuntimeException.class,
287 "Cannot create a matrix from a jagged Scalar[][]");
288 for (int col = 0; col < values[row].length; col++)
289 {
290 Throw.whenNull(values[row][col], "Cannot create a matrix from Scalar[][] containing null(s)");
291 }
292 }
293 return values;
294 }
295
296
297
298
299
300
301 protected void checkSizes(final DoubleMatrixData other) throws ValueRuntimeException
302 {
303 if (this.rows() != other.rows() || this.cols() != other.cols())
304 {
305 throw new ValueRuntimeException("Two data objects used in a DoubleMatrix operation do not have the same size");
306 }
307 }
308
309
310
311
312
313
314
315
316
317
318 public abstract DoubleMatrixData assign(DoubleFunction doubleFunction);
319
320
321
322
323
324
325
326
327 abstract DoubleMatrixData assign(DoubleFunction2 doubleFunction2, DoubleMatrixData right) throws ValueRuntimeException;
328
329
330
331
332
333
334
335
336 public abstract DoubleMatrixData plus(DoubleMatrixData right) throws ValueRuntimeException;
337
338
339
340
341
342
343
344 public final DoubleMatrixData incrementBy(final DoubleMatrixData right) throws ValueRuntimeException
345 {
346 return assign(new DoubleFunction2()
347 {
348 @Override
349 public double apply(final double leftValue, final double rightValue)
350 {
351 return leftValue + rightValue;
352 }
353 }, right);
354 }
355
356
357
358
359
360
361
362
363 public abstract DoubleMatrixData minus(DoubleMatrixData right) throws ValueRuntimeException;
364
365
366
367
368
369
370
371 public final DoubleMatrixData decrementBy(final DoubleMatrixData decrement) throws ValueRuntimeException
372 {
373 return assign(new DoubleFunction2()
374 {
375 @Override
376 public double apply(final double leftValue, final double rightValue)
377 {
378 return leftValue - rightValue;
379 }
380 }, decrement);
381 }
382
383
384
385
386
387
388
389
390 public abstract DoubleMatrixData times(DoubleMatrixData right) throws ValueRuntimeException;
391
392
393
394
395
396
397
398
399 public final DoubleMatrixData multiplyBy(final DoubleMatrixData right) throws ValueRuntimeException
400 {
401 return assign(new DoubleFunction2()
402 {
403 @Override
404 public double apply(final double leftValue, final double rightValue)
405 {
406 return leftValue * rightValue;
407 }
408 }, right);
409 }
410
411
412
413
414
415
416
417
418 public abstract DoubleMatrixData divide(DoubleMatrixData right) throws ValueRuntimeException;
419
420
421
422
423
424
425
426
427 public final DoubleMatrixData divideBy(final DoubleMatrixData right) throws ValueRuntimeException
428 {
429 return assign(new DoubleFunction2()
430 {
431 @Override
432 public double apply(final double leftValue, final double rightValue)
433 {
434 return leftValue / rightValue;
435 }
436 }, right);
437 }
438
439
440
441
442
443 @Override
444 public int hashCode()
445 {
446 final int prime = 31;
447 int result = 1;
448 result = prime * result + this.rows;
449 result = prime * result + this.cols;
450 for (int row = 0; row < this.rows; row++)
451 {
452 for (int col = 0; col < this.cols; col++)
453 {
454 long bits = Double.doubleToLongBits(getSI(row, col));
455 result = 31 * result + (int) (bits ^ (bits >>> 32));
456 }
457 }
458 return result;
459 }
460
461
462
463
464
465
466
467 protected boolean compareDenseMatrixWithSparseMatrix(final DoubleMatrixDataDense dm, final DoubleMatrixDataSparse sm)
468 {
469 for (int row = 0; row < dm.rows; row++)
470 {
471 for (int col = 0; col < dm.cols; col++)
472 {
473 if (dm.getSI(row, col) != sm.getSI(row, col))
474 {
475 return false;
476 }
477 }
478 }
479 return true;
480 }
481
482 @Override
483 @SuppressWarnings("checkstyle:needbraces")
484 public boolean equals(final Object obj)
485 {
486 if (this == obj)
487 return true;
488 if (obj == null)
489 return false;
490 if (!(obj instanceof DoubleMatrixData))
491 return false;
492 DoubleMatrixData other = (DoubleMatrixData) obj;
493 if (this.rows != other.rows)
494 return false;
495 if (this.cols != other.cols)
496 return false;
497 if (other instanceof DoubleMatrixDataSparse && this instanceof DoubleMatrixDataDense)
498 {
499 return compareDenseMatrixWithSparseMatrix((DoubleMatrixDataDense) this, (DoubleMatrixDataSparse) other);
500 }
501 else if (other instanceof DoubleMatrixDataDense && this instanceof DoubleMatrixDataSparse)
502 {
503 return compareDenseMatrixWithSparseMatrix((DoubleMatrixDataDense) other, (DoubleMatrixDataSparse) this);
504 }
505
506 return Arrays.equals(this.matrixSI, other.matrixSI);
507 }
508
509 }