All Downloads are FREE. Search and download functionalities are using the official Maven repository.

matlabcontrol.link.ArrayLinearizer Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show newest version
/*
 * 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.link;

import static matlabcontrol.link.ArrayUtils.*;

import java.lang.reflect.Array;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabOperations;
import matlabcontrol.link.MatlabType.MatlabTypeSetter;

/**
 *
 * @since 4.2.0
 * @author Joshua Kaplan
 */
class ArrayLinearizer {
	static MatlabTypeSetter getSetter(Object array) {
		return new MultidimensionalPrimitiveArraySetter(array);
	}

	private static class MultidimensionalPrimitiveArraySetter implements MatlabTypeSetter {
		private static final long serialVersionUID = 7871972881461753065L;
		private final Object _linearArray;
		private final int[] _lengths;

		public MultidimensionalPrimitiveArraySetter(Object multidimensionalArray) {
			_lengths = computeBoundingDimensions(multidimensionalArray);
			_linearArray = linearize(multidimensionalArray, _lengths);
		}

		@Override
		public void setInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException {
			ops.setVariable(variableName, this);

			StringBuilder command = new StringBuilder();
			if (_lengths.length == 1) {
				command.append(variableName + " = reshape(" + variableName + ".getLinearArray(), 1, " + _lengths[0] + ");");
			} else {
				command.append(variableName + " = reshape(" + variableName + ".getLinearArray()");
				for (int length : _lengths) {
					command.append(", " + length);
				}
				command.append(");");
			}

			ops.eval(command.toString());
		}

		@SuppressWarnings("unused")
		// called in MATLAB by the script above
		public Object getLinearArray() {
			return _linearArray;
		}
	}

	/**
	 * Creates a linearized version of the {@code array}.
	 * 
	 * @param array a multidimensional primitive array
	 * @param lengths the bounding lengths of the array
	 * @return linear array
	 */
	static Object linearize(Object array, int[] lengths) {
		if (array == null || !array.getClass().isArray()) {
			throw new RuntimeException("provided object is not an array");
		}

		//Base component type of the array
		Class baseClass = getBaseComponentType(array.getClass());
		if (!baseClass.isPrimitive()) {
			throw new RuntimeException("array type is not a primitive, type: " + baseClass.getCanonicalName());
		}

		//Create linear array with size equal to that of the bounding lengths of the array
		int size = getNumberOfElements(lengths);
		Object linearArray = Array.newInstance(baseClass, size);

		//Fill linearArray with values from array
		@SuppressWarnings("rawtypes")
		ArrayFillOperation fillOperation = FILL_OPERATIONS.get(baseClass);
		linearize_internal(linearArray, array, fillOperation, lengths, 0, new int[lengths.length]);

		return linearArray;
	}

	/**
	 * Performs the linearization using recursion.
	 * 
	 * @param linearArray array to be filled
	 * @param srcArray source array
	 * @param fillOperation operation to read values from srcArray and write into linearArray
	 * @param lengths the lengths of the array for the initial array supplied before any recursion
	 * @param depth the level of recursion, initially {@code 0}
	 * @param indices must be the length of {@code lengths}
	 */
	@SuppressWarnings({"unchecked", "rawtypes"})
	private static void linearize_internal(Object linearArray, Object srcArray, ArrayFillOperation fillOperation,
			int[] lengths, int depth, int[] indices) {
		//Base case - array holding non-array elements
		if (!srcArray.getClass().getComponentType().isArray()) {
			fillOperation.fill(linearArray, srcArray, indices, lengths);
		} else {
			int arrayLength = Array.getLength(srcArray);
			for (int i = 0; i < arrayLength; i++) {
				indices[depth] = i;
				linearize_internal(linearArray, Array.get(srcArray, i), fillOperation, lengths, depth + 1, indices);
			}
		}
	}

	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 < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class ShortArrayFillOperation implements ArrayFillOperation {
		@Override
		public void fill(short[] dst, short[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class IntArrayFillOperation implements ArrayFillOperation {
		@Override
		public void fill(int[] dst, int[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class LongArrayFillOperation implements ArrayFillOperation {
		@Override
		public void fill(long[] dst, long[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class FloatArrayFillOperation implements ArrayFillOperation {
		@Override
		public void fill(float[] dst, float[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class DoubleArrayFillOperation implements ArrayFillOperation {
		@Override
		public void fill(double[] dst, double[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class BooleanArrayFillOperation implements ArrayFillOperation {
		@Override
		public void fill(boolean[] dst, boolean[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}

	private static class CharArrayFillOperation implements ArrayFillOperation {
		@Override
		public void fill(char[] dst, char[] src, int[] indices, int[] lengths) {
			for (int i = 0; i < src.length; i++) {
				indices[indices.length - 1] = i;
				int linearIndex = multidimensionalIndicesToLinearIndex(lengths, indices);
				dst[linearIndex] = src[i];
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy