VectorN.java
package org.djunits.vecmat.dn;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import org.djunits.quantity.SIQuantity;
import org.djunits.quantity.def.Quantity;
import org.djunits.unit.UnitInterface;
import org.djunits.unit.si.SIUnit;
import org.djunits.util.ArrayMath;
import org.djunits.vecmat.d1.Vector1;
import org.djunits.vecmat.d2.Vector2;
import org.djunits.vecmat.d3.Vector3;
import org.djunits.vecmat.def.Vector;
import org.djunits.vecmat.operations.VectorTransposable;
import org.djunits.vecmat.storage.DataGridSi;
import org.djunits.vecmat.storage.DenseDoubleDataSi;
import org.djutils.exceptions.Throw;
/**
* VectorN.java.
* <p>
* Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
* distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
* @author Alexander Verbraeck
* @param <Q> the quantity type
* @param <U> the unit type
* @param <V> the vector type (Row or Col)
* @param <SI> the vector type with generics <SIQuantity, SIUnit<
* @param <H> the generic vector type with generics <?, ?< for Hadamard operations
*/
public abstract class VectorN<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>, V extends VectorN<Q, U, V, SI, H>,
SI extends VectorN<SIQuantity, SIUnit, SI, ?, ?>, H extends VectorN<?, ?, ?, ?, ?>> extends Vector<Q, U, V, SI, H>
{
/** */
private static final long serialVersionUID = 600L;
/** The data of the matrix, in SI unit. */
@SuppressWarnings("checkstyle:visibilitymodifier")
protected final DataGridSi<?> dataSi;
/**
* Create a new VectorN with a unit, based on a DataGridSi storage object that contains SI data.
* @param dataSi the data of the vector, in SI unit.
* @param displayUnit the display unit to use
* @throws IllegalArgumentException when the number of rows or columns does not have a positive value
*/
protected VectorN(final DataGridSi<?> dataSi, final U displayUnit)
{
super(displayUnit);
Throw.whenNull(dataSi, "dataSi");
this.dataSi = dataSi;
}
@Override
public Iterator<Q> iterator()
{
final double[] si = this.dataSi.getDataArray(); // should be immutable, otherwise make defensive copy
final U frozenDisplayUnit = getDisplayUnit(); // capture once
return Arrays.stream(si).mapToObj(v -> frozenDisplayUnit.ofSi(v).setDisplayUnit(frozenDisplayUnit)).iterator();
}
@Override
public Q[] getScalarArray()
{
final double[] si = this.dataSi.getDataArray(); // should be immutable, otherwise make defensive copy
final U frozenDisplayUnit = getDisplayUnit(); // capture once
final Q first = frozenDisplayUnit.ofSi(si[0]).setDisplayUnit(frozenDisplayUnit);
final Class<?> qClass = first.getClass();
@SuppressWarnings("unchecked")
final Q[] out = (Q[]) Array.newInstance(qClass, si.length);
out[0] = first;
for (int i = 1; i < si.length; i++)
{
out[i] = frozenDisplayUnit.ofSi(si[i]).setDisplayUnit(frozenDisplayUnit);
}
return out;
}
@Override
public Q normL1()
{
double n = 0.0;
for (var d : si())
{
n += Math.abs(d);
}
return getDisplayUnit().ofSi(n).setDisplayUnit(getDisplayUnit());
}
@Override
public Q normL2()
{
double n = 0.0;
for (var d : si())
{
n += d * d;
}
return getDisplayUnit().ofSi(Math.sqrt(n)).setDisplayUnit(getDisplayUnit());
}
@Override
public Q normLp(final int p)
{
double n = 0.0;
for (var d : si())
{
n += Math.pow(Math.abs(d), p);
}
return getDisplayUnit().ofSi(Math.pow(n, 1.0 / p)).setDisplayUnit(getDisplayUnit());
}
@Override
public Q normLinf()
{
double max = Double.NEGATIVE_INFINITY;
for (var d : si())
{
max = Math.max(Math.abs(d), max);
}
return getDisplayUnit().ofSi(max).setDisplayUnit(getDisplayUnit());
}
@Override
public int rows()
{
return this.dataSi.rows();
}
@Override
public int cols()
{
return this.dataSi.cols();
}
@Override
public double[] si()
{
return this.dataSi.getDataArray();
}
@Override
public double si(final int row, final int col) throws IndexOutOfBoundsException
{
return this.dataSi.get(row, col);
}
@Override
public int hashCode()
{
return Objects.hash(this.dataSi);
}
@SuppressWarnings("checkstyle:needbraces")
@Override
public boolean equals(final Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
VectorN<?, ?, ?, ?, ?> other = (VectorN<?, ?, ?, ?, ?>) obj;
return Objects.equals(this.dataSi, other.dataSi);
}
@Override
public String toString(final U withUnit)
{
double[] data = si();
var s = new StringBuilder();
s.append(isColumnVector() ? "Col" : "Row");
s.append("[");
for (int i = 0; i < data.length; i++)
{
s.append(i > 0 ? ", " : "");
s.append(withUnit.fromBaseValue(data[i]));
}
s.append("] ");
s.append(withUnit.getDisplayAbbreviation());
return s.toString();
}
@Override
public String toString()
{
return toString(getDisplayUnit());
}
/**
* VectorN.Col implements a column vector with real-valued entries. The vector is immutable, except for the display unit,
* which can be changed.
* <p>
* Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
* See for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
* distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
* @author Alexander Verbraeck
* @param <Q> the quantity type
* @param <U> the unit type
*/
public static class Col<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>>
extends VectorN<Q, U, Col<Q, U>, VectorN.Col<SIQuantity, SIUnit>, VectorN.Col<?, ?>>
implements VectorTransposable<Row<Q, U>>
{
/** */
private static final long serialVersionUID = 600L;
/**
* Create a new column VectorN with a unit, based on a DataGridSi storage object that contains SI data.
* @param dataSi the data of the vector, in SI unit.
* @param displayUnit the display unit to use
* @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
* is initialized with more than one row
*/
public Col(final DataGridSi<?> dataSi, final U displayUnit)
{
super(dataSi, displayUnit);
Throw.when(dataSi.cols() != 1, IllegalArgumentException.class,
"Column vector initialized with more than one column");
}
/**
* Create a new column VectorN with a unit, based on a DataGridSi storage object that contains SI data.
* @param <Q> the quantity type
* @param <U> the unit type
* @param dataSi the data of the vector, in SI unit.
* @param displayUnit the display unit to use
* @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
* is initialized with more than one row
* @return a new column VectorN with a unit, based on a DataGridSi storage object that contains SI data
*/
public static <Q extends Quantity<Q, U>,
U extends UnitInterface<U, Q>> VectorN.Col<Q, U> ofSi(final DataGridSi<?> dataSi, final U displayUnit)
{
return new VectorN.Col<Q, U>(dataSi, displayUnit.getBaseUnit()).setDisplayUnit(displayUnit);
}
/**
* Create a new column VectorN with a unit, based on a double[] array that contains SI data.
* @param <Q> the quantity type
* @param <U> the unit type
* @param dataSi the data of the vector, in SI unit.
* @param displayUnit the display unit to use
* @return a new column VectorN with a unit, based on a double[] array that contains SI data
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> ofSi(final double[] dataSi,
final U displayUnit)
{
return new VectorN.Col<Q, U>(new DenseDoubleDataSi(dataSi.clone(), dataSi.length, 1), displayUnit.getBaseUnit())
.setDisplayUnit(displayUnit);
}
/**
* Create a new column VectorN with a unit, based on a double[] array that contains data in the given unit.
* @param <Q> the quantity type
* @param <U> the unit type
* @param data the data of the vector, in the given unit.
* @param unit the unit of the data
* @return a new column VectorN with a unit, based on a double[] array expressed in the given unit
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> of(final double[] data,
final U unit)
{
double[] dataSi = new double[data.length];
for (int i = 0; i < data.length; i++)
{
dataSi[i] = unit.toBaseValue(data[i]);
}
return ofSi(dataSi, unit);
}
/**
* Create a new column VectorN with a unit, based on a quantity array that contains data.
* @param <Q> the quantity type
* @param <U> the display unit type
* @param data the data of the vector, in the given unit.
* @param displayUnit the display unit of the vector
* @return a new column VectorN with a display unit, based on a quantity array
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> of(final Q[] data,
final U displayUnit)
{
double[] dataSi = new double[data.length];
for (int i = 0; i < data.length; i++)
{
dataSi[i] = data[i].si();
}
return ofSi(dataSi, displayUnit);
}
/**
* Create a new column VectorN with a unit, based on a quantity list that contains data.
* @param <Q> the quantity type
* @param <U> the display unit type
* @param data the data of the vector, in the given unit.
* @param displayUnit the display unit of the vector
* @return a new column VectorN with a display unit, based on a quantity list
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Col<Q, U> of(final List<Q> data,
final U displayUnit)
{
double[] dataSi = new double[data.size()];
for (int i = 0; i < data.size(); i++)
{
dataSi[i] = data.get(i).si();
}
return ofSi(dataSi, displayUnit);
}
@Override
public VectorN.Col<Q, U> instantiateSi(final double[] data)
{
return new VectorN.Col<Q, U>(this.dataSi.instantiateNew(data), getDisplayUnit().getBaseUnit())
.setDisplayUnit(getDisplayUnit());
}
@Override
public Col<SIQuantity, SIUnit> instantiateSi(final double[] siNew, final SIUnit siUnit)
{
return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(siNew), siUnit);
}
@Override
public Vector1<Q, U> getRowVector(final int row)
{
checkRow(row);
return new Vector1<Q, U>(si(row, 0), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
@Override
public Vector1<Q, U> mgetRowVector(final int mRow)
{
mcheckRow(mRow);
return new Vector1<Q, U>(msi(mRow, 1), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
@Override
public VectorN.Col<Q, U> getColumnVector(final int col)
{
checkCol(col);
return new VectorN.Col<Q, U>(this.dataSi.copy(), getDisplayUnit());
}
@Override
public VectorN.Col<Q, U> mgetColumnVector(final int mCol)
{
mcheckCol(mCol);
return new VectorN.Col<Q, U>(this.dataSi.copy(), getDisplayUnit());
}
@Override
public double[] getRowSi(final int row)
{
checkRow(row);
return new double[] {si(row, 0)};
}
@Override
public double[] getColumnSi(final int col)
{
checkCol(col);
return this.dataSi.getColArray(col);
}
@Override
public boolean isColumnVector()
{
return true;
}
@Override
public int size()
{
return this.dataSi.rows();
}
@Override
public double si(final int index) throws IndexOutOfBoundsException
{
return this.dataSi.get(index, 0);
}
@Override
public VectorN.Row<Q, U> transpose()
{
var newSi = this.dataSi.instantiateNew(this.dataSi.getDataArray().clone(), cols(), rows());
return new VectorN.Row<Q, U>(newSi, getDisplayUnit());
}
@Override
public VectorN.Col<SIQuantity, SIUnit> invertElements()
{
SIUnit siUnit = getDisplayUnit().siUnit().invert();
return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.reciprocal(si())), siUnit);
}
@Override
public VectorN.Col<SIQuantity, SIUnit> multiplyElements(final VectorN.Col<?, ?> other)
{
SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.multiply(si(), other.si())),
siUnit);
}
@Override
public VectorN.Col<SIQuantity, SIUnit> divideElements(final VectorN.Col<?, ?> other)
{
SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.divide(si(), other.si())), siUnit);
}
@Override
public VectorN.Col<SIQuantity, SIUnit> multiplyElements(final Quantity<?, ?> quantity)
{
SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
return new VectorN.Col<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.scaleBy(si(), quantity.si())),
siUnit);
}
/**
* Return the vector 'as' a vector with a known quantity, using a unit to express the result in. Throw a Runtime
* exception when the SI units of this vector and the target vector do not match. The dataSi object containing the
* vector values is NOT copied.
* @param targetUnit the unit to convert the vector to
* @return a quantity typed in the target vector class
* @throws IllegalArgumentException when the units do not match
* @param <TQ> target quantity type
* @param <TU> target unit type
*/
public <TQ extends Quantity<TQ, TU>, TU extends UnitInterface<TU, TQ>> VectorN.Col<TQ, TU> as(final TU targetUnit)
throws IllegalArgumentException
{
Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
"Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
return new VectorN.Col<TQ, TU>(this.dataSi, targetUnit.getBaseUnit()).setDisplayUnit(targetUnit);
}
/**
* Return this matrix as a 1-element column vector. Shape must be 1 x 1.
* @return a {@code Vector1} with identical SI data and display unit
* @throws IllegalStateException if shape is not 1 x 1
*/
public Vector1<Q, U> asVector1()
{
Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class, "Matrix is not 1x1");
final double[] data = si();
return new Vector1<Q, U>(data[0], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
/**
* Return this matrix as a 2-element column vector. Shape must be 2 x 1.
* @return a {@code Vector2.Col} with identical SI data and display unit
* @throws IllegalStateException if shape is not 2 x 1
*/
public Vector2.Col<Q, U> asVector2Col()
{
Throw.when(rows() != 2 || cols() != 1, IllegalStateException.class, "Matrix is not 2x1");
final double[] data = si();
return new Vector2.Col<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
/**
* Return this matrix as a 3-element column vector. Shape must be 3 x 1.
* @return a {@code Vector3.Col} with identical SI data and display unit
* @throws IllegalStateException if shape is not 3 x 1
*/
public Vector3.Col<Q, U> asVector3Col()
{
Throw.when(rows() != 3 || cols() != 1, IllegalStateException.class, "Matrix is not 3x1");
final double[] data = si();
return new Vector3.Col<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
.setDisplayUnit(getDisplayUnit());
}
}
/**
* VectorN.Row implements a row vector with real-valued entries. The vector is immutable, except for the display unit, which
* can be changed.
* <p>
* Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
* See for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
* distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
* @author Alexander Verbraeck
* @param <Q> the quantity type
* @param <U> the unit type
*/
public static class Row<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>>
extends VectorN<Q, U, Row<Q, U>, VectorN.Row<SIQuantity, SIUnit>, VectorN.Row<?, ?>>
implements VectorTransposable<Col<Q, U>>
{
/** */
private static final long serialVersionUID = 600L;
/**
* Create a new row VectorN with a unit, based on a DataGridSi storage object that contains SI data.
* @param dataSi the data of the vector, in SI unit.
* @param displayUnit the display unit to use
* @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
* is initialized with more than one row
*/
public Row(final DataGridSi<?> dataSi, final U displayUnit)
{
super(dataSi, displayUnit);
Throw.when(dataSi.rows() != 1, IllegalArgumentException.class, "Row vector initialized with more than one row");
}
/**
* Create a new row VectorN with a unit, based on a DataGridSi storage object that contains SI data.
* @param <Q> the quantity type
* @param <U> the unit type
* @param dataSi the data of the vector, in SI unit.
* @param displayUnit the display unit to use
* @throws IllegalArgumentException when the number of rows or columns does not have a positive value or when the vector
* is initialized with more than one row
* @return a new row VectorN with a unit, based on a DataGridSi storage object that contains SI data
*/
public static <Q extends Quantity<Q, U>,
U extends UnitInterface<U, Q>> VectorN.Row<Q, U> ofSi(final DataGridSi<?> dataSi, final U displayUnit)
{
return new VectorN.Row<Q, U>(dataSi, displayUnit.getBaseUnit()).setDisplayUnit(displayUnit);
}
/**
* Create a new row VectorN with a unit, based on a double[] array that contains SI data.
* @param <Q> the quantity type
* @param <U> the unit type
* @param dataSi the data of the vector, in SI unit.
* @param displayUnit the display unit to use
* @return a new row VectorN with a unit, based on a double[] array that contains SI data
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> ofSi(final double[] dataSi,
final U displayUnit)
{
return new VectorN.Row<Q, U>(new DenseDoubleDataSi(dataSi.clone(), 1, dataSi.length), displayUnit.getBaseUnit())
.setDisplayUnit(displayUnit);
}
/**
* Create a new row VectorN with a unit, based on a double[] array that contains data in the given unit.
* @param <Q> the quantity type
* @param <U> the unit type
* @param data the data of the vector, in the given unit.
* @param unit the unit of the data
* @return a new row VectorN with a unit, based on a double[] array expressed in the given unit
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> of(final double[] data,
final U unit)
{
double[] dataSi = new double[data.length];
for (int i = 0; i < data.length; i++)
{
dataSi[i] = unit.toBaseValue(data[i]);
}
return ofSi(dataSi, unit);
}
/**
* Create a new row VectorN with a unit, based on a quantity array that contains data.
* @param <Q> the quantity type
* @param <U> the display unit type
* @param data the data of the vector, in the given unit.
* @param displayUnit the display unit of the vector
* @return a new row VectorN with a display unit, based on a quantity array
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> of(final Q[] data,
final U displayUnit)
{
double[] dataSi = new double[data.length];
for (int i = 0; i < data.length; i++)
{
dataSi[i] = data[i].si();
}
return ofSi(dataSi, displayUnit);
}
/**
* Create a new row VectorN with a unit, based on a quantity list that contains data.
* @param <Q> the quantity type
* @param <U> the display unit type
* @param data the data of the vector, in the given unit.
* @param displayUnit the display unit of the vector
* @return a new row VectorN with a display unit, based on a quantity list
*/
public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> VectorN.Row<Q, U> of(final List<Q> data,
final U displayUnit)
{
double[] dataSi = new double[data.size()];
for (int i = 0; i < data.size(); i++)
{
dataSi[i] = data.get(i).si();
}
return ofSi(dataSi, displayUnit);
}
@Override
public boolean isColumnVector()
{
return false;
}
@Override
public VectorN.Row<Q, U> instantiateSi(final double[] data)
{
return new VectorN.Row<>(this.dataSi.instantiateNew(data), getDisplayUnit());
}
@Override
public VectorN.Row<SIQuantity, SIUnit> instantiateSi(final double[] siNew, final SIUnit siUnit)
{
return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(siNew), siUnit);
}
@Override
public VectorN.Row<Q, U> getRowVector(final int row)
{
checkRow(row);
return new VectorN.Row<Q, U>(this.dataSi.copy(), getDisplayUnit());
}
@Override
public VectorN.Row<Q, U> mgetRowVector(final int mRow)
{
mcheckRow(mRow);
return new VectorN.Row<Q, U>(this.dataSi.copy(), getDisplayUnit());
}
@Override
public Vector1<Q, U> getColumnVector(final int col)
{
checkCol(col);
return new Vector1<Q, U>(si(0, col), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
@Override
public Vector1<Q, U> mgetColumnVector(final int mCol)
{
mcheckCol(mCol);
return new Vector1<Q, U>(msi(1, mCol), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
@Override
public double[] getRowSi(final int row)
{
checkRow(row);
return this.dataSi.getRowArray(row);
}
@Override
public double[] getColumnSi(final int col)
{
checkCol(col);
return new double[] {si(0, col)};
}
@Override
public int size()
{
return this.dataSi.cols();
}
@Override
public double si(final int index) throws IndexOutOfBoundsException
{
return this.dataSi.get(0, index);
}
@Override
public VectorN.Col<Q, U> transpose()
{
var newSi = this.dataSi.instantiateNew(this.dataSi.getDataArray().clone(), cols(), rows());
return new VectorN.Col<Q, U>(newSi, getDisplayUnit());
}
@Override
public VectorN.Row<SIQuantity, SIUnit> invertElements()
{
SIUnit siUnit = getDisplayUnit().siUnit().invert();
return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.reciprocal(si())), siUnit);
}
@Override
public VectorN.Row<SIQuantity, SIUnit> multiplyElements(final VectorN.Row<?, ?> other)
{
SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.multiply(si(), other.si())),
siUnit);
}
@Override
public VectorN.Row<SIQuantity, SIUnit> divideElements(final VectorN.Row<?, ?> other)
{
SIUnit siUnit = SIUnit.subtract(getDisplayUnit().siUnit(), other.getDisplayUnit().siUnit());
return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.divide(si(), other.si())), siUnit);
}
@Override
public VectorN.Row<SIQuantity, SIUnit> multiplyElements(final Quantity<?, ?> quantity)
{
SIUnit siUnit = SIUnit.add(getDisplayUnit().siUnit(), quantity.getDisplayUnit().siUnit());
return new VectorN.Row<SIQuantity, SIUnit>(this.dataSi.instantiateNew(ArrayMath.scaleBy(si(), quantity.si())),
siUnit);
}
/**
* Return the vector 'as' a vector with a known quantity, using a unit to express the result in. Throw a Runtime
* exception when the SI units of this vector and the target vector do not match. The dataSi object containing the
* vector values is NOT copied.
* @param targetUnit the unit to convert the vector to
* @return a quantity typed in the target vector class
* @throws IllegalArgumentException when the units do not match
* @param <TQ> target quantity type
* @param <TU> target unit type
*/
public <TQ extends Quantity<TQ, TU>, TU extends UnitInterface<TU, TQ>> VectorN.Row<TQ, TU> as(final TU targetUnit)
throws IllegalArgumentException
{
Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
"Quantity.as(%s) called, but units do not match: %s <> %s", targetUnit,
getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
return new VectorN.Row<TQ, TU>(this.dataSi, targetUnit.getBaseUnit()).setDisplayUnit(targetUnit);
}
/**
* Return this matrix as a 1-element column vector. Shape must be 1 x 1.
* @return a {@code Vector1} with identical SI data and display unit
* @throws IllegalStateException if shape is not 1 x 1
*/
public Vector1<Q, U> asVector1()
{
Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class, "Matrix is not 1x1");
final double[] data = si();
return new Vector1<Q, U>(data[0], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
/**
* Return this matrix as a 2-element row vector. Shape must be 1 x 2.
* @return a {@code Vector2.Row} with identical SI data and display unit
* @throws IllegalStateException if shape is not 1 x 2
*/
public Vector2.Row<Q, U> asVector2Row()
{
Throw.when(rows() != 1 || cols() != 2, IllegalStateException.class, "Matrix is not 1x2");
final double[] data = si();
return new Vector2.Row<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
}
/**
* Return this matrix as a 3-element row vector. Shape must be 1 x 3.
* @return a {@code Vector3.Row} with identical SI data and display unit
* @throws IllegalStateException if shape is not 1 x 3
*/
public Vector3.Row<Q, U> asVector3Row()
{
Throw.when(rows() != 1 || cols() != 3, IllegalStateException.class, "Matrix is not 1x3");
final double[] data = si();
return new Vector3.Row<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
.setDisplayUnit(getDisplayUnit());
}
}
}