1 package org.djunits.value.vdouble.vector;
2
3 import java.io.Serializable;
4 import java.util.Arrays;
5 import java.util.List;
6 import java.util.SortedMap;
7 import java.util.stream.IntStream;
8
9 import org.djunits.unit.scale.Scale;
10 import org.djunits.value.StorageType;
11 import org.djunits.value.ValueException;
12 import org.djunits.value.vdouble.scalar.DoubleScalarInterface;
13
14
15
16
17
18
19
20
21
22
23
24
25 abstract class DoubleVectorData implements Serializable
26 {
27
28 private static final long serialVersionUID = 1L;
29
30
31 @SuppressWarnings("checkstyle:visibilitymodifier")
32 protected double[] vectorSI;
33
34
35 private final StorageType storageType;
36
37
38 protected static final int PARALLEL_THRESHOLD = 1000;
39
40
41
42
43 DoubleVectorData(final StorageType storageType)
44 {
45 super();
46 this.storageType = storageType;
47 }
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public static DoubleVectorData instantiate(final double[] values, final Scale scale, final StorageType storageType)
62 throws ValueException
63 {
64 if (values == null)
65 {
66 throw new ValueException("DoubleVectorData.instantiate: double[] values is null");
67 }
68
69 double[] valuesSI = scale.isBaseSIScale() ? values : new double[values.length];
70 if (!scale.isBaseSIScale())
71 {
72 if (values.length > PARALLEL_THRESHOLD)
73 {
74 IntStream.range(0, values.length).parallel().forEach(i -> valuesSI[i] = scale.toStandardUnit(values[i]));
75 }
76 else
77 {
78 IntStream.range(0, values.length).forEach(i -> valuesSI[i] = scale.toStandardUnit(values[i]));
79 }
80 }
81
82 switch (storageType)
83 {
84 case DENSE:
85 return new DoubleVectorDataDense(valuesSI);
86
87 case SPARSE:
88 return DoubleVectorDataSparse.instantiate(valuesSI);
89
90 default:
91 throw new ValueException("Unknown data type in DoubleVectorData.instantiate: " + storageType);
92 }
93 }
94
95
96
97
98
99
100
101
102
103 public static DoubleVectorData instantiate(final List<Double> values, final Scale scale, final StorageType storageType)
104 throws ValueException
105 {
106 if (values == null)
107 {
108 throw new ValueException("DoubleVectorData.instantiate: List<Double> values is null");
109 }
110
111 double[] valuesSI;
112 if (values.size() > PARALLEL_THRESHOLD)
113 {
114 if (scale.isBaseSIScale())
115 {
116 valuesSI = values.parallelStream().mapToDouble(d -> d).toArray();
117 }
118 else
119 {
120 valuesSI = values.parallelStream().mapToDouble(d -> scale.toStandardUnit(d)).toArray();
121 }
122 }
123 else
124 {
125 if (scale.isBaseSIScale())
126 {
127 valuesSI = values.stream().mapToDouble(d -> d).toArray();
128 }
129 else
130 {
131 valuesSI = values.stream().mapToDouble(d -> scale.toStandardUnit(d)).toArray();
132 }
133 }
134
135 switch (storageType)
136 {
137 case DENSE:
138 return new DoubleVectorDataDense(valuesSI);
139
140 case SPARSE:
141 return DoubleVectorDataSparse.instantiate(valuesSI);
142
143 default:
144 throw new ValueException("Unknown data type in DoubleVectorData.instantiate: " + storageType);
145 }
146 }
147
148
149
150
151
152
153
154
155 public static DoubleVectorData instantiate(final DoubleScalarInterface[] values, final StorageType storageType)
156 throws ValueException
157 {
158 if (values == null)
159 {
160 throw new ValueException("DoubleVectorData.instantiate: DoubleScalar[] values is null");
161 }
162
163 double[] valuesSI;
164 if (values.length > PARALLEL_THRESHOLD)
165 {
166 valuesSI = Arrays.stream(values).parallel().mapToDouble(s -> s.getSI()).toArray();
167 }
168 else
169 {
170 valuesSI = Arrays.stream(values).mapToDouble(s -> s.getSI()).toArray();
171 }
172
173 switch (storageType)
174 {
175 case DENSE:
176 return new DoubleVectorDataDense(valuesSI);
177
178 case SPARSE:
179 return DoubleVectorDataSparse.instantiate(valuesSI);
180
181 default:
182 throw new ValueException("Unknown data type in DoubleVectorData.instantiate: " + storageType);
183 }
184 }
185
186
187
188
189
190
191
192
193 public static DoubleVectorData instantiateLD(final List<? extends DoubleScalarInterface> values,
194 final StorageType storageType) throws ValueException
195 {
196 if (values == null)
197 {
198 throw new ValueException("DoubleVectorData.instantiate: values list is null");
199 }
200
201 double[] valuesSI = values.parallelStream().mapToDouble(s -> s.getSI()).toArray();
202
203 switch (storageType)
204 {
205 case DENSE:
206 return new DoubleVectorDataDense(valuesSI);
207
208 case SPARSE:
209 return DoubleVectorDataSparse.instantiate(valuesSI);
210
211 default:
212 throw new ValueException("Unknown data type in DoubleVectorData.instantiate: " + storageType);
213 }
214 }
215
216
217
218
219
220
221
222
223
224
225 public static <S extends DoubleScalarInterface> DoubleVectorData instantiateMD(final SortedMap<Integer, S> values,
226 final int length, final StorageType storageType) throws ValueException
227 {
228 if (values == null)
229 {
230 throw new ValueException("DoubleVectorData.instantiate: values map is null");
231 }
232
233 switch (storageType)
234 {
235 case DENSE:
236 {
237 double[] valuesSI = values.keySet().parallelStream().mapToDouble(index -> values.get(index).getSI()).toArray();
238 return new DoubleVectorDataDense(valuesSI);
239 }
240
241 case SPARSE:
242 {
243 int[] indices = values.keySet().parallelStream().mapToInt(i -> i).toArray();
244 double[] valuesSI = values.values().parallelStream().mapToDouble(s -> s.getSI()).toArray();
245 return new DoubleVectorDataSparse(valuesSI, indices, length);
246 }
247
248 default:
249 throw new ValueException("Unknown data type in DoubleVectorData.instantiate: " + storageType);
250 }
251 }
252
253
254
255
256
257
258
259
260
261
262 public static DoubleVectorData instantiate(final SortedMap<Integer, Double> values, final int length, final Scale scale,
263 final StorageType storageType) throws ValueException
264 {
265 if (values == null)
266 {
267 throw new ValueException("DoubleVectorData.instantiate: values map is null");
268 }
269
270 switch (storageType)
271 {
272 case DENSE:
273 {
274 double[] valuesSI = values.keySet().parallelStream()
275 .mapToDouble(index -> scale.toStandardUnit(values.get(index))).toArray();
276 return new DoubleVectorDataDense(valuesSI);
277 }
278
279 case SPARSE:
280 {
281 int[] indices = values.keySet().parallelStream().mapToInt(i -> i).toArray();
282 double[] valuesSI = values.values().parallelStream().mapToDouble(d -> scale.toStandardUnit(d)).toArray();
283 return new DoubleVectorDataSparse(valuesSI, indices, length);
284 }
285
286 default:
287 throw new ValueException("Unknown data type in DoubleVectorData.instantiate: " + storageType);
288 }
289 }
290
291
292
293
294
295
296
297
298
299 public final StorageType getStorageType()
300 {
301 return this.storageType;
302 }
303
304
305
306
307 public abstract int size();
308
309
310
311
312 public boolean isSparse()
313 {
314 return this.storageType.equals(StorageType.SPARSE);
315 }
316
317
318
319
320 public DoubleVectorDataSparse toSparse()
321 {
322 return isSparse() ? (DoubleVectorDataSparse) this : ((DoubleVectorDataDense) this).toSparse();
323 }
324
325
326
327
328 public boolean isDense()
329 {
330 return this.storageType.equals(StorageType.DENSE);
331 }
332
333
334
335
336 public DoubleVectorDataDense toDense()
337 {
338 return isDense() ? (DoubleVectorDataDense) this : ((DoubleVectorDataSparse) this).toDense();
339 }
340
341
342
343
344
345 public abstract double getSI(int index);
346
347
348
349
350
351
352 public abstract void setSI(int index, double valueSI);
353
354
355
356
357 public final int cardinality()
358 {
359 return (int) Arrays.stream(this.vectorSI).parallel().filter(d -> d != 0.0).count();
360 }
361
362
363
364
365 public final double zSum()
366 {
367 return Arrays.stream(this.vectorSI).parallel().sum();
368 }
369
370
371
372
373 public abstract DoubleVectorData copy();
374
375
376
377
378 public abstract double[] getDenseVectorSI();
379
380
381
382
383
384
385 private void checkSizes(final DoubleVectorData other) throws ValueException
386 {
387 if (this.size() != other.size())
388 {
389 throw new ValueException("Two data objects used in a DoubleVector operation do not have the same size");
390 }
391 }
392
393
394
395
396
397
398
399
400
401
402
403
404 public DoubleVectorData plus(final DoubleVectorData right) throws ValueException
405 {
406 checkSizes(right);
407 double[] dv = IntStream.range(0, size()).parallel().mapToDouble(i -> getSI(i) + right.getSI(i)).toArray();
408 if (this instanceof DoubleVectorDataSparse && right instanceof DoubleVectorDataSparse)
409 {
410 return new DoubleVectorDataDense(dv).toSparse();
411 }
412 return new DoubleVectorDataDense(dv);
413 }
414
415
416
417
418
419
420 public abstract void incrementBy(DoubleVectorData right) throws ValueException;
421
422
423
424
425
426 public void incrementBy(final double valueSI)
427 {
428 IntStream.range(0, this.vectorSI.length).parallel().forEach(i -> this.vectorSI[i] += valueSI);
429 }
430
431
432
433
434
435
436
437
438 public DoubleVectorData minus(final DoubleVectorData right) throws ValueException
439 {
440 checkSizes(right);
441 double[] dv = IntStream.range(0, size()).parallel().mapToDouble(i -> getSI(i) - right.getSI(i)).toArray();
442 if (this instanceof DoubleVectorDataSparse && right instanceof DoubleVectorDataSparse)
443 {
444 return new DoubleVectorDataDense(dv).toSparse();
445 }
446 return new DoubleVectorDataDense(dv);
447 }
448
449
450
451
452
453
454 public abstract void decrementBy(DoubleVectorData right) throws ValueException;
455
456
457
458
459
460 public void decrementBy(final double valueSI)
461 {
462 IntStream.range(0, this.vectorSI.length).parallel().forEach(i -> this.vectorSI[i] -= valueSI);
463 }
464
465
466
467
468
469
470
471
472 public DoubleVectorData times(final DoubleVectorData right) throws ValueException
473 {
474 checkSizes(right);
475 double[] dv = IntStream.range(0, size()).parallel().mapToDouble(i -> getSI(i) * right.getSI(i)).toArray();
476 if (this instanceof DoubleVectorDataDense && right instanceof DoubleVectorDataDense)
477 {
478 return new DoubleVectorDataDense(dv);
479 }
480 return new DoubleVectorDataDense(dv).toSparse();
481 }
482
483
484
485
486
487
488
489 public abstract void multiplyBy(DoubleVectorData right) throws ValueException;
490
491
492
493
494
495 public void multiplyBy(final double valueSI)
496 {
497 IntStream.range(0, this.vectorSI.length).parallel().forEach(i -> this.vectorSI[i] *= valueSI);
498 }
499
500
501
502
503
504
505
506
507 public DoubleVectorData divide(final DoubleVectorData right) throws ValueException
508 {
509 checkSizes(right);
510 double[] dv = IntStream.range(0, size()).parallel().mapToDouble(i -> getSI(i) / right.getSI(i)).toArray();
511 if (this instanceof DoubleVectorDataDense && right instanceof DoubleVectorDataDense)
512 {
513 return new DoubleVectorDataDense(dv);
514 }
515 return new DoubleVectorDataDense(dv).toSparse();
516 }
517
518
519
520
521
522
523
524 public abstract void divideBy(DoubleVectorData right) throws ValueException;
525
526
527
528
529
530 public void divideBy(final double valueSI)
531 {
532 IntStream.range(0, this.vectorSI.length).parallel().forEach(i -> this.vectorSI[i] /= valueSI);
533 }
534
535
536
537
538
539
540 @Override
541 public int hashCode()
542 {
543 final int prime = 31;
544 int result = 1;
545 result = prime * result + Arrays.hashCode(this.vectorSI);
546 return result;
547 }
548
549
550 @Override
551 @SuppressWarnings("checkstyle:needbraces")
552 public boolean equals(final Object obj)
553 {
554 if (this == obj)
555 return true;
556 if (obj == null)
557 return false;
558 if (getClass() != obj.getClass())
559 return false;
560 DoubleVectorData other = (DoubleVectorData) obj;
561 if (!Arrays.equals(this.vectorSI, other.vectorSI))
562 return false;
563 return true;
564 }
565
566
567 @Override
568 public String toString()
569 {
570 return "DoubleVectorData [storageType=" + this.storageType + ", vectorSI=" + Arrays.toString(this.vectorSI) + "]";
571 }
572 }