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