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