1 package org.djunits.vecmat.dn;
2
3 import java.lang.reflect.Array;
4 import java.util.Arrays;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Objects;
8
9 import org.djunits.quantity.SIQuantity;
10 import org.djunits.quantity.def.Quantity;
11 import org.djunits.unit.Unit;
12 import org.djunits.unit.si.SIUnit;
13 import org.djunits.util.ArrayMath;
14 import org.djunits.vecmat.def.Vector;
15 import org.djunits.vecmat.storage.DataGridSi;
16 import org.djunits.vecmat.storage.DenseDoubleDataSi;
17 import org.djutils.exceptions.Throw;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public abstract class VectorN<Q extends Quantity<Q>, V extends VectorN<Q, V, SI, H, VT>,
33 SI extends VectorN<SIQuantity, SI, ?, ?, ?>, H extends VectorN<?, ?, ?, ?, ?>, VT extends VectorN<Q, VT, ?, ?, V>>
34 extends Vector<Q, V, SI, H, VT>
35 {
36
37 private static final long serialVersionUID = 600L;
38
39
40 @SuppressWarnings("checkstyle:visibilitymodifier")
41 protected final DataGridSi<?> dataSi;
42
43
44
45
46
47
48
49 protected VectorN(final DataGridSi<?> dataSi, final Unit<?, Q> displayUnit)
50 {
51 super(displayUnit);
52 Throw.whenNull(dataSi, "dataSi");
53 this.dataSi = dataSi;
54 }
55
56 @Override
57 public Iterator<Q> iterator()
58 {
59 final double[] si = this.dataSi.unsafeSiArray();
60 final Unit<?, Q> frozenDisplayUnit = getDisplayUnit();
61 return Arrays.stream(si).mapToObj(v -> frozenDisplayUnit.ofSi(v).setDisplayUnit(frozenDisplayUnit)).iterator();
62 }
63
64 @Override
65 public Q[] getScalarArray()
66 {
67 final double[] siArray = this.dataSi.unsafeSiArray();
68 final Unit<?, Q> frozenDisplayUnit = getDisplayUnit();
69 final Q first = frozenDisplayUnit.ofSi(siArray[0]).setDisplayUnit(frozenDisplayUnit);
70 final Class<?> qClass = first.getClass();
71 @SuppressWarnings("unchecked")
72 final Q[] out = (Q[]) Array.newInstance(qClass, siArray.length);
73 out[0] = first;
74 for (int i = 1; i < siArray.length; i++)
75 {
76 out[i] = frozenDisplayUnit.ofSi(siArray[i]).setDisplayUnit(frozenDisplayUnit);
77 }
78 return out;
79 }
80
81 @Override
82 public Q normL1()
83 {
84 double n = 0.0;
85 for (var d : unsafeSiArray())
86 {
87 n += Math.abs(d);
88 }
89 return getDisplayUnit().ofSi(n).setDisplayUnit(getDisplayUnit());
90 }
91
92 @Override
93 public Q normL2()
94 {
95 double n = 0.0;
96 for (var d : unsafeSiArray())
97 {
98 n += d * d;
99 }
100 return getDisplayUnit().ofSi(Math.sqrt(n)).setDisplayUnit(getDisplayUnit());
101 }
102
103 @Override
104 public Q normLp(final int p)
105 {
106 double n = 0.0;
107 for (var d : unsafeSiArray())
108 {
109 n += Math.pow(Math.abs(d), p);
110 }
111 return getDisplayUnit().ofSi(Math.pow(n, 1.0 / p)).setDisplayUnit(getDisplayUnit());
112 }
113
114 @Override
115 public Q normLinf()
116 {
117 double max = Double.NEGATIVE_INFINITY;
118 for (var d : unsafeSiArray())
119 {
120 max = Math.max(Math.abs(d), max);
121 }
122 return getDisplayUnit().ofSi(max).setDisplayUnit(getDisplayUnit());
123 }
124
125 @Override
126 public int rows()
127 {
128 return this.dataSi.rows();
129 }
130
131 @Override
132 public int cols()
133 {
134 return this.dataSi.cols();
135 }
136
137 @Override
138 public double[] getSiArray()
139 {
140 return this.dataSi.getSiArray();
141 }
142
143 @Override
144 public double[] unsafeSiArray()
145 {
146 return this.dataSi.unsafeSiArray();
147 }
148
149 @Override
150 public int nonZeroCount()
151 {
152 return this.dataSi.nonZeroCount();
153 }
154
155 @Override
156 public int hashCode()
157 {
158 return Objects.hash(this.dataSi, rows(), cols());
159 }
160
161 @SuppressWarnings("checkstyle:needbraces")
162 @Override
163 public boolean equals(final Object obj)
164 {
165 if (this == obj)
166 return true;
167 if (obj == null)
168 return false;
169 if (getClass() != obj.getClass())
170 return false;
171 VectorN<?, ?, ?, ?, ?> other = (VectorN<?, ?, ?, ?, ?>) obj;
172 return Objects.equals(this.dataSi, other.dataSi) && rows() == other.rows() && cols() == other.cols();
173 }
174
175
176
177
178
179
180
181
182
183
184
185 public static class Col<Q extends Quantity<Q>> extends
186 VectorN<Q, Col<Q>, VectorN.Col<SIQuantity>, VectorN.Col<?>, VectorN.Row<Q>> implements Vector.Col<VectorN.Col<Q>, Q>
187 {
188
189 private static final long serialVersionUID = 600L;
190
191
192
193
194
195
196
197
198 public Col(final DataGridSi<?> dataSi, final Unit<?, Q> displayUnit)
199 {
200 super(dataSi, displayUnit);
201 Throw.when(dataSi.cols() != 1, IllegalArgumentException.class,
202 "Column vector initialized with more than one column");
203 }
204
205 @Override
206 public VectorN.Col<Q> instantiateSi(final double[] data)
207 {
208 return new VectorN.Col<Q>(this.dataSi.instantiateNew(data), getDisplayUnit().getBaseUnit())
209 .setDisplayUnit(getDisplayUnit());
210 }
211
212 @Override
213 public Col<SIQuantity> instantiateSi(final double[] siNew, final SIUnit siUnit)
214 {
215 return new VectorN.Col<SIQuantity>(this.dataSi.instantiateNew(siNew), siUnit);
216 }
217
218 @Override
219 public boolean isColumnVector()
220 {
221 return true;
222 }
223
224 @Override
225 public int size()
226 {
227 return this.dataSi.rows();
228 }
229
230 @Override
231 public double si(final int index) throws IndexOutOfBoundsException
232 {
233 return this.dataSi.get(index, 0);
234 }
235
236 @Override
237 public VectorN.Row<Q> transpose()
238 {
239 var newSi = this.dataSi.instantiateNew(unsafeSiArray(), cols(), rows());
240 return new VectorN.Row<Q>(newSi, getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
241 }
242
243 @Override
244 public VectorN.Col<SIQuantity> invertEntries()
245 {
246 SIUnit siUnit = getDisplayUnit().siUnit().invert();
247 return new VectorN.Col<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.reciprocal(unsafeSiArray())), siUnit);
248 }
249
250 @Override
251 public VectorN.Col<SIQuantity> multiplyEntries(final VectorN.Col<?> other)
252 {
253 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
254 return new VectorN.Col<SIQuantity>(
255 this.dataSi.instantiateNew(ArrayMath.multiply(unsafeSiArray(), other.unsafeSiArray())), siUnit);
256 }
257
258 @Override
259 public VectorN.Col<SIQuantity> divideEntries(final VectorN.Col<?> other)
260 {
261 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
262 return new VectorN.Col<SIQuantity>(
263 this.dataSi.instantiateNew(ArrayMath.divide(unsafeSiArray(), other.unsafeSiArray())), siUnit);
264 }
265
266 @Override
267 public VectorN.Col<SIQuantity> multiplyEntries(final Quantity<?> quantity)
268 {
269 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
270 return new VectorN.Col<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.scaleBy(unsafeSiArray(), quantity.si())),
271 siUnit);
272 }
273
274
275
276
277
278
279
280
281
282
283 public static <Q extends Quantity<Q>> VectorN.Col<Q> of(final double[] dataInUnit, final Unit<?, Q> unit)
284 {
285 double[] dataSi = new double[dataInUnit.length];
286 for (int i = 0; i < dataInUnit.length; i++)
287 {
288 dataSi[i] = unit.toBaseValue(dataInUnit[i]);
289 }
290 return ofSi(dataSi, unit);
291 }
292
293
294
295
296
297
298
299
300 public static <Q extends Quantity<Q>> VectorN.Col<Q> ofSi(final double[] dataSi, final Unit<?, Q> displayUnit)
301 {
302 return new VectorN.Col<Q>(new DenseDoubleDataSi(dataSi.clone(), dataSi.length, 1), displayUnit.getBaseUnit())
303 .setDisplayUnit(displayUnit);
304 }
305
306
307
308
309
310
311
312
313
314 public static <Q extends Quantity<Q>> VectorN.Col<Q> of(final Q[] data)
315 {
316 Throw.when(data.length < 1, IllegalArgumentException.class, "data array length < 1");
317 double[] dataSi = new double[data.length];
318 for (int i = 0; i < data.length; i++)
319 {
320 dataSi[i] = data[i].si();
321 }
322 return ofSi(dataSi, data[0].getDisplayUnit());
323 }
324
325
326
327
328
329
330
331
332
333
334 public static <Q extends Quantity<Q>> VectorN.Col<Q> ofSi(final DataGridSi<?> dataSi, final Unit<?, Q> displayUnit)
335 {
336 return new VectorN.Col<Q>(dataSi, displayUnit.getBaseUnit()).setDisplayUnit(displayUnit);
337 }
338
339
340
341
342
343
344
345
346
347 public static <Q extends Quantity<Q>> VectorN.Col<Q> of(final List<Q> data)
348 {
349 Throw.when(data.size() < 1, IllegalArgumentException.class, "data.size < 1");
350 double[] dataSi = new double[data.size()];
351 for (int i = 0; i < data.size(); i++)
352 {
353 dataSi[i] = data.get(i).si();
354 }
355 return ofSi(dataSi, data.get(0).getDisplayUnit());
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369 public <TQ extends Quantity<TQ>> VectorN.Col<TQ> as(final Unit<?, TQ> targetUnit) throws IllegalArgumentException
370 {
371 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
372 "Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
373 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
374 return new VectorN.Col<TQ>(this.dataSi, targetUnit);
375 }
376
377 }
378
379
380
381
382
383
384
385
386
387
388
389 public static class Row<Q extends Quantity<Q>> extends
390 VectorN<Q, Row<Q>, VectorN.Row<SIQuantity>, VectorN.Row<?>, VectorN.Col<Q>> implements Vector.Row<VectorN.Row<Q>, Q>
391 {
392
393 private static final long serialVersionUID = 600L;
394
395
396
397
398
399
400
401
402 public Row(final DataGridSi<?> dataSi, final Unit<?, Q> displayUnit)
403 {
404 super(dataSi, displayUnit);
405 Throw.when(dataSi.rows() != 1, IllegalArgumentException.class, "Row vector initialized with more than one row");
406 }
407
408 @Override
409 public boolean isColumnVector()
410 {
411 return false;
412 }
413
414 @Override
415 public VectorN.Row<Q> instantiateSi(final double[] data)
416 {
417 return new VectorN.Row<>(this.dataSi.instantiateNew(data), getDisplayUnit());
418 }
419
420 @Override
421 public VectorN.Row<SIQuantity> instantiateSi(final double[] siNew, final SIUnit siUnit)
422 {
423 return new VectorN.Row<SIQuantity>(this.dataSi.instantiateNew(siNew), siUnit);
424 }
425
426 @Override
427 public int size()
428 {
429 return this.dataSi.cols();
430 }
431
432 @Override
433 public double si(final int index) throws IndexOutOfBoundsException
434 {
435 return this.dataSi.get(0, index);
436 }
437
438 @Override
439 public VectorN.Col<Q> transpose()
440 {
441 var newSi = this.dataSi.instantiateNew(unsafeSiArray(), cols(), rows());
442 return new VectorN.Col<Q>(newSi, getDisplayUnit());
443 }
444
445 @Override
446 public VectorN.Row<SIQuantity> invertEntries()
447 {
448 SIUnit siUnit = getDisplayUnit().siUnit().invert();
449 return new VectorN.Row<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.reciprocal(unsafeSiArray())), siUnit);
450 }
451
452 @Override
453 public VectorN.Row<SIQuantity> multiplyEntries(final VectorN.Row<?> other)
454 {
455 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
456 return new VectorN.Row<SIQuantity>(
457 this.dataSi.instantiateNew(ArrayMath.multiply(unsafeSiArray(), other.unsafeSiArray())), siUnit);
458 }
459
460 @Override
461 public VectorN.Row<SIQuantity> divideEntries(final VectorN.Row<?> other)
462 {
463 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
464 return new VectorN.Row<SIQuantity>(
465 this.dataSi.instantiateNew(ArrayMath.divide(unsafeSiArray(), other.unsafeSiArray())), siUnit);
466 }
467
468 @Override
469 public VectorN.Row<SIQuantity> multiplyEntries(final Quantity<?> quantity)
470 {
471 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
472 return new VectorN.Row<SIQuantity>(this.dataSi.instantiateNew(ArrayMath.scaleBy(unsafeSiArray(), quantity.si())),
473 siUnit);
474 }
475
476
477
478
479
480
481
482
483
484
485 public static <Q extends Quantity<Q>> VectorN.Row<Q> of(final double[] dataInUnit, final Unit<?, Q> unit)
486 {
487 double[] dataSi = new double[dataInUnit.length];
488 for (int i = 0; i < dataInUnit.length; i++)
489 {
490 dataSi[i] = unit.toBaseValue(dataInUnit[i]);
491 }
492 return ofSi(dataSi, unit);
493 }
494
495
496
497
498
499
500
501
502 public static <Q extends Quantity<Q>> VectorN.Row<Q> ofSi(final double[] dataSi, final Unit<?, Q> displayUnit)
503 {
504 return new VectorN.Row<Q>(new DenseDoubleDataSi(dataSi.clone(), 1, dataSi.length), displayUnit);
505 }
506
507
508
509
510
511
512
513
514
515 public static <Q extends Quantity<Q>> VectorN.Row<Q> of(final Q[] data)
516 {
517 Throw.when(data.length < 1, IllegalArgumentException.class, "data array length < 1");
518 double[] dataSi = new double[data.length];
519 for (int i = 0; i < data.length; i++)
520 {
521 dataSi[i] = data[i].si();
522 }
523 return ofSi(dataSi, data[0].getDisplayUnit());
524 }
525
526
527
528
529
530
531
532
533
534
535 public static <Q extends Quantity<Q>> VectorN.Row<Q> ofSi(final DataGridSi<?> dataSi, final Unit<?, Q> displayUnit)
536 {
537 return new VectorN.Row<Q>(dataSi, displayUnit);
538 }
539
540
541
542
543
544
545
546
547
548 public static <Q extends Quantity<Q>> VectorN.Row<Q> of(final List<Q> data)
549 {
550 Throw.when(data.size() < 1, IllegalArgumentException.class, "data.size < 1");
551 double[] dataSi = new double[data.size()];
552 for (int i = 0; i < data.size(); i++)
553 {
554 dataSi[i] = data.get(i).si();
555 }
556 return ofSi(dataSi, data.get(0).getDisplayUnit());
557 }
558
559
560
561
562
563
564
565
566
567
568
569
570 public <TQ extends Quantity<TQ>> VectorN.Row<TQ> as(final Unit<?, TQ> targetUnit) throws IllegalArgumentException
571 {
572 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
573 "Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
574 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
575 return new VectorN.Row<TQ>(this.dataSi, targetUnit);
576 }
577
578 }
579
580 }