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