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.UnitInterface;
12 import org.djunits.unit.si.SIUnit;
13 import org.djunits.util.ArrayMath;
14 import org.djunits.vecmat.d1.Vector1;
15 import org.djunits.vecmat.d2.Vector2;
16 import org.djunits.vecmat.d3.Vector3;
17 import org.djunits.vecmat.def.Vector;
18 import org.djunits.vecmat.operations.VectorTransposable;
19 import org.djunits.vecmat.storage.DataGridSi;
20 import org.djunits.vecmat.storage.DenseDoubleDataSi;
21 import org.djutils.exceptions.Throw;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public abstract class VectorN<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>, V extends VectorN<Q, U, V, SI, H>,
37 SI extends VectorN<SIQuantity, SIUnit, SI, ?, ?>, H extends VectorN<?, ?, ?, ?, ?>> extends Vector<Q, U, V, SI, H>
38 {
39
40 private static final long serialVersionUID = 600L;
41
42
43 @SuppressWarnings("checkstyle:visibilitymodifier")
44 protected final DataGridSi<?> dataSi;
45
46
47
48
49
50
51
52 protected VectorN(final DataGridSi<?> dataSi, final U displayUnit)
53 {
54 super(displayUnit);
55 Throw.whenNull(dataSi, "dataSi");
56 this.dataSi = dataSi;
57 }
58
59 @Override
60 public Iterator<Q> iterator()
61 {
62 final double[] si = this.dataSi.getDataArray();
63 final U frozenDisplayUnit = getDisplayUnit();
64 return Arrays.stream(si).mapToObj(v -> frozenDisplayUnit.ofSi(v).setDisplayUnit(frozenDisplayUnit)).iterator();
65 }
66
67 @Override
68 public Q[] getScalarArray()
69 {
70 final double[] si = this.dataSi.getDataArray();
71 final U frozenDisplayUnit = getDisplayUnit();
72 final Q first = frozenDisplayUnit.ofSi(si[0]).setDisplayUnit(frozenDisplayUnit);
73 final Class<?> qClass = first.getClass();
74 @SuppressWarnings("unchecked")
75 final Q[] out = (Q[]) Array.newInstance(qClass, si.length);
76 out[0] = first;
77 for (int i = 1; i < si.length; i++)
78 {
79 out[i] = frozenDisplayUnit.ofSi(si[i]).setDisplayUnit(frozenDisplayUnit);
80 }
81 return out;
82 }
83
84 @Override
85 public Q normL1()
86 {
87 double n = 0.0;
88 for (var d : si())
89 {
90 n += Math.abs(d);
91 }
92 return getDisplayUnit().ofSi(n).setDisplayUnit(getDisplayUnit());
93 }
94
95 @Override
96 public Q normL2()
97 {
98 double n = 0.0;
99 for (var d : si())
100 {
101 n += d * d;
102 }
103 return getDisplayUnit().ofSi(Math.sqrt(n)).setDisplayUnit(getDisplayUnit());
104 }
105
106 @Override
107 public Q normLp(final int p)
108 {
109 double n = 0.0;
110 for (var d : si())
111 {
112 n += Math.pow(Math.abs(d), p);
113 }
114 return getDisplayUnit().ofSi(Math.pow(n, 1.0 / p)).setDisplayUnit(getDisplayUnit());
115 }
116
117 @Override
118 public Q normLinf()
119 {
120 double max = Double.NEGATIVE_INFINITY;
121 for (var d : si())
122 {
123 max = Math.max(Math.abs(d), max);
124 }
125 return getDisplayUnit().ofSi(max).setDisplayUnit(getDisplayUnit());
126 }
127
128 @Override
129 public int rows()
130 {
131 return this.dataSi.rows();
132 }
133
134 @Override
135 public int cols()
136 {
137 return this.dataSi.cols();
138 }
139
140 @Override
141 public double[] si()
142 {
143 return this.dataSi.getDataArray();
144 }
145
146 @Override
147 public double si(final int row, final int col) throws IndexOutOfBoundsException
148 {
149 return this.dataSi.get(row, col);
150 }
151
152 @Override
153 public int hashCode()
154 {
155 return Objects.hash(this.dataSi);
156 }
157
158 @SuppressWarnings("checkstyle:needbraces")
159 @Override
160 public boolean equals(final Object obj)
161 {
162 if (this == obj)
163 return true;
164 if (obj == null)
165 return false;
166 if (getClass() != obj.getClass())
167 return false;
168 VectorN<?, ?, ?, ?, ?> other = (VectorN<?, ?, ?, ?, ?>) obj;
169 return Objects.equals(this.dataSi, other.dataSi);
170 }
171
172 @Override
173 public String toString(final U withUnit)
174 {
175 double[] data = si();
176 var s = new StringBuilder();
177 s.append(isColumnVector() ? "Col" : "Row");
178 s.append("[");
179 for (int i = 0; i < data.length; i++)
180 {
181 s.append(i > 0 ? ", " : "");
182 s.append(withUnit.fromBaseValue(data[i]));
183 }
184 s.append("] ");
185 s.append(withUnit.getDisplayAbbreviation());
186 return s.toString();
187 }
188
189 @Override
190 public String toString()
191 {
192 return toString(getDisplayUnit());
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206 public static class Col<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>>
207 extends VectorN<Q, U, Col<Q, U>, VectorN.Col<SIQuantity, SIUnit>, VectorN.Col<?, ?>>
208 implements VectorTransposable<Row<Q, U>>
209 {
210
211 private static final long serialVersionUID = 600L;
212
213
214
215
216
217
218
219
220 public Col(final DataGridSi<?> dataSi, final U displayUnit)
221 {
222 super(dataSi, displayUnit);
223 Throw.when(dataSi.cols() != 1, IllegalArgumentException.class,
224 "Column vector initialized with more than one column");
225 }
226
227
228
229
230
231
232
233
234
235
236
237 public static <Q extends Quantity<Q, U>,
238 U extends UnitInterface<U, Q>> VectorN.Col<Q, U> ofSi(final DataGridSi<?> dataSi, final U displayUnit)
239 {
240 return new VectorN.Col<Q, U>(dataSi, displayUnit.getBaseUnit()).setDisplayUnit(displayUnit);
241 }
242
243
244
245
246
247
248
249
250
251 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> ofSi(final double[] dataSi,
252 final U displayUnit)
253 {
254 return new VectorN.Col<Q, U>(new DenseDoubleDataSi(dataSi.clone(), dataSi.length, 1), displayUnit.getBaseUnit())
255 .setDisplayUnit(displayUnit);
256 }
257
258
259
260
261
262
263
264
265
266 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> of(final double[] data,
267 final U unit)
268 {
269 double[] dataSi = new double[data.length];
270 for (int i = 0; i < data.length; i++)
271 {
272 dataSi[i] = unit.toBaseValue(data[i]);
273 }
274 return ofSi(dataSi, unit);
275 }
276
277
278
279
280
281
282
283
284
285 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> of(final Q[] data,
286 final U displayUnit)
287 {
288 double[] dataSi = new double[data.length];
289 for (int i = 0; i < data.length; i++)
290 {
291 dataSi[i] = data[i].si();
292 }
293 return ofSi(dataSi, displayUnit);
294 }
295
296
297
298
299
300
301
302
303
304 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> of(final List<Q> data,
305 final U displayUnit)
306 {
307 double[] dataSi = new double[data.size()];
308 for (int i = 0; i < data.size(); i++)
309 {
310 dataSi[i] = data.get(i).si();
311 }
312 return ofSi(dataSi, displayUnit);
313 }
314
315 @Override
316 public VectorN.Col<Q, U> instantiateSi(final double[] data)
317 {
318 return new VectorN.Col<Q, U>(this.dataSi.instantiateNew(data), getDisplayUnit().getBaseUnit())
319 .setDisplayUnit(getDisplayUnit());
320 }
321
322 @Override
323 public Col<SIQuantity, SIUnit> instantiateSi(final double[] siNew, final SIUnit siUnit)
324 {
325 return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(siNew), siUnit);
326 }
327
328 @Override
329 public Vector1<Q, U> getRowVector(final int row)
330 {
331 checkRow(row);
332 return new Vector1<Q, U>(si(row, 0), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
333 }
334
335 @Override
336 public Vector1<Q, U> mgetRowVector(final int mRow)
337 {
338 mcheckRow(mRow);
339 return new Vector1<Q, U>(msi(mRow, 1), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
340 }
341
342 @Override
343 public VectorN.Col<Q, U> getColumnVector(final int col)
344 {
345 checkCol(col);
346 return new VectorN.Col<Q, U>(this.dataSi.copy(), getDisplayUnit());
347 }
348
349 @Override
350 public VectorN.Col<Q, U> mgetColumnVector(final int mCol)
351 {
352 mcheckCol(mCol);
353 return new VectorN.Col<Q, U>(this.dataSi.copy(), getDisplayUnit());
354 }
355
356 @Override
357 public double[] getRowSi(final int row)
358 {
359 checkRow(row);
360 return new double[] {si(row, 0)};
361 }
362
363 @Override
364 public double[] getColumnSi(final int col)
365 {
366 checkCol(col);
367 return this.dataSi.getColArray(col);
368 }
369
370 @Override
371 public boolean isColumnVector()
372 {
373 return true;
374 }
375
376 @Override
377 public int size()
378 {
379 return this.dataSi.rows();
380 }
381
382 @Override
383 public double si(final int index) throws IndexOutOfBoundsException
384 {
385 return this.dataSi.get(index, 0);
386 }
387
388 @Override
389 public VectorN.Row<Q, U> transpose()
390 {
391 var newSi = this.dataSi.instantiateNew(this.dataSi.getDataArray().clone(), cols(), rows());
392 return new VectorN.Row<Q, U>(newSi, getDisplayUnit());
393 }
394
395 @Override
396 public VectorN.Col<SIQuantity, SIUnit> invertElements()
397 {
398 SIUnit siUnit = getDisplayUnit().siUnit().invert();
399 return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.reciprocal(si())), siUnit);
400 }
401
402 @Override
403 public VectorN.Col<SIQuantity, SIUnit> multiplyElements(final VectorN.Col<?, ?> other)
404 {
405 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
406 return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.multiply(si(), other.si())),
407 siUnit);
408 }
409
410 @Override
411 public VectorN.Col<SIQuantity, SIUnit> divideElements(final VectorN.Col<?, ?> other)
412 {
413 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
414 return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.divide(si(), other.si())), siUnit);
415 }
416
417 @Override
418 public VectorN.Col<SIQuantity, SIUnit> multiplyElements(final Quantity<?, ?> quantity)
419 {
420 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
421 return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.scaleBy(si(), quantity.si())),
422 siUnit);
423 }
424
425
426
427
428
429
430
431
432
433
434
435 public <TQ extends Quantity<TQ, TU>, TU extends UnitInterface<TU, TQ>> VectorN.Col<TQ, TU> as(final TU targetUnit)
436 throws IllegalArgumentException
437 {
438 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
439 "Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
440 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
441 return new VectorN.Col<TQ, TU>(this.dataSi, targetUnit.getBaseUnit()).setDisplayUnit(targetUnit);
442 }
443
444
445
446
447
448
449 public Vector1<Q, U> asVector1()
450 {
451 Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class, "Matrix is not 1x1");
452 final double[] data = si();
453 return new Vector1<Q, U>(data[0], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
454 }
455
456
457
458
459
460
461 public Vector2.Col<Q, U> asVector2Col()
462 {
463 Throw.when(rows() != 2 || cols() != 1, IllegalStateException.class, "Matrix is not 2x1");
464 final double[] data = si();
465 return new Vector2.Col<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
466 }
467
468
469
470
471
472
473 public Vector3.Col<Q, U> asVector3Col()
474 {
475 Throw.when(rows() != 3 || cols() != 1, IllegalStateException.class, "Matrix is not 3x1");
476 final double[] data = si();
477 return new Vector3.Col<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
478 .setDisplayUnit(getDisplayUnit());
479 }
480
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494 public static class Row<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>>
495 extends VectorN<Q, U, Row<Q, U>, VectorN.Row<SIQuantity, SIUnit>, VectorN.Row<?, ?>>
496 implements VectorTransposable<Col<Q, U>>
497 {
498
499 private static final long serialVersionUID = 600L;
500
501
502
503
504
505
506
507
508 public Row(final DataGridSi<?> dataSi, final U displayUnit)
509 {
510 super(dataSi, displayUnit);
511 Throw.when(dataSi.rows() != 1, IllegalArgumentException.class, "Row vector initialized with more than one row");
512 }
513
514
515
516
517
518
519
520
521
522
523
524 public static <Q extends Quantity<Q, U>,
525 U extends UnitInterface<U, Q>> VectorN.Row<Q, U> ofSi(final DataGridSi<?> dataSi, final U displayUnit)
526 {
527 return new VectorN.Row<Q, U>(dataSi, displayUnit.getBaseUnit()).setDisplayUnit(displayUnit);
528 }
529
530
531
532
533
534
535
536
537
538 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> ofSi(final double[] dataSi,
539 final U displayUnit)
540 {
541 return new VectorN.Row<Q, U>(new DenseDoubleDataSi(dataSi.clone(), 1, dataSi.length), displayUnit.getBaseUnit())
542 .setDisplayUnit(displayUnit);
543 }
544
545
546
547
548
549
550
551
552
553 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> of(final double[] data,
554 final U unit)
555 {
556 double[] dataSi = new double[data.length];
557 for (int i = 0; i < data.length; i++)
558 {
559 dataSi[i] = unit.toBaseValue(data[i]);
560 }
561 return ofSi(dataSi, unit);
562 }
563
564
565
566
567
568
569
570
571
572 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> of(final Q[] data,
573 final U displayUnit)
574 {
575 double[] dataSi = new double[data.length];
576 for (int i = 0; i < data.length; i++)
577 {
578 dataSi[i] = data[i].si();
579 }
580 return ofSi(dataSi, displayUnit);
581 }
582
583
584
585
586
587
588
589
590
591 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> of(final List<Q> data,
592 final U displayUnit)
593 {
594 double[] dataSi = new double[data.size()];
595 for (int i = 0; i < data.size(); i++)
596 {
597 dataSi[i] = data.get(i).si();
598 }
599 return ofSi(dataSi, displayUnit);
600 }
601
602 @Override
603 public boolean isColumnVector()
604 {
605 return false;
606 }
607
608 @Override
609 public VectorN.Row<Q, U> instantiateSi(final double[] data)
610 {
611 return new VectorN.Row<>(this.dataSi.instantiateNew(data), getDisplayUnit());
612 }
613
614 @Override
615 public VectorN.Row<SIQuantity, SIUnit> instantiateSi(final double[] siNew, final SIUnit siUnit)
616 {
617 return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(siNew), siUnit);
618 }
619
620 @Override
621 public VectorN.Row<Q, U> getRowVector(final int row)
622 {
623 checkRow(row);
624 return new VectorN.Row<Q, U>(this.dataSi.copy(), getDisplayUnit());
625 }
626
627 @Override
628 public VectorN.Row<Q, U> mgetRowVector(final int mRow)
629 {
630 mcheckRow(mRow);
631 return new VectorN.Row<Q, U>(this.dataSi.copy(), getDisplayUnit());
632 }
633
634 @Override
635 public Vector1<Q, U> getColumnVector(final int col)
636 {
637 checkCol(col);
638 return new Vector1<Q, U>(si(0, col), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
639 }
640
641 @Override
642 public Vector1<Q, U> mgetColumnVector(final int mCol)
643 {
644 mcheckCol(mCol);
645 return new Vector1<Q, U>(msi(1, mCol), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
646 }
647
648 @Override
649 public double[] getRowSi(final int row)
650 {
651 checkRow(row);
652 return this.dataSi.getRowArray(row);
653 }
654
655 @Override
656 public double[] getColumnSi(final int col)
657 {
658 checkCol(col);
659 return new double[] {si(0, col)};
660 }
661
662 @Override
663 public int size()
664 {
665 return this.dataSi.cols();
666 }
667
668 @Override
669 public double si(final int index) throws IndexOutOfBoundsException
670 {
671 return this.dataSi.get(0, index);
672 }
673
674 @Override
675 public VectorN.Col<Q, U> transpose()
676 {
677 var newSi = this.dataSi.instantiateNew(this.dataSi.getDataArray().clone(), cols(), rows());
678 return new VectorN.Col<Q, U>(newSi, getDisplayUnit());
679 }
680
681 @Override
682 public VectorN.Row<SIQuantity, SIUnit> invertElements()
683 {
684 SIUnit siUnit = getDisplayUnit().siUnit().invert();
685 return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.reciprocal(si())), siUnit);
686 }
687
688 @Override
689 public VectorN.Row<SIQuantity, SIUnit> multiplyElements(final VectorN.Row<?, ?> other)
690 {
691 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
692 return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.multiply(si(), other.si())),
693 siUnit);
694 }
695
696 @Override
697 public VectorN.Row<SIQuantity, SIUnit> divideElements(final VectorN.Row<?, ?> other)
698 {
699 SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
700 return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.divide(si(), other.si())), siUnit);
701 }
702
703 @Override
704 public VectorN.Row<SIQuantity, SIUnit> multiplyElements(final Quantity<?, ?> quantity)
705 {
706 SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
707 return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.scaleBy(si(), quantity.si())),
708 siUnit);
709 }
710
711
712
713
714
715
716
717
718
719
720
721 public <TQ extends Quantity<TQ, TU>, TU extends UnitInterface<TU, TQ>> VectorN.Row<TQ, TU> as(final TU targetUnit)
722 throws IllegalArgumentException
723 {
724 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
725 "Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
726 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
727 return new VectorN.Row<TQ, TU>(this.dataSi, targetUnit.getBaseUnit()).setDisplayUnit(targetUnit);
728 }
729
730
731
732
733
734
735 public Vector1<Q, U> asVector1()
736 {
737 Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class, "Matrix is not 1x1");
738 final double[] data = si();
739 return new Vector1<Q, U>(data[0], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
740 }
741
742
743
744
745
746
747 public Vector2.Row<Q, U> asVector2Row()
748 {
749 Throw.when(rows() != 1 || cols() != 2, IllegalStateException.class, "Matrix is not 1x2");
750 final double[] data = si();
751 return new Vector2.Row<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
752 }
753
754
755
756
757
758
759 public Vector3.Row<Q, U> asVector3Row()
760 {
761 Throw.when(rows() != 1 || cols() != 3, IllegalStateException.class, "Matrix is not 1x3");
762 final double[] data = si();
763 return new Vector3.Row<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
764 .setDisplayUnit(getDisplayUnit());
765 }
766
767 }
768
769 }