org.n52.matlab.control.link.ArrayMultidimensionalizer Maven / Gradle / Ivy
The newest version!
package org.n52.matlab.control.link;
/*
* Copyright (c) 2013, Joshua Kaplan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* - Neither the name of matlabcontrol nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.HashMap;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import org.n52.matlab.control.MatlabOperations;
import org.n52.matlab.control.MatlabInvocationException;
import org.n52.matlab.control.link.MatlabType.MatlabTypeGetter;
import static org.n52.matlab.control.link.ArrayUtils.*;
/**
*
* @since 4.2.0
* @author Joshua Kaplan
*/
class ArrayMultidimensionalizer
{
static class PrimitiveArrayGetter implements MatlabTypeGetter
{
private int[] _lengths;
private Object _array;
private boolean _retreived = false;
private final boolean _getRealPart;
private final boolean _keepLinear;
public PrimitiveArrayGetter(boolean realPart, boolean keepLinear)
{
_getRealPart = realPart;
_keepLinear = keepLinear;
}
public boolean isRealPart()
{
return _getRealPart;
}
public int[] getLengths()
{
return _lengths;
}
/**
* May be null if this represents the imaginary part and the array has no imaginary values or the array was
* empty.
*
* @return
*/
@Override
public Object retrieve()
{
//Validate
if(!_retreived)
{
throw new IllegalStateException("array has not yet been retrieved");
}
Object array = _array;
if(_array != null && !_keepLinear)
{
array = multidimensionalize(_array, _lengths);
}
return array;
}
@Override
public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException
{
//Retrieve lengths of array
double[] size = (double[]) ops.returningEval("size(" + variableName + ");", 1)[0];
_lengths = new int[size.length];
for(int i = 0; i < size.length; i++)
{
_lengths[i] = (int) size[i];
}
//Retrieve array
String name = (String) ops.returningEval("genvarname('" + variableName + "_getter', who);", 1)[0];
ops.setVariable(name, this);
try
{
if(_getRealPart)
{
ops.eval(name + ".setArray(reshape(" + variableName + ", 1, []));");
}
else
{
//If the array has an imaginary part, retrieve it
boolean isReal = ((boolean[]) ops.returningEval("isreal(" + variableName + ");", 1)[0])[0];
if(!isReal)
{
ops.eval(name + ".setArray(imag(reshape(" + variableName + ", 1, [])));");
}
}
}
finally
{
ops.eval("clear " + name);
}
_retreived = true;
}
//The following methods are to be called only from MATLAB to pass in the array
public void setArray(byte[] array)
{
_array = array;
}
public void setArray(short[] array)
{
_array = array;
}
public void setArray(int[] array)
{
_array = array;
}
public void setArray(long[] array)
{
_array = array;
}
public void setArray(float[] array)
{
_array = array;
}
public void setArray(double[] array)
{
_array = array;
}
public void setArray(char[] array)
{
_array = array;
}
public void setArray(boolean[] array)
{
_array = array;
}
}
/**
* Creates a rectangular multidimensional array from {@code linearArray} with the length of each dimension specified
* by {@code lengths}. The length of the array must equal the total size specified by {@code lengths}.
*
* @param
* @param linearArray a primitive linear array
* @param lengths length of each dimension
* @return multidimensional array
*/
static Object multidimensionalize(Object linearArray, int[] lengths)
{
//Validate primitive single dimension array
if(linearArray == null || !linearArray.getClass().isArray() &&
!linearArray.getClass().getComponentType().isPrimitive())
{
throw new RuntimeException("linear array must be a single dimension primitive array");
}
//Validate lengths
if(getNumberOfElements(lengths) != Array.getLength(linearArray))
{
throw new RuntimeException("linear array's length does not match the total size of the provided " +
"multidimensional lengths\n"+
"Linear Array Length: " + Array.getLength(linearArray) + "\n" +
"Multidimensional Lengths: " + Arrays.toString(lengths) + "\n" +
"Multidimensional Total Size: " + getNumberOfElements(lengths));
}
Class> componentType = linearArray.getClass().getComponentType();
Class> outputArrayType = getArrayClass(componentType, lengths.length);
ArrayFillOperation> fillOperation = FILL_OPERATIONS.get(componentType);
return multidimensionalize_internal(linearArray, outputArrayType, fillOperation, lengths, 0, new int[lengths.length]);
}
/**
* The real logic of the multidimensionalize. This method recurs on itself, hence the need for the extra parameters.
* This method does not store state in any external variables.
*
* @param linearArray
* @param outputArrayType
* @param fillOperation operation used to fill in single dimension pieces of the array
* @param lengths
* @param depth should be {@code 0} initially
* @param indices must be the length of {@code lengths}
* @return
*/
private static Object multidimensionalize_internal(Object linearArray, Class> outputArrayType,
ArrayFillOperation fillOperation, int[] lengths, int depth, int[] indices)
{
Class> componentType = outputArrayType.getComponentType();
int arrayLength = lengths[depth];
Object array = Array.newInstance(componentType, arrayLength);
//If what was created holds an array, then fill it
if(componentType.isArray())
{
//If the array that was created holds the primitive array: double[], int[], boolean[] etc.
if(componentType.getComponentType().isPrimitive())
{
//Iterate over the created array, placing a primitive array in each index
for(int i = 0; i < arrayLength; i++)
{
indices[indices.length - 2] = i;
//Create the primitive array
Object primitiveArray = Array.newInstance(componentType.getComponentType(), lengths[lengths.length - 1]);
//Fill the primitive array with values from the linear array
fillOperation.fill(primitiveArray, linearArray, indices, lengths);
//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++)
{
indices[depth] = i;
Object innerArray = multidimensionalize_internal(linearArray, componentType,
fillOperation, lengths, depth + 1, indices);
Array.set(array, i, innerArray);
}
}
}
//If the componentType is not an array, then the original request was to create a one dimensional array
else
{
System.arraycopy(linearArray, 0, array, 0, arrayLength);
}
return array;
}
private static final Map, ArrayFillOperation>> FILL_OPERATIONS;
static
{
Map, ArrayFillOperation>> map = new HashMap, ArrayFillOperation>>();
map.put(byte.class, new ByteArrayFillOperation());
map.put(short.class, new ShortArrayFillOperation());
map.put(int.class, new IntArrayFillOperation());
map.put(long.class, new LongArrayFillOperation());
map.put(float.class, new FloatArrayFillOperation());
map.put(double.class, new DoubleArrayFillOperation());
map.put(boolean.class, new BooleanArrayFillOperation());
map.put(char.class, new CharArrayFillOperation());
FILL_OPERATIONS = Collections.unmodifiableMap(map);
}
private static interface ArrayFillOperation
{
public void fill(T dst, T src, int[] indices, int[] lengths);
}
private static class ByteArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(byte[] dst, byte[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
private static class ShortArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(short[] dst, short[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
private static class IntArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(int[] dst, int[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
private static class LongArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(long[] dst, long[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
private static class FloatArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(float[] dst, float[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
private static class DoubleArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(double[] dst, double[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
private static class BooleanArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(boolean[] dst, boolean[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
private static class CharArrayFillOperation implements ArrayFillOperation
{
@Override
public void fill(char[] dst, char[] src, int[] indices, int[] lengths)
{
for(int i = 0; i < dst.length; i++)
{
indices[indices.length - 1] = i;
int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
dst[i] = src[linearIndex];
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy