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 * Stores the data for a DoubleVector and carries out basic operations.
22 * <p>
23 * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
24 * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
25 * </p>
26 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
27 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
28 */
29 public abstract class DoubleVectorData extends AbstractStorage<DoubleVectorData> implements Serializable
30 {
31 /** */
32 private static final long serialVersionUID = 1L;
33
34 /** The internal storage of the Vector; can be sparse or dense. */
35 @SuppressWarnings("checkstyle:visibilitymodifier")
36 protected double[] vectorSI;
37
38 /** Threshold to do parallel execution. */
39 protected static final int PARALLEL_THRESHOLD = 1000;
40
41 /**
42 * Construct a new DoubleVectorData object.
43 * @param storageType StorageType; the data type.
44 */
45 DoubleVectorData(final StorageType storageType)
46 {
47 super(storageType);
48 }
49
50 /* ============================================================================================ */
51 /* ====================================== INSTANTIATION ======================================= */
52 /* ============================================================================================ */
53
54 /**
55 * Instantiate a DoubleVectorData with the right data type.
56 * @param values double[]; the (SI) values to store
57 * @param scale Scale; the scale of the unit to use for conversion to SI
58 * @param storageType StorageType; the data type to use
59 * @return DoubleVectorData; the DoubleVectorData with the right data type
60 * @throws NullPointerException when values are null, or storageType is null
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 * Instantiate a DoubleVectorData with the right data type.
96 * @param values List<Double>; the values to store
97 * @param scale Scale; the scale of the unit to use for conversion to SI
98 * @param storageType StorageType; the data type to use
99 * @return DoubleVectorData; the DoubleVectorData with the right data type
100 * @throws NullPointerException when list is null, or storageType is null
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 // Counting non zeros could be done in parallel; but filling the arrays has to be done sequentially
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 * Instantiate a DoubleVectorData with the right data type.
190 * @param values S[]; the values to store
191 * @param storageType StorageType; the data type to use
192 * @return DoubleVectorData; the DoubleVectorData with the right data type
193 * @throws NullPointerException when values is null, or storageType is null
194 * @param <U> the unit type
195 * @param <S> the corresponding scalar type
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 // Counting non zeros could be done in parallel; but filling the arrays has to be done sequentially
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 * Instantiate a DoubleVectorData with the right data type.
258 * @param valueList List<S>; the values to store
259 * @param storageType StorageType; the data type to use
260 * @return DoubleVectorData; the DoubleVectorData with the right data type
261 * @throws NullPointerException when values is null, or storageType is null
262 * @param <U> the unit type
263 * @param <S> the corresponding scalar type
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 // Counting non zeros could be done in parallel; but filling the arrays has to be done sequentially
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 * Instantiate a DoubleVectorData with the right data type.
318 * @param valueMap SortedMap<Integer,Double>; the DoubleScalar values to store
319 * @param length int; the length of the vector to pad with 0 after last entry in map
320 * @param scale Scale; the scale of the unit to use for conversion to SI
321 * @param storageType StorageType; the data type to use
322 * @return DoubleVectorData; the DoubleVectorData with the right data type
323 * @throws ValueRuntimeException when length < 0
324 * @throws NullPointerException when values is null, or storageType is null
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 // Much harder, and the result is unlikely to be very sparse
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 * Instantiate a DoubleVectorData with the right data type.
421 * @param values SortedMap<Integer,S>; the DoubleScalar values to store
422 * @param length int; the length of the vector to pad with 0 after last entry in map
423 * @param storageType StorageType; the data type to use
424 * @return DoubleVectorData; the DoubleVectorData with the right data type
425 * @throws NullPointerException when values is null, or storageType is null
426 * @param <U> the unit
427 * @param <S> the corresponding scalar type
428 * @throws ValueRuntimeException when length < 0
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 /* ==================================== UTILITY FUNCTIONS ===================================== */
477 /* ============================================================================================ */
478
479 /**
480 * Retrieve the size of the vector.
481 * @return int; the size of the vector
482 */
483 public abstract int size();
484
485 /**
486 * Return the densely stored equivalent of this data.
487 * @return DoubleVectorDataDense; the dense transformation of this data
488 */
489 public abstract DoubleVectorDataDense toDense();
490
491 /**
492 * Return the sparsely stored equivalent of this data.
493 * @return DoubleVectorDataSparse; the sparse transformation of this data
494 */
495 public abstract DoubleVectorDataSparse toSparse();
496
497 /**
498 * Retrieve the SI value of one element of this data.
499 * @param index int; the index to get the value for
500 * @return double; the value at the index
501 */
502 public abstract double getSI(int index);
503
504 /**
505 * Sets a value at the index in the vector.
506 * @param index int; the index to set the value for
507 * @param valueSI double; the value at the index
508 */
509 public abstract void setSI(int index, double valueSI);
510
511 /**
512 * Compute and return the sum of all values.
513 * @return double; the sum of the values of all cells
514 */
515 public final double zSum()
516 {
517 return Arrays.stream(this.vectorSI).parallel().sum();
518 }
519
520 /**
521 * Create and return a dense copy of the data.
522 * @return double[]; a safe copy of VectorSI
523 */
524 public abstract double[] getDenseVectorSI();
525
526 /**
527 * Check the sizes of this data object and the other data object.
528 * @param other DoubleVectorData; the other data object
529 * @throws ValueRuntimeException if vectors have different lengths
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 /* ================================== CALCULATION FUNCTIONS =================================== */
541 /* ============================================================================================ */
542
543 /**
544 * Apply an operation to each cell.
545 * @param doubleFunction DoubleFunction; the operation to apply
546 * @return DoubleVectorData; this (modified) double vector data object
547 */
548 public abstract DoubleVectorData assign(DoubleFunction doubleFunction);
549
550 /**
551 * Apply a binary operation on a cell by cell basis.
552 * @param doubleFunction2 DoubleFunction2; the binary operation to apply
553 * @param right DoubleVectorData; the right operand for the binary operation
554 * @return DoubleVectorData; this (modified) double vector data object
555 * @throws ValueRuntimeException when the sizes of the vectors do not match
556 */
557 abstract DoubleVectorDatable/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData assign(DoubleFunction2 doubleFunction2, DoubleVectorData right) throws ValueRuntimeException;
558
559 /**
560 * Add two vectors on a cell-by-cell basis. If both vectors are sparse, a sparse vector is returned, otherwise a dense
561 * vector is returned. Neither of the two objects is changed.
562 * @param right DoubleVectorData; the other data object to add
563 * @return DoubleVectorData; the sum of this data object and the other data object as a new data object
564 * @throws ValueRuntimeException if vectors have different lengths
565 */
566 public abstract DoubleVectorData/../../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData plus(DoubleVectorData right) throws ValueRuntimeException;
567
568 /**
569 * Add a vector to this vector on a cell-by-cell basis. The type of vector (sparse, dense) stays the same.
570 * @param right DoubleVectorData; the other data object to add
571 * @return DoubleVectorData; this modified double vector data object
572 * @throws ValueRuntimeException if vectors have different lengths
573 */
574 public final DoubleVectorData/DoubleVectorData.html#DoubleVectorData">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 * Subtract two vectors on a cell-by-cell basis. If both vectors are sparse, a sparse vector is returned, otherwise a dense
588 * vector is returned. Neither of the two objects is changed.
589 * @param right DoubleVectorData; the other data object to subtract
590 * @return DoubleVectorData; the difference of this data object and the other data object as a new data object
591 * @throws ValueRuntimeException if vectors have different lengths
592 */
593 public abstract DoubleVectorData../../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData minus(DoubleVectorData right) throws ValueRuntimeException;
594
595 /**
596 * Subtract a vector from this vector on a cell-by-cell basis. The type of vector (sparse, dense) stays the same.
597 * @param right DoubleVectorData; the other data object to subtract
598 * @return DoubleVectorData; this modified double vector data object
599 * @throws ValueRuntimeException if vectors have different lengths
600 */
601 public final DoubleVectorData/DoubleVectorData.html#DoubleVectorData">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 * Multiply two vectors on a cell-by-cell basis. If both vectors are dense, a dense vector is returned, otherwise a sparse
615 * vector is returned.
616 * @param right DoubleVectorData; the other data object to multiply with
617 * @return DoubleVectorData; a new double vector data store holding the result of the multiplications
618 * @throws ValueRuntimeException if vectors have different lengths
619 */
620 public abstract DoubleVectorData../../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData times(DoubleVectorData right) throws ValueRuntimeException;
621
622 /**
623 * Multiply a vector with the values of another vector on a cell-by-cell basis. The type of vector (sparse, dense) stays the
624 * same.
625 * @param right DoubleVectorData; the other data object to multiply with
626 * @return DoubleVectordata; this modified double vector data store
627 * @throws ValueRuntimeException if vectors have different lengths
628 */
629 public final DoubleVectorDataa/DoubleVectorData.html#DoubleVectorData">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 * Multiply the values of this vector with a number on a cell-by-cell basis.
644 * @param valueSI double; the value to multiply with
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 * Divide two vectors on a cell-by-cell basis. If this vector is sparse and <code>right</code> is dense, a sparse vector is
660 * returned, otherwise a dense vector is returned.
661 * @param right DoubleVectorData; the other data object to divide by
662 * @return DoubleVectorData; the ratios of the values of this data object and the other data object
663 * @throws ValueRuntimeException if vectors have different lengths
664 */
665 public abstract DoubleVectorData./../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">DoubleVectorData divide(DoubleVectorData right) throws ValueRuntimeException;
666
667 /**
668 * Divide the values of a vector by the values of another vector on a cell-by-cell basis. The type of vector (sparse, dense)
669 * stays the same.
670 * @param right DoubleVectorData; the other data object to divide by
671 * @return DoubleVectorData; this modified double vector data store
672 * @throws ValueRuntimeException if vectors have different lengths
673 */
674 public final DoubleVectorDataata/DoubleVectorData.html#DoubleVectorData">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 * Divide the values of this vector by a number on a cell-by-cell basis.
688 * @param valueSI double; the value to multiply with
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 /* =============================== EQUALS, HASHCODE, TOSTRING ================================= */
704 /* ============================================================================================ */
705
706 /** {@inheritDoc} */
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 * Compare contents of a dense and a sparse vector.
723 * @param dm DoubleVectorDataDense; the dense vector
724 * @param sm DoubleVectorDataSparse; the sparse vector
725 * @return boolean; true if the contents are equal
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 /** {@inheritDoc} */
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../../../org/djunits/value/vdouble/vector/data/DoubleVectorData.html#DoubleVectorData">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 // Both are dense (both sparse is handled in DoubleVectorDataSparse class)
762 return Arrays.equals(this.vectorSI, other.vectorSI);
763 }
764
765 /** {@inheritDoc} */
766 @Override
767 public String toString()
768 {
769 return "DoubleVectorData [storageType=" + getStorageType() + ", vectorSI=" + Arrays.toString(this.vectorSI) + "]";
770 }
771
772 }