1 package org.djunits.value.vdouble.vector.data;
2
3 import java.io.Serializable;
4 import java.util.Arrays;
5 import java.util.List;
6 import java.util.Map.Entry;
7 import java.util.SortedMap;
8 import java.util.stream.IntStream;
9
10 import org.djunits.Throw;
11 import org.djunits.unit.Unit;
12 import org.djunits.unit.scale.Scale;
13 import org.djunits.value.ValueRuntimeException;
14 import org.djunits.value.storage.AbstractStorage;
15 import org.djunits.value.storage.StorageType;
16 import org.djunits.value.vdouble.function.DoubleFunction;
17 import org.djunits.value.vdouble.function.DoubleFunction2;
18 import org.djunits.value.vdouble.scalar.base.DoubleScalarInterface;
19
20
21
22
23
24
25
26
27
28
29 public abstract class DoubleVectorData extends AbstractStorage<DoubleVectorData> implements Serializable
30 {
31
32 private static final long serialVersionUID = 1L;
33
34
35 @SuppressWarnings("checkstyle:visibilitymodifier")
36 protected double[] vectorSI;
37
38
39 protected static final int PARALLEL_THRESHOLD = 1000;
40
41
42
43
44
45 DoubleVectorData(final StorageType storageType)
46 {
47 super(storageType);
48 }
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public static DoubleVectorData instantiate(final double[] values, final Scale scale, final StorageType storageType)
63 throws ValueRuntimeException
64 {
65 Throw.whenNull(values, "DoubleVectorData.instantiate: double[] values is null");
66 Throw.whenNull(scale, "DoubleVectorData.instantiate: scale is null");
67 Throw.whenNull(storageType, "DoubleVectorData.instantiate: storageType is null");
68 Throw.when(values.length == 0, ValueRuntimeException.class,
69 "DoubleVectorData.instantiate: double[] values wrong: values.length == 0");
70
71 double[] valuesSI = scale.isBaseSIScale() ? values : new double[values.length];
72 if (!scale.isBaseSIScale())
73 {
74 if (values.length > PARALLEL_THRESHOLD)
75 {
76 IntStream.range(0, values.length).parallel().forEach(i -> valuesSI[i] = scale.toStandardUnit(values[i]));
77 }
78 else
79 {
80 IntStream.range(0, values.length).forEach(i -> valuesSI[i] = scale.toStandardUnit(values[i]));
81 }
82 }
83
84 switch (storageType)
85 {
86 case DENSE:
87 return new DoubleVectorDataDense(valuesSI);
88
89 case SPARSE:
90 return DoubleVectorDataSparse.instantiate(valuesSI);
91
92 default:
93 throw new ValueRuntimeException("Unknown storage type in DoubleVectorData.instantiate: " + storageType);
94 }
95 }
96
97
98
99
100
101
102
103
104
105 public static DoubleVectorData instantiate(final List<Double> values, final Scale scale, final StorageType storageType)
106 throws ValueRuntimeException
107 {
108 Throw.whenNull(values, "DoubleVectorData.instantiate: double[] values is null");
109 Throw.whenNull(scale, "DoubleVectorData.instantiate: scale is null");
110 Throw.whenNull(storageType, "DoubleVectorData.instantiate: storageType is null");
111 Throw.when(values.size() == 0, ValueRuntimeException.class, "DoubleVectorData.instantiate: values.size() == 0");
112 Throw.when(values.parallelStream().filter(d -> d == null).count() > 0, NullPointerException.class,
113 "values contains one or more null values");
114
115 switch (storageType)
116 {
117 case DENSE:
118 {
119 double[] valuesSI;
120 if (values.size() > PARALLEL_THRESHOLD)
121 {
122 if (scale.isBaseSIScale())
123 {
124 valuesSI = values.parallelStream().mapToDouble(d -> d).toArray();
125 }
126 else
127 {
128 valuesSI = values.parallelStream().mapToDouble(d -> scale.toStandardUnit(d)).toArray();
129 }
130 }
131 else
132 {
133 if (scale.isBaseSIScale())
134 {
135 valuesSI = values.stream().mapToDouble(d -> d).toArray();
136 }
137 else
138 {
139 valuesSI = values.stream().mapToDouble(d -> scale.toStandardUnit(d)).toArray();
140 }
141 }
142 return new DoubleVectorDataDense(valuesSI);
143 }
144
145 case SPARSE:
146 {
147 int nonZeroCount;
148 if (values.size() > PARALLEL_THRESHOLD)
149 {
150 if (scale.isBaseSIScale())
151 {
152 nonZeroCount = (int) values.parallelStream().filter(d -> d != 0d).count();
153 }
154 else
155 {
156 nonZeroCount = (int) values.parallelStream().filter(d -> scale.toStandardUnit(d) != 0d).count();
157 }
158 }
159 else
160 {
161 if (scale.isBaseSIScale())
162 {
163 nonZeroCount = (int) values.stream().filter(d -> d != 0d).count();
164 }
165 else
166 {
167 nonZeroCount = values.size()
168 - (int) values.parallelStream().filter(d -> scale.toStandardUnit(d) == 0d).count();
169 }
170 }
171 int[] indices = new int[nonZeroCount];
172 double[] valuesSI = new double[nonZeroCount];
173
174 int index = 0;
175 for (int i = 0; i < values.size(); i++)
176 {
177 double d = scale.toStandardUnit(values.get(i));
178 if (d != 0.0)
179 {
180 indices[index] = i;
181 valuesSI[index] = d;
182 index++;
183 }
184 }
185 return new DoubleVectorDataSparse(valuesSI, indices, values.size());
186 }
187
188 default:
189 throw new ValueRuntimeException("Unknown storage type in DoubleVectorData.instantiate: " + storageType);
190 }
191 }
192
193
194
195
196
197
198
199
200
201
202 public static <U extends Unit<U>, S extends DoubleScalarInterface<U, S>> DoubleVectorData instantiate(final S[] values,
203 final StorageType storageType) throws ValueRuntimeException
204 {
205 Throw.whenNull(values, "DoubleVectorData.instantiate: double[] values is null");
206 Throw.whenNull(storageType, "DoubleVectorData.instantiate: storageType is null");
207 Throw.when(values.length == 0, ValueRuntimeException.class,
208 "DoubleVectorData.instantiate: DoubleScalar[] values wrong: values.length == 0");
209 for (S s : values)
210 {
211 Throw.whenNull(s, "null value in values");
212 }
213
214 switch (storageType)
215 {
216 case DENSE:
217 {
218 double[] valuesSI;
219 if (values.length > PARALLEL_THRESHOLD)
220 {
221 valuesSI = Arrays.stream(values).parallel().mapToDouble(s -> s.getSI()).toArray();
222 }
223 else
224 {
225 valuesSI = Arrays.stream(values).mapToDouble(s -> s.getSI()).toArray();
226 }
227 return new DoubleVectorDataDense(valuesSI);
228 }
229
230 case SPARSE:
231 {
232 int nonZeroCount;
233 if (values.length > PARALLEL_THRESHOLD)
234 {
235 nonZeroCount = (int) Arrays.stream(values).parallel().filter(s -> s.getSI() != 0).count();
236 }
237 else
238 {
239 nonZeroCount = (int) Arrays.stream(values).filter(s -> s.getSI() != 0.0).count();
240 }
241 int[] indices = new int[nonZeroCount];
242 double[] valuesSI = new double[nonZeroCount];
243
244 int index = 0;
245 for (int i = 0; i < values.length; i++)
246 {
247 double d = values[i].getSI();
248 if (d != 0.0)
249 {
250 indices[index] = i;
251 valuesSI[index] = d;
252 index++;
253 }
254 }
255 return new DoubleVectorDataSparse(valuesSI, indices, values.length);
256 }
257
258 default:
259 throw new ValueRuntimeException("Unknown storage type in DoubleVectorData.instantiate: " + storageType);
260 }
261 }
262
263
264
265
266
267
268
269
270
271
272 public static <U extends Unit<U>, S extends DoubleScalarInterface<U, S>> DoubleVectorData instantiateList(
273 final List<S> valueList, final StorageType storageType) throws ValueRuntimeException
274 {
275 Throw.whenNull(valueList, "DoubleVectorData.instantiate: valueList is null");
276 Throw.whenNull(storageType, "DoubleVectorData.instantiate: storageType is null");
277 Throw.when(valueList.size() == 0, ValueRuntimeException.class, "DoubleVectorData.instantiate: valueList.size() == 0");
278 for (S s : valueList)
279 {
280 Throw.whenNull(s, "null value in valueList");
281 }
282
283 switch (storageType)
284 {
285 case DENSE:
286 {
287 double[] valuesSI;
288 if (valueList.size() > PARALLEL_THRESHOLD)
289 {
290 valuesSI = valueList.stream().parallel().mapToDouble(s -> s.getSI()).toArray();
291 }
292 else
293 {
294 valuesSI = valueList.stream().mapToDouble(s -> s.getSI()).toArray();
295 }
296 return new DoubleVectorDataDense(valuesSI);
297 }
298
299 case SPARSE:
300 {
301 int nonZeroCount = (int) valueList.parallelStream().filter(s -> s.getSI() != 0.0).count();
302 int[] indices = new int[nonZeroCount];
303 double[] valuesSI = new double[nonZeroCount];
304
305 int index = 0;
306 for (int i = 0; i < valueList.size(); i++)
307 {
308 double d = valueList.get(i).getSI();
309 if (d != 0.0)
310 {
311 indices[index] = i;
312 valuesSI[index] = d;
313 index++;
314 }
315 }
316 return new DoubleVectorDataSparse(valuesSI, indices, valueList.size());
317 }
318
319 default:
320 throw new ValueRuntimeException("Unknown storage type in DoubleVectorData.instantiate: " + storageType);
321 }
322 }
323
324
325
326
327
328
329
330
331
332
333 public static DoubleVectorData instantiate(final SortedMap<Integer, Double> valueMap, final int length, final Scale scale,
334 final StorageType storageType) throws ValueRuntimeException
335 {
336 Throw.whenNull(valueMap, "DoubleVectorData.instantiate: values is null");
337 Throw.when(length < 1, ValueRuntimeException.class, "Length must be > 0");
338 Throw.whenNull(scale, "DoubleVectorData.instantiate: scale is null");
339 Throw.whenNull(storageType, "DoubleVectorData.instantiate: storageType is null");
340 for (Integer key : valueMap.keySet())
341 {
342 Throw.when(key < 0 || key >= length, ValueRuntimeException.class, "Key in values out of range");
343 }
344
345 switch (storageType)
346 {
347 case DENSE:
348 {
349 double[] valuesSI = new double[length];
350 if (scale.isBaseSIScale())
351 {
352 valueMap.entrySet().parallelStream().forEach(entry -> valuesSI[entry.getKey()] = entry.getValue());
353 }
354 else
355 {
356 Arrays.fill(valuesSI, scale.toStandardUnit(0.0));
357 valueMap.entrySet().parallelStream()
358 .forEach(entry -> valuesSI[entry.getKey()] = scale.toStandardUnit(entry.getValue()));
359 }
360 return new DoubleVectorDataDense(valuesSI);
361 }
362
363 case SPARSE:
364 {
365 int nonZeroCount;
366 if (scale.isBaseSIScale())
367 {
368 nonZeroCount = (int) valueMap.keySet().parallelStream().filter(d -> d != 0d).count();
369 }
370 else
371 {
372
373 nonZeroCount = length
374 - (int) valueMap.values().parallelStream().filter(d -> scale.toStandardUnit(d) == 0d).count();
375 }
376 int[] indices = new int[nonZeroCount];
377 double[] valuesSI = new double[nonZeroCount];
378 if (scale.isBaseSIScale())
379 {
380 int index = 0;
381 for (Integer key : valueMap.keySet())
382 {
383 double value = valueMap.get(key);
384 if (0.0 != value)
385 {
386 indices[index] = key;
387 valuesSI[index] = value;
388 index++;
389 }
390 }
391 }
392 else
393 {
394 Arrays.fill(valuesSI, scale.toStandardUnit(0.0));
395 int index = 0;
396 int lastKey = 0;
397 for (Integer key : valueMap.keySet())
398 {
399 for (int i = lastKey; i < key; i++)
400 {
401 indices[index++] = i;
402 }
403 lastKey = key;
404 double value = scale.toStandardUnit(valueMap.get(key));
405 if (0.0 != value)
406 {
407 indices[index] = key;
408 valuesSI[index] = value;
409 index++;
410 }
411 lastKey = key + 1;
412 }
413 while (index < indices.length)
414 {
415 indices[index++] = lastKey++;
416 }
417 }
418 return new DoubleVectorDataSparse(valuesSI, indices, length);
419 }
420
421 default:
422 throw new ValueRuntimeException("Unknown storage type in DoubleVectorData.instantiate: " + storageType);
423 }
424 }
425
426
427
428
429
430
431
432
433
434
435
436 public static <U extends Unit<U>, S extends DoubleScalarInterface<U, S>> DoubleVectorData instantiateMap(
437 final SortedMap<Integer, S> values, final int length, final StorageType storageType) throws ValueRuntimeException
438 {
439 Throw.whenNull(values, "DoubleVectorData.instantiate: values is null");
440 Throw.when(length < 1, ValueRuntimeException.class, "Length must be > 0");
441 Throw.whenNull(storageType, "DoubleVectorData.instantiate: storageType is null");
442 for (Entry<Integer, S> e : values.entrySet())
443 {
444 Throw.when(e.getKey() < 0 || e.getKey() >= length, ValueRuntimeException.class, "Key in values out of range");
445 Throw.whenNull(e.getValue(), "null value in map");
446 }
447
448 switch (storageType)
449 {
450 case DENSE:
451 {
452 double[] valuesSI = new double[length];
453 values.entrySet().parallelStream().forEach(entry -> valuesSI[entry.getKey()] = entry.getValue().getSI());
454 return new DoubleVectorDataDense(valuesSI);
455 }
456
457 case SPARSE:
458 {
459 int nonZeroCount = (int) values.values().parallelStream().filter(s -> s.getSI() != 0d).count();
460 int[] indices = new int[nonZeroCount];
461 double[] valuesSI = new double[nonZeroCount];
462 int index = 0;
463 for (Integer key : values.keySet())
464 {
465 double value = values.get(key).getSI();
466 if (0.0 != value)
467 {
468 indices[index] = key;
469 valuesSI[index] = value;
470 index++;
471 }
472 }
473 return new DoubleVectorDataSparse(valuesSI, indices, length);
474 }
475
476 default:
477 throw new ValueRuntimeException("Unknown storage type in DoubleVectorData.instantiate: " + storageType);
478 }
479 }
480
481
482
483
484
485
486
487
488
489 public abstract int size();
490
491
492
493
494
495 public abstract DoubleVectorDataDense toDense();
496
497
498
499
500
501 public abstract DoubleVectorDataSparse toSparse();
502
503
504
505
506
507
508 public abstract double getSI(int index);
509
510
511
512
513
514
515 public abstract void setSI(int index, double valueSI);
516
517
518
519
520
521 public final double zSum()
522 {
523 return Arrays.stream(this.vectorSI).parallel().sum();
524 }
525
526
527
528
529
530 public abstract double[] getDenseVectorSI();
531
532
533
534
535
536
537 protected void checkSizes(final DoubleVectorData other) throws ValueRuntimeException
538 {
539 if (this.size() != other.size())
540 {
541 throw new ValueRuntimeException("Two data objects used in a DoubleVector operation do not have the same size");
542 }
543 }
544
545
546
547
548
549
550
551
552
553
554 public abstract DoubleVectorData assign(DoubleFunction doubleFunction);
555
556
557
558
559
560
561
562
563 abstract DoubleVectorDatable/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData assign(DoubleFunction2 doubleFunction2, DoubleVectorData right) throws ValueRuntimeException;
564
565
566
567
568
569
570
571
572 public abstract DoubleVectorData/../../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData plus(DoubleVectorData right) throws ValueRuntimeException;
573
574
575
576
577
578
579
580 public final DoubleVectorData/DoubleVectorData.html#DoubleVectorData">DoubleVectorData incrementBy(final DoubleVectorData right) throws ValueRuntimeException
581 {
582 return assign(new DoubleFunction2()
583 {
584 @Override
585 public double apply(final double leftValue, final double rightValue)
586 {
587 return leftValue + rightValue;
588 }
589 }, right);
590 }
591
592
593
594
595
596
597
598
599 public abstract DoubleVectorData../../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData minus(DoubleVectorData right) throws ValueRuntimeException;
600
601
602
603
604
605
606
607 public final DoubleVectorData/DoubleVectorData.html#DoubleVectorData">DoubleVectorData decrementBy(final DoubleVectorData right) throws ValueRuntimeException
608 {
609 return assign(new DoubleFunction2()
610 {
611 @Override
612 public double apply(final double leftValue, final double rightValue)
613 {
614 return leftValue - rightValue;
615 }
616 }, right);
617 }
618
619
620
621
622
623
624
625
626 public abstract DoubleVectorData../../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData times(DoubleVectorData right) throws ValueRuntimeException;
627
628
629
630
631
632
633
634
635 public final DoubleVectorDataa/DoubleVectorData.html#DoubleVectorData">DoubleVectorData multiplyBy(final DoubleVectorData right) throws ValueRuntimeException
636 {
637 assign(new DoubleFunction2()
638 {
639 @Override
640 public double apply(final double leftValue, final double rightValue)
641 {
642 return leftValue * rightValue;
643 }
644 }, right);
645 return this;
646 }
647
648
649
650
651
652 public final void multiplyBy(final double valueSI)
653 {
654 assign(new DoubleFunction()
655 {
656 @Override
657 public double apply(final double value)
658 {
659 return value * valueSI;
660 }
661 });
662 }
663
664
665
666
667
668
669
670
671 public abstract DoubleVectorData./../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData divide(DoubleVectorData right) throws ValueRuntimeException;
672
673
674
675
676
677
678
679
680 public final DoubleVectorDataata/DoubleVectorData.html#DoubleVectorData">DoubleVectorData divideBy(final DoubleVectorData right) throws ValueRuntimeException
681 {
682 return assign(new DoubleFunction2()
683 {
684 @Override
685 public double apply(final double leftValue, final double rightValue)
686 {
687 return leftValue / rightValue;
688 }
689 }, right);
690 }
691
692
693
694
695
696 public final void divideBy(final double valueSI)
697 {
698 assign(new DoubleFunction()
699 {
700 @Override
701 public double apply(final double value)
702 {
703 return value / valueSI;
704 }
705 });
706 }
707
708
709
710
711
712
713 @Override
714 public int hashCode()
715 {
716 final int prime = 31;
717 int result = 1;
718 result = prime * result + this.size();
719 for (int index = 0; index < this.size(); index++)
720 {
721 long bits = Double.doubleToLongBits(getSI(index));
722 result = 31 * result + (int) (bits ^ (bits >>> 32));
723 }
724 return result;
725 }
726
727
728
729
730
731
732
733 protected boolean compareDenseVectorWithSparseVector(final DoubleVectorDataDense dm, final DoubleVectorDataSparse sm)
734 {
735 for (int index = 0; index < dm.size(); index++)
736 {
737 if (dm.getSI(index) != sm.getSI(index))
738 {
739 return false;
740 }
741 }
742 return true;
743 }
744
745
746 @Override
747 @SuppressWarnings("checkstyle:needbraces")
748 public boolean equals(final Object obj)
749 {
750 if (this == obj)
751 return true;
752 if (obj == null)
753 return false;
754 if (!(obj instanceof DoubleVectorData))
755 return false;
756 DoubleVectorData../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData other = (DoubleVectorData) obj;
757 if (this.size() != other.size())
758 return false;
759 if (other instanceof DoubleVectorDataSparse && this instanceof DoubleVectorDataDense)
760 {
761 return compareDenseVectorWithSparseVector((DoubleVectorDataDense) this, (DoubleVectorDataSparse) other);
762 }
763 else if (other instanceof DoubleVectorDataDense && this instanceof DoubleVectorDataSparse)
764 {
765 return compareDenseVectorWithSparseVector((DoubleVectorDataDense) other, (DoubleVectorDataSparse) this);
766 }
767
768 return Arrays.equals(this.vectorSI, other.vectorSI);
769 }
770
771
772 @Override
773 public String toString()
774 {
775 return "DoubleVectorData [storageType=" + getStorageType() + ", vectorSI=" + Arrays.toString(this.vectorSI) + "]";
776 }
777
778 }