matlabcontrol.extensions.MatlabNumericArray Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of matconsolectl Show documentation
Show all versions of matconsolectl Show documentation
MatConsoleCtl - control MATLAB from Java
/*
* Code licensed under new-style BSD (see LICENSE).
* All code up to tags/original: Copyright (c) 2013, Joshua Kaplan
* All code after tags/original: Copyright (c) 2016, DiffPlug
*/
package matlabcontrol.extensions;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Acts as a MATLAB array of doubles. MATLAB arrays of any numeric type may be represented by a
* {@code MatlabNumericArray}, but precision may be lost in the process. Dimensions of 2 and greater are supported. (No
* array in MATLAB has a dimension less than 2.) This representation is a copy of the MATLAB data, not a live view.
* Retrieving large arrays from MATLAB can result in a {@link OutOfMemoryError}; if this occurs you may want to either
* retrieve only part of the array from MATLAB or increase your Java Virtual Machine's heap size.
*
* Note: Sparse arrays are not supported. Attempts to retrieve a sparse may not throw an exception, but the
* result will not be valid.
*
* Both the real and imaginary components of a MATLAB array are supported. If the array has no imaginary values then
* attempts to access these values will result in a {@link IllegalStateException} being thrown.
*
* Arrays in MATLAB are stored in a linear manner. The number and lengths of the dimensions are stored separately from
* the real and imaginary value entries. Each dimension has a fixed length. (MATLAB's array implementation is known as
* a dope vector.)
*
* Java has no multidimensional array type. To support multiple dimensions, Java allows for creating arrays of any data
* type, including arrays. (Java's array implementation is known as an Iliffe vector.) A two dimensional array of
* {@code double}s, {@code double[][]}, is just an array of {@code double[]}. A result of this is that each
* {@code double[]} can have a different length. When not all inner arrays for a given dimension have the same length,
* then the array is known as as a jagged array (also known as a ragged array).
*
* When an array is retrieved from MATLAB the resulting Java array is never jagged. When a {@code MatlabNumericArray} is
* constructed from Java arrays, the arrays provided may be jagged; see the
* {@link #MatlabNumericArray(DoubleArrayType, java.lang.Object, java.lang.Object) main constructor} for details.
*
* Each instance knows the number of dimensions it represents and can create the corresponding multidimensional Java
* array. In order to do this in a type safe manner the methods {@link #getRealArray(DoubleArrayType) getRealArray(...)}
* and {@link #getImaginaryArray(DoubleArrayType) getImaginaryArray(...)} exist. Convenience methods exist to easily
* retrieve the arrays as two, three, and four dimensional arrays. All of these methods will throw a
* {@link ArrayDimensionException} if the array is not actually of that dimension. It is also possible to retrieve
* values from the array without converting it to the corresponding multidimensional Java array. This can be done either
* by using the index into the underlying linear MATLAB array, or by using the multidimensional indices. Retrieving
* values in this manner does not require the computation and memory necessary to create the multidimensional Java
* array.
*
* While this class mimics the dimension and lengths of a MATLAB array, it uses Java's 0-index convention instead of
* MATLAB's 1-index convention. For instance in MATLAB if an array were indexed into as {@code array(3,4,7,2)}, then in
* Java to retrieve the same entry the indexing would be performed as {@code array[2][3][6][1]}.
*
* Once constructed, this class is unconditionally thread-safe. If the data provided to a constructor is modified while
* construction is occurring, problems may occur.
*
* @see MatlabTypeConverter#setNumericArray(java.lang.String, matlabcontrol.extensions.MatlabNumericArray)
* @see MatlabTypeConverter#getNumericArray(java.lang.String)
*
* @since 4.0.0
*
* @author Joshua Kaplan
*/
public final class MatlabNumericArray {
/**
* Linear array of real values.
*/
private final double[] _realValues;
/**
* Linear array of imaginary values.
*/
private final double[] _imaginaryValues;
/**
* The lengths for each dimension of the array.
*/
private final int[] _lengths;
/**
* The type of double array.
*/
private final DoubleArrayType> _arrayType;
/**
* If the array was retrieved from MATLAB.
*/
private final boolean _fromMatlab;
/**
* If the array is composed entirely of real values. If this is {@code true} then {@link #_imaginaryValues} will be
* {@code null}.
*/
private final boolean _isReal;
/**
* Constructs an array from data retrieved from MATLAB.
*
* @param real
* @param imaginary
* @param lengths
*/
MatlabNumericArray(double[] real, double[] imaginary, int[] lengths) {
_fromMatlab = true;
_realValues = real;
_imaginaryValues = imaginary;
_isReal = (imaginary == null);
_lengths = lengths;
_arrayType = DoubleArrayType.getInstance(lengths.length);
}
/**
* Constructs a numeric array from Java arrays that can be transferred to MATLAB. The {@code imaginary} array
* may be {@code null}, if so then this array will be real. References to the arrays passed in are not kept, and
* modifying the array data after this class has been constructed will have no effect. If the data is modified
* concurrently with this class's construction, problems may arise.
*
* The arrays may be jagged; however, MATLAB does not support jagged arrays and therefore the arrays will be treated
* as if they had uniform length for each dimension. For each dimension the maximum length is determined. If both
* the {@code real} and {@code imaginary} arrays are provided then the maximum length per dimension is determined
* across both arrays. For parts of the array that have a length less than the maximum length, {@code 0} will be
* used.
*
* @param
* @param type may not be {@code null}
* @param real may not be {@code null}
* @param imaginary may be {@code null}, if {@code null} then this array will be real
* @throws NullPointerException
*/
public MatlabNumericArray(DoubleArrayType type, T real, T imaginary) {
//Validate input
if (type == null) {
throw new NullPointerException("The type of the arrays may not be null.");
}
if (real == null) {
throw new NullPointerException("Real array may not be null.");
}
_fromMatlab = false;
_isReal = (imaginary == null);
//Store type
_arrayType = type;
//Determine lengths
_lengths = new int[type.getDimensions()];
int[] realLengths = computeBoundingLengths(real);
for (int i = 0; i < realLengths.length; i++) {
_lengths[i] = Math.max(_lengths[i], realLengths[i]);
}
if (imaginary != null) {
int[] imaginaryLengths = computeBoundingLengths(imaginary);
for (int i = 0; i < imaginaryLengths.length; i++) {
_lengths[i] = Math.max(_lengths[i], imaginaryLengths[i]);
}
}
//Linearize arrays
_realValues = linearize(real, _lengths);
if (imaginary != null) {
_imaginaryValues = linearize(imaginary, _lengths);
} else {
_imaginaryValues = null;
}
}
/**
* Convenience constructor, equivalent to {@code new MatlabNumericArray(DoubleArrayType.DIM_2, real, imaginary)}.
*
* @param real
* @param imaginary
* @throws NullPointerException
*/
public MatlabNumericArray(double[][] real, double[][] imaginary) {
this(DoubleArrayType.DIM_2, real, imaginary);
}
/**
* Convenience constructor, equivalent to {@code new MatlabNumericArray(DoubleArrayType.DIM_3, real, imaginary)}.
*
* @param real
* @param imaginary
* @throws NullPointerException
*/
public MatlabNumericArray(double[][][] real, double[][][] imaginary) {
this(DoubleArrayType.DIM_3, real, imaginary);
}
/**
* Convenience constructor, equivalent to {@code new MatlabNumericArray(DoubleArrayType.DIM_4, real, imaginary)}.
*
* @param real
* @param imaginary
* @throws NullPointerException
*/
public MatlabNumericArray(double[][][][] real, double[][][][] imaginary) {
this(DoubleArrayType.DIM_4, real, imaginary);
}
/**
* Computes the total size of an array with lengths specified by {@code lengths}.
*
* @param lengths
* @return
*/
private static int getTotalSize(int[] lengths) {
int size = 0;
for (int length : lengths) {
if (size == 0) {
size = length;
} else if (length != 0) {
size *= length;
}
}
return size;
}
/**
* Gets the real value at {@code linearIndex} treating this array as the underlying one dimensional array. This
* is equivalent to indexing into a MATLAB array with just one subscript.
*
* @param linearIndex
* @return real value at {@code linearIndex}
* @throws ArrayIndexOutOfBoundsException
*/
public double getRealValue(int linearIndex) {
return _realValues[linearIndex];
}
/**
* Gets the imaginary value at {@code linearIndex} treating this array as the underlying one dimensional array.
* This is equivalent to indexing into a MATLAB array with just one subscript.
*
* @param linearIndex
* @return imaginary value at {@code linearIndex}
* @throws ArrayIndexOutOfBoundsException
* @throws IllegalStateException if the array is real
*/
public double getImaginaryValue(int linearIndex) {
if (_isReal) {
throw new IllegalStateException("array is real");
}
return _imaginaryValues[linearIndex];
}
/**
* Gets the real value at the specified {@code indices}. The amount of indices provided must be the number of
* dimensions in the array.
*
* @param indices
* @return real value at {@code indices}
* @throws ArrayDimensionException if number of indices is not the number of dimensions
* @throws IndexOutOfBoundsException if the indices are out of bound
*/
public double getRealValue(int... indices) {
return this.getValue(_realValues, indices);
}
/**
* Gets the imaginary value at the specified {@code indices}. The amount of indices provided must be the number of
* dimensions in the array.
*
* @param indices
* @return imaginary value at {@code indices}
* @throws ArrayDimensionException if number of indices is not the number of dimensions
* @throws IndexOutOfBoundsException if the indices are out of bound
* @throws IllegalStateException if the array is real
*/
public double getImaginaryValue(int... indices) {
if (_isReal) {
throw new IllegalStateException("array is real");
}
return this.getValue(_imaginaryValues, indices);
}
private double getValue(double[] values, int... indices) throws ArrayDimensionException, ArrayIndexOutOfBoundsException {
double value;
if (indices.length == this.getDimensions()) {
//Check the indices are in bounds
for (int i = 0; i < indices.length; i++) {
if (indices[i] >= _lengths[i]) {
throw new IndexOutOfBoundsException("[" + indices[i] + "] is out of bounds for dimension " +
i + " where the length is " + _lengths[i]);
}
}
value = values[multidimensionalIndicesToLinearIndex(_lengths, indices)];
} else {
throw new ArrayDimensionException(_arrayType.getDimensions(), indices.length);
}
return value;
}
/**
* The number of dimensions this array has.
*
* @return number of dimensions
*/
public int getDimensions() {
return _arrayType.getDimensions();
}
/**
* Returns the lengths of each dimension with respect to their index. In MATLAB the first dimension (0 index in the
* returned integer array) is the row length. The second dimension is the column length. The third dimension and
* beyond are pages. The length of the returned array will be the number of dimensions returned by
* {@link #getDimensions()}.
*
* @return lengths
*/
public int[] getLengths() {
int[] lengthsCopy = new int[_lengths.length];
System.arraycopy(_lengths, 0, lengthsCopy, 0, _lengths.length);
return lengthsCopy;
}
/**
* The length of the underlying linear array.
*
* @return length
*/
public int getLength() {
return _realValues.length;
}
private T getAsJavaArray(DoubleArrayType type, double[] values) {
if (type.getDimensions() != _arrayType.getDimensions()) {
throw new ArrayDimensionException(_arrayType.getDimensions(), type.getDimensions());
}
return multidimensionalize(values, type._arrayClass, _lengths);
}
/**
* Returns a {@code double} array of type {@code T} that holds the real values from the MATLAB array.
*
* @param
* @param type
* @return
* @throws ArrayDimensionException if the array is not of the dimension specified by {@code type}
*/
public T getRealArray(DoubleArrayType type) {
return getAsJavaArray(type, _realValues);
}
/**
* Equivalent to {@code getRealArray(DoubleArrayType.DIM_2)}.
*
* @return
* @throws ArrayDimensionException if the array is not a two dimensional array
*/
public double[][] getRealArray2D() {
return this.getRealArray(DoubleArrayType.DIM_2);
}
/**
* Equivalent to {@code getRealArray(DoubleArrayType.DIM_3)}.
*
* @return
* @throws ArrayDimensionException if the array is not a three dimensional array
*/
public double[][][] getRealArray3D() {
return this.getRealArray(DoubleArrayType.DIM_3);
}
/**
* Equivalent to {@code getRealArray(DoubleArrayType.DIM_4)}.
*
* @return
* @throws ArrayDimensionException if the array is not a four dimensional array
*/
public double[][][][] getRealArray4D() {
return this.getRealArray(DoubleArrayType.DIM_4);
}
/**
* Returns a {@code double} array of type {@code T} that holds the imaginary values from the MATLAB array.
*
* @param
* @param type
* @return
* @throws ArrayDimensionException if the array is not of the dimension specified by {@code type}
* @throws IllegalStateException if the array is real
*/
public T getImaginaryArray(DoubleArrayType type) {
if (_isReal) {
throw new IllegalStateException("array is real");
}
return getAsJavaArray(type, _imaginaryValues);
}
/**
* Equivalent to {@code getImaginaryArray(DoubleArrayType.DIM_2)}.
*
* @return
* @throws ArrayDimensionException if the array is not a two dimensional array
* @throws IllegalStateException if the array is real
*/
public double[][] getImaginaryArray2D() {
return this.getImaginaryArray(DoubleArrayType.DIM_2);
}
/**
* Equivalent to {@code getImaginaryArray(DoubleArrayType.DIM_3)}.
*
* @return
* @throws ArrayDimensionException if the array is not a three dimensional array
* @throws IllegalStateException if the array is real
*/
public double[][][] getImaginaryArray3D() {
return this.getImaginaryArray(DoubleArrayType.DIM_3);
}
/**
* Equivalent to {@code getImaginaryArray(DoubleArrayType.DIM_4)}.
*
* @return
* @throws ArrayDimensionException if the array is not a four dimensional array
* @throws IllegalStateException if the array is real
*/
public double[][][][] getImaginaryArray4D() {
return this.getImaginaryArray(DoubleArrayType.DIM_4);
}
/**
* Returns {@code true} if the array has no imaginary values, {@code false} otherwise. Equivalent to the MATLAB
* {@code isreal} function.
*
* @return
*/
public boolean isReal() {
return _isReal;
}
/**
* Returns the underlying linear array of real values. Returns the actual array, not a copy.
*
* @return
*/
double[] getRealLinearArray() {
return _realValues;
}
/**
* Returns the underlying linear array of imaginary values. Returns the actual array, not a copy.
*
* @return
*/
double[] getImaginaryLinearArray() {
return _imaginaryValues;
}
/**
* Returns a brief description of this array. The exact details of this representation are unspecified and are
* subject to change.
*
* @return
*/
@Override
public String toString() {
return "[" + this.getClass() +
" dimensions=" + this.getDimensions() + "," +
" linearLength=" + this.getLength() + "," +
" lengths=" + Arrays.toString(_lengths) + "," +
" fromMATLAB=" + _fromMatlab + "]";
}
/**
* Multidimensional indices to linear index. Similar to MATLAB's (@code sub2ind} function.
*
* @param lengths the lengths of the array in each dimension
* @param indices
* @return
* @throws IllegalArgumentException thrown if the length of {@code lengths} and {@code indices} are not the same
*/
private static int multidimensionalIndicesToLinearIndex(int[] lengths, int[] indices) {
if (lengths.length != indices.length) {
throw new IllegalArgumentException("There must be an equal number of lengths [" + lengths.length + "] "
+ "and indices [" + indices.length + "]");
}
int linearIndex = 0;
int accumSize = 1;
for (int i = 0; i < lengths.length; i++) {
linearIndex += accumSize * indices[i];
accumSize *= lengths[i];
}
return linearIndex;
}
/**
* Creates a {@code double} array of type {@code T} with the length of each dimension specified by {@code lengths}.
* As the array is created it is populated with the values of {@code linearArray}.
*
* @param
* @param linearArray
* @param outputArrayType
* @param lengths
* @return
*/
private static T multidimensionalize(double[] linearArray, Class outputArrayType, int[] lengths) {
return multidimensionalize_internal(linearArray, outputArrayType, lengths, 0, new int[0]);
}
/**
* The real logic of the {@link #multidimensionalize(double[], java.lang.Class, int[])} method. This method
* recurs on itself, hence the need for the extra parameters. This method does not store state in any external
* variables.
*
* @param
* @param linearArray
* @param outputArrayType
* @param lengths
* @param indexIntoLengths should be {@code 0} initially
* @param currIndices should be an empty integer array initially
* @return
*/
@SuppressWarnings("unchecked")
private static T multidimensionalize_internal(double[] linearArray, Class outputArrayType, int[] lengths,
int indexIntoLengths, int[] currIndices) {
Class> arrayType = outputArrayType.getComponentType();
int arrayLength = lengths[indexIntoLengths];
T array = (T) Array.newInstance(arrayType, arrayLength);
//If what was created holds an array, then fill it
if (arrayType.isArray()) {
//If the array that was created holds the double array, double[]
if (arrayType.equals(double[].class)) {
//The index in the multidimensional array being created
int[] primitiveArrayIndices = new int[currIndices.length + 2];
System.arraycopy(currIndices, 0, primitiveArrayIndices, 0, currIndices.length);
//Iterate over the created array, placing a double[] array in each index
for (int i = 0; i < arrayLength; i++) {
primitiveArrayIndices[primitiveArrayIndices.length - 2] = i;
//Create the primitive array
double[] primitiveArray = new double[lengths[lengths.length - 1]];
//Fill the primitive array with values from the linear array
for (int j = 0; j < primitiveArray.length; j++) {
primitiveArrayIndices[primitiveArrayIndices.length - 1] = j;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, primitiveArrayIndices);
primitiveArray[j] = linearArray[linearIndex];
}
//Place primitive array into the enclosing array
Array.set(array, i, primitiveArray);
}
} else {
//Iterate over the created array, placing an array in each index (using recursion)
for (int i = 0; i < arrayLength; i++) {
int[] nextIndices = new int[currIndices.length + 1];
System.arraycopy(currIndices, 0, nextIndices, 0, currIndices.length);
nextIndices[nextIndices.length - 1] = i;
Object innerArray = multidimensionalize_internal(linearArray, arrayType, lengths,
indexIntoLengths + 1, nextIndices);
Array.set(array, i, innerArray);
}
}
}
//If a double[] was just created, then the original request was to create a one dimensional array
else {
System.arraycopy(linearArray, 0, array, 0, arrayLength);
}
return array;
}
/**
* Determines the maximum length for each dimension of the array.
*
* @param array
* @return
*/
private static int[] computeBoundingLengths(Object array) {
DoubleArrayType> type = DoubleArrayType.getInstanceUnsafe(array.getClass());
int[] maxLengths = new int[type.getDimensions()];
//The length of this array
int arrayLength = Array.getLength(array);
maxLengths[0] = arrayLength;
//If the array holds arrays as its entries
if (!array.getClass().getComponentType().equals(double.class)) {
//For each entry in the array
for (int i = 0; i < arrayLength; i++) {
//childLengths' information will be one index ahead of maxLengths
int[] childLengths = computeBoundingLengths(Array.get(array, i));
for (int j = 0; j < childLengths.length; j++) {
maxLengths[j + 1] = Math.max(maxLengths[j + 1], childLengths[j]);
}
}
}
return maxLengths;
}
/**
* Creates a linearized version of the {@code array} with maximum length in each dimension specified by
* {@code lengths}. No verification is performed that the dimensions of the array match the length of the lengths
* array.
*
* @param array
* @param lengths
* @return
*/
private static double[] linearize(Object array, int[] lengths) {
//Create linear array with equal size of the array
double[] linearArray = new double[getTotalSize(lengths)];
//Fill linearArray with values from array
linearize_internal(linearArray, array, lengths, new int[0]);
return linearArray;
}
/**
* Performs the linearization using recursion.
*
* @param linearArray array to be filled
* @param array source array
* @param lengths the lengths of the array for the initial array supplied before any recursion
* @param currIndices must initially be an empty integer array
*/
private static void linearize_internal(double[] linearArray, Object array, int[] lengths, int[] currIndices) {
//Base case
if (array.getClass().equals(double[].class)) {
int[] doubleArrayIndices = new int[currIndices.length + 1];
System.arraycopy(currIndices, 0, doubleArrayIndices, 0, currIndices.length);
//Fill linear array with contents of the double[] array
double[] doubleArray = (double[]) array;
for (int i = 0; i < doubleArray.length; i++) {
doubleArrayIndices[doubleArrayIndices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, doubleArrayIndices);
linearArray[linearIndex] = doubleArray[i];
}
} else {
int arrayLength = Array.getLength(array);
for (int i = 0; i < arrayLength; i++) {
int[] nextIndices = new int[currIndices.length + 1];
System.arraycopy(currIndices, 0, nextIndices, 0, currIndices.length);
nextIndices[nextIndices.length - 1] = i;
linearize_internal(linearArray, Array.get(array, i), lengths, nextIndices);
}
}
}
/**
* Represents attempting to retrieve or manipulate a MATLAB array as the wrong dimension.
*/
public static class ArrayDimensionException extends RuntimeException {
private static final long serialVersionUID = 0xC400L;
private final int _actualNumberOfDimensions;
private final int _usedAsNumberOfDimensions;
ArrayDimensionException(int actualNumDim, int usedAsNumDim) {
super("Array has " + actualNumDim + " dimension(s), it cannot be used as if it had " + usedAsNumDim +
" dimension(s).");
_actualNumberOfDimensions = actualNumDim;
_usedAsNumberOfDimensions = usedAsNumDim;
}
/**
* The actual number of dimensions the array has.
*
* @return
*/
public int getActualNumberOfDimensions() {
return _actualNumberOfDimensions;
}
/**
* The number of dimensions that were used when interacting with the array.
*
* @return
*/
public int getUsedNumberOfDimensions() {
return _usedAsNumberOfDimensions;
}
}
/**
* An array type of dimension 2 or greater which holds {@code double}s. Instances for dimensions 2 through 9 are
* available as {@code public static} fields.
*
* This class is unconditionally thread-safe.
*
* @param an array of 2 or more dimensions which holds {@code double}s
*/
public static final class DoubleArrayType {
/**
* Caches loaded {@code DoubleArrayType}s.
*/
@SuppressWarnings("rawtypes")
private static final Map, DoubleArrayType> CLASS_TO_ARRAY_TYPE = new ConcurrentHashMap, DoubleArrayType>();
/**
* Representation of {@code double[][]} class.
*/
public static final DoubleArrayType DIM_2 = getInstance(double[][].class);
/**
* Representation of {@code double[][][]} class.
*/
public static final DoubleArrayType DIM_3 = getInstance(double[][][].class);
/**
* Representation of {@code double[][][][]} class.
*/
public static final DoubleArrayType DIM_4 = getInstance(double[][][][].class);
/**
* Representation of {@code double[][][][][]} class.
*/
public static final DoubleArrayType DIM_5 = getInstance(double[][][][][].class);
/**
* Representation of {@code double[][][][][][]} class.
*/
public static final DoubleArrayType DIM_6 = getInstance(double[][][][][][].class);
/**
* Representation of {@code double[][][][][][][]} class.
*/
public static final DoubleArrayType DIM_7 = getInstance(double[][][][][][][].class);
/**
* Representation of {@code double[][][][][][][][]} class.
*/
public static final DoubleArrayType DIM_8 = getInstance(double[][][][][][][][].class);
/**
* Representation of {@code double[][][][][][][][][]} class.
*/
public static final DoubleArrayType DIM_9 = getInstance(double[][][][][][][][][].class);
/**
* The array class represented.
*/
private final Class _arrayClass;
/**
* The number of dimensions of the array type.
*/
private final int _numDimensions;
/**
* Constructs a representation of a multidimensional array of {@code double}s.
*
* @param arrayClass
* @throws IllegalArgumentException if the type is not an array holding {@code double}s
*/
private DoubleArrayType(Class arrayClass) {
if (!isDoubleArrayType(arrayClass)) {
throw new IllegalArgumentException(arrayClass + " does not hold doubles");
}
_arrayClass = arrayClass;
_numDimensions = getNumberOfDimensions(arrayClass);
}
/**
* Gets an instance of {@code DoubleArrayType} where {@code T} is the type of {@code arrayType}. {@code T}
* must be an array of 1 or more dimensions that holds {@code double}s. This is intended for getting array types
* in excess of 9 dimensions, as dimensions 2 through 9 are represented by constants {@code DIM_2 ... DIM_9}.
*
* Contrived example usage:
* {@code DoubleArrayType type3D = DoubleArrayType.getInstance(double[][][].class);}
*
* @param
* @param arrayType
*
* @return
*
* @throws IllegalArgumentException if the type is not an array holding {@code double}s or the type is of less
* than 2 dimensions
*/
public static DoubleArrayType getInstance(Class arrayType) {
if (arrayType.equals(double[].class)) {
throw new IllegalArgumentException(arrayType + " not supported, must be 2 or more dimensions");
}
return getInstanceUnsafe(arrayType);
}
/**
* Behaves the same as {@link #getInstance(java.lang.Class)} except that {@code double[]} is valid. This is
* needed by some of the recursive algorithms in {@code MatlabNumericArray}.
*/
@SuppressWarnings("unchecked")
static DoubleArrayType getInstanceUnsafe(Class arrayType) {
if (!CLASS_TO_ARRAY_TYPE.containsKey(arrayType)) {
DoubleArrayType type = new DoubleArrayType(arrayType);
CLASS_TO_ARRAY_TYPE.put(arrayType, type);
}
return CLASS_TO_ARRAY_TYPE.get(arrayType);
}
static DoubleArrayType> getInstance(int dimensions) {
DoubleArrayType> type;
//Construct the name of the class
StringBuilder className = new StringBuilder(1 + dimensions);
for (int i = 0; i < dimensions; i++) {
className.append('[');
}
className.append('D');
//Retrieve the class, and then getInstance the corresponding DoubleArrayType
try {
type = getInstanceUnsafe(Class.forName(className.toString()));
} catch (ClassNotFoundException e) {
type = null;
}
return type;
}
/**
* The number of dimensions of the array type.
*
* @return
*/
public int getDimensions() {
return _numDimensions;
}
/**
* The type of array. The array holds {@code double}s, and may be of any dimension 2 or greater.
*
* @return
*/
public Class getArrayClass() {
return _arrayClass;
}
/**
* If {@code type} is an array of one or more dimensions which holds doubles.
*
* @param type
* @return
*/
private static boolean isDoubleArrayType(Class> type) {
boolean isType;
if (type.isArray()) {
while (type.isArray()) {
type = type.getComponentType();
}
isType = type.equals(double.class);
} else {
isType = false;
}
return isType;
}
/**
* Returns the number of dimensions the array type has. If {@code type} is not a type of array then {@code 0}
* will be returned.
*
* @param type
* @return
*/
private static int getNumberOfDimensions(Class> type) {
int numDim = 0;
while (type.isArray()) {
numDim++;
type = type.getComponentType();
}
return numDim;
}
/**
* Returns a brief description of this double array type. The exact details of this representation are
* unspecified and are subject to change.
*
* @return
*/
@Override
public String toString() {
return "[" + this.getClass().getName() + " class=" + _arrayClass + ", dimensions=" + _numDimensions + "]";
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy