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