View Javadoc
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   * VectorN.java.
25   * <p>
26   * Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
27   * for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
28   * distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
29   * @author Alexander Verbraeck
30   * @param <Q> the quantity type
31   * @param <U> the unit type
32   * @param <V> the vector type (Row or Col)
33   * @param <SI> the vector type with generics &lt;SIQuantity, SIUnit&lt;
34   * @param <H> the generic vector type with generics &lt;?, ?&lt; for Hadamard operations
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      /** The data of the matrix, in SI unit. */
43      @SuppressWarnings("checkstyle:visibilitymodifier")
44      protected final DataGridSi<?> dataSi;
45  
46      /**
47       * Create a new VectorN with a unit, based on a DataGridSi storage object that contains SI data.
48       * @param dataSi the data of the vector, in SI unit.
49       * @param displayUnit the display unit to use
50       * @throws IllegalArgumentException when the number of rows or columns does not have a positive value
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(); // should be immutable, otherwise make defensive copy
63          final U frozenDisplayUnit = getDisplayUnit(); // capture once
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(); // should be immutable, otherwise make defensive copy
71          final U frozenDisplayUnit = getDisplayUnit(); // capture once
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      * VectorN.Col implements a column vector with real-valued entries. The vector is immutable, except for the display unit,
197      * which can be changed.
198      * <p>
199      * Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
200      * See for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
201      * distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
202      * @author Alexander Verbraeck
203      * @param <Q> the quantity type
204      * @param <U> the unit type
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          * Create a new column VectorN with a unit, based on a DataGridSi storage object that contains SI data.
215          * @param dataSi the data of the vector, in SI unit.
216          * @param displayUnit the display unit to use
217          * @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
218          *             is initialized with more than one row
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          * Create a new column VectorN with a unit, based on a DataGridSi storage object that contains SI data.
229          * @param <Q> the quantity type
230          * @param <U> the unit type
231          * @param dataSi the data of the vector, in SI unit.
232          * @param displayUnit the display unit to use
233          * @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
234          *             is initialized with more than one row
235          * @return a new column VectorN with a unit, based on a DataGridSi storage object that contains SI data
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          * Create a new column VectorN with a unit, based on a double[] array that contains SI data.
245          * @param <Q> the quantity type
246          * @param <U> the unit type
247          * @param dataSi the data of the vector, in SI unit.
248          * @param displayUnit the display unit to use
249          * @return a new column VectorN with a unit, based on a double[] array that contains SI data
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          * Create a new column VectorN with a unit, based on a double[] array that contains data in the given unit.
260          * @param <Q> the quantity type
261          * @param <U> the unit type
262          * @param data the data of the vector, in the given unit.
263          * @param unit the unit of the data
264          * @return a new column VectorN with a unit, based on a double[] array expressed in the given unit
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          * Create a new column VectorN with a unit, based on a quantity array that contains data.
279          * @param <Q> the quantity type
280          * @param <U> the display unit type
281          * @param data the data of the vector, in the given unit.
282          * @param displayUnit the display unit of the vector
283          * @return a new column VectorN with a display unit, based on a quantity array
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          * Create a new column VectorN with a unit, based on a quantity list that contains data.
298          * @param <Q> the quantity type
299          * @param <U> the display unit type
300          * @param data the data of the vector, in the given unit.
301          * @param displayUnit the display unit of the vector
302          * @return a new column VectorN with a display unit, based on a quantity list
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          * Return the vector 'as' a vector with a known quantity, using a unit to express the result in. Throw a Runtime
427          * exception when the SI units of this vector and the target vector do not match. The dataSi object containing the
428          * vector values is NOT copied.
429          * @param targetUnit the unit to convert the vector to
430          * @return a quantity typed in the target vector class
431          * @throws IllegalArgumentException when the units do not match
432          * @param <TQ> target quantity type
433          * @param <TU> target unit type
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          * Return this matrix as a 1-element column vector. Shape must be 1 x 1.
446          * @return a {@code Vector1} with identical SI data and display unit
447          * @throws IllegalStateException if shape is not 1 x 1
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          * Return this matrix as a 2-element column vector. Shape must be 2 x 1.
458          * @return a {@code Vector2.Col} with identical SI data and display unit
459          * @throws IllegalStateException if shape is not 2 x 1
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          * Return this matrix as a 3-element column vector. Shape must be 3 x 1.
470          * @return a {@code Vector3.Col} with identical SI data and display unit
471          * @throws IllegalStateException if shape is not 3 x 1
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      * VectorN.Row implements a row vector with real-valued entries. The vector is immutable, except for the display unit, which
485      * can be changed.
486      * <p>
487      * Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
488      * See for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
489      * distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
490      * @author Alexander Verbraeck
491      * @param <Q> the quantity type
492      * @param <U> the unit type
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          * Create a new row VectorN with a unit, based on a DataGridSi storage object that contains SI data.
503          * @param dataSi the data of the vector, in SI unit.
504          * @param displayUnit the display unit to use
505          * @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
506          *             is initialized with more than one row
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          * Create a new row VectorN with a unit, based on a DataGridSi storage object that contains SI data.
516          * @param <Q> the quantity type
517          * @param <U> the unit type
518          * @param dataSi the data of the vector, in SI unit.
519          * @param displayUnit the display unit to use
520          * @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
521          *             is initialized with more than one row
522          * @return a new row VectorN with a unit, based on a DataGridSi storage object that contains SI data
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          * Create a new row VectorN with a unit, based on a double[] array that contains SI data.
532          * @param <Q> the quantity type
533          * @param <U> the unit type
534          * @param dataSi the data of the vector, in SI unit.
535          * @param displayUnit the display unit to use
536          * @return a new row VectorN with a unit, based on a double[] array that contains SI data
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          * Create a new row VectorN with a unit, based on a double[] array that contains data in the given unit.
547          * @param <Q> the quantity type
548          * @param <U> the unit type
549          * @param data the data of the vector, in the given unit.
550          * @param unit the unit of the data
551          * @return a new row VectorN with a unit, based on a double[] array expressed in the given unit
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          * Create a new row VectorN with a unit, based on a quantity array that contains data.
566          * @param <Q> the quantity type
567          * @param <U> the display unit type
568          * @param data the data of the vector, in the given unit.
569          * @param displayUnit the display unit of the vector
570          * @return a new row VectorN with a display unit, based on a quantity array
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          * Create a new row VectorN with a unit, based on a quantity list that contains data.
585          * @param <Q> the quantity type
586          * @param <U> the display unit type
587          * @param data the data of the vector, in the given unit.
588          * @param displayUnit the display unit of the vector
589          * @return a new row VectorN with a display unit, based on a quantity list
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          * Return the vector 'as' a vector with a known quantity, using a unit to express the result in. Throw a Runtime
713          * exception when the SI units of this vector and the target vector do not match. The dataSi object containing the
714          * vector values is NOT copied.
715          * @param targetUnit the unit to convert the vector to
716          * @return a quantity typed in the target vector class
717          * @throws IllegalArgumentException when the units do not match
718          * @param <TQ> target quantity type
719          * @param <TU> target unit type
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          * Return this matrix as a 1-element column vector. Shape must be 1 x 1.
732          * @return a {@code Vector1} with identical SI data and display unit
733          * @throws IllegalStateException if shape is not 1 x 1
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          * Return this matrix as a 2-element row vector. Shape must be 1 x 2.
744          * @return a {@code Vector2.Row} with identical SI data and display unit
745          * @throws IllegalStateException if shape is not 1 x 2
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          * Return this matrix as a 3-element row vector. Shape must be 1 x 3.
756          * @return a {@code Vector3.Row} with identical SI data and display unit
757          * @throws IllegalStateException if shape is not 1 x 3
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 }