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