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