From 9c386518a49b161c49a16ba86cdc44078346c93e Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Mon, 15 Sep 2008 06:47:19 +0000
Subject: [PATCH] add: classes for numerical multi-dimensional arrays

SVN: 8286
---
 .../systemsx/cisd/common/array/MDArray.java   | 199 ++++++++++++++++++
 .../cisd/common/array/MDByteArray.java        | 156 ++++++++++++++
 .../cisd/common/array/MDDoubleArray.java      | 156 ++++++++++++++
 .../cisd/common/array/MDFloatArray.java       | 156 ++++++++++++++
 .../cisd/common/array/MDIntArray.java         | 156 ++++++++++++++
 .../cisd/common/array/MDLongArray.java        | 156 ++++++++++++++
 .../cisd/common/array/MDShortArray.java       | 156 ++++++++++++++
 .../cisd/common/array/MDArraytest.java        |  92 ++++++++
 8 files changed, 1227 insertions(+)
 create mode 100644 common/source/java/ch/systemsx/cisd/common/array/MDArray.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/array/MDByteArray.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/array/MDDoubleArray.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/array/MDFloatArray.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/array/MDIntArray.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/array/MDLongArray.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/array/MDShortArray.java
 create mode 100644 common/sourceTest/java/ch/systemsx/cisd/common/array/MDArraytest.java

diff --git a/common/source/java/ch/systemsx/cisd/common/array/MDArray.java b/common/source/java/ch/systemsx/cisd/common/array/MDArray.java
new file mode 100644
index 00000000000..29eacad2110
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/array/MDArray.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+/**
+ * Base class of a multi-dimensional array. The <var>shape</var> of an array is provided separately
+ * to the data as a <code>int[]</code>.
+ * 
+ * @author Bernd Rinn
+ */
+public abstract class MDArray<T>
+{
+
+    protected final int[] shape;
+
+    protected MDArray(int[] shape)
+    {
+        assert shape != null;
+
+        this.shape = shape;
+    }
+
+    /**
+     * Returns the rank of the array.
+     */
+    public int rank()
+    {
+        return shape.length;
+    }
+
+    /**
+     * Returns the extent of the array along its <var>dim</var>-th axis.
+     */
+    public int size(int dim)
+    {
+        assert dim < shape.length;
+
+        return shape[dim];
+    }
+
+    /**
+     * Returns a copy of the shape (dimensions) of the multi-dimensional array.
+     */
+    public int[] shape()
+    {
+        return shape.clone();
+    }
+
+    /**
+     * Returns a copy of the shape (dimensions) of the multi-dimensional array as
+     * <code>long[]</code>.
+     */
+    public long[] longShape()
+    {
+        final long[] shapeCopy = new long[shape.length];
+        for (int i = 0; i < shapeCopy.length; ++i)
+        {
+            shapeCopy[i] = shape[i];
+        }
+        return shapeCopy;
+    }
+
+    /**
+     * Returns the number of elements in the array.
+     */
+    public abstract int size();
+
+    /**
+     * Return an object which has the same value as the element of the array specified by
+     * <var>indices</var>.
+     */
+    public abstract T getAsObject(int[] indices);
+
+    /**
+     * Sets the element of the array specified by <var>indices</var> to the particular
+     * <var>value</var>.
+     */
+    public abstract void setToObject(int[] indices, T value);
+
+    /**
+     * Computes the linear index for the multi-dimensional <var>indices</var> provided.
+     */
+    protected int computeIndex(int[] indices)
+    {
+        assert indices != null;
+        assert indices.length == shape.length;
+
+        int index = indices[0];
+        for (int i = 1; i < indices.length; ++i)
+        {
+            index = index * shape[i] + indices[i];
+        }
+        return index;
+    }
+
+    /**
+     * Converts the <var>shape</var> from <code>long[]</code> to <code>int[]</code>.
+     */
+    public static int[] toInt(final long[] shape)
+    {
+        assert shape != null;
+
+        final int[] result = new int[shape.length];
+        for (int i = 0; i < result.length; ++i)
+        {
+            result[i] = (int) shape[i];
+            if (result[i] != shape[i])
+            {
+                throw new IllegalArgumentException("Dimension " + i + "  is too large (" + shape[i]
+                        + ")");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts the <var>shape</var> from <code>int[]</code> to <code>long[]</code>.
+     */
+    public static long[] toLong(final int[] shape)
+    {
+        assert shape != null;
+
+        final long[] result = new long[shape.length];
+        for (int i = 0; i < result.length; ++i)
+        {
+            result[i] = shape[i];
+        }
+        return result;
+    }
+
+    /**
+     * Returns the one-dimensional length of the multi-dimensional array defined by
+     * <var>shape</var>.
+     * 
+     * @throws IllegalArgumentException If <var>shape</var> overflow the <code>int</code> type.
+     */
+    public static int getLength(final int[] shape)
+    {
+        assert shape != null;
+
+        if (shape.length == 0)
+        {
+            return 0;
+        }
+        long length = shape[0];
+        for (int i = 1; i < shape.length; ++i)
+        {
+            length *= shape[i];
+        }
+        int intLength = (int) length;
+        if (length != intLength)
+        {
+            throw new IllegalArgumentException("Length is too large (" + length + ")");
+        }
+        return intLength;
+    }
+
+    /**
+     * Returns the one-dimensional length of the multi-dimensional array defined by
+     * <var>shape</var>.
+     * 
+     * @throws IllegalArgumentException If <var>shape</var> overflow the <code>int</code> type.
+     */
+    public static int getLength(final long[] shape)
+    {
+        assert shape != null;
+
+        if (shape.length == 0) // NULL data space needs to be treated differently
+        {
+            return 0;
+        }
+        long length = shape[0];
+        for (int i = 1; i < shape.length; ++i)
+        {
+            length *= shape[i];
+        }
+        int intLength = (int) length;
+        if (length != intLength)
+        {
+            throw new IllegalArgumentException("Length is too large (" + length + ")");
+        }
+        return intLength;
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/array/MDByteArray.java b/common/source/java/ch/systemsx/cisd/common/array/MDByteArray.java
new file mode 100644
index 00000000000..7971598145b
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/array/MDByteArray.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+import java.util.Arrays;
+
+/**
+ * A multi-dimensional <code>byte</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDByteArray extends MDArray<Byte>
+{
+    private final byte[] flattenedArray;
+
+    public MDByteArray(long[] dimensions)
+    {
+        this(new byte[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDByteArray(byte[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDByteArray(byte[] flattenedArray, long[] dimensions, boolean checkDimensions)
+    {
+        this(flattenedArray, MDArray.toInt(dimensions), checkDimensions);
+    }
+
+    public MDByteArray(int[] dimensions)
+    {
+        this(new byte[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDByteArray(byte[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDByteArray(byte[] flattenedArray, int[] shape, boolean checkDimensions)
+    {
+        super(shape);
+        assert flattenedArray != null;
+
+        if (checkDimensions)
+        {
+            final int expectedLength = getLength(shape);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    @Override
+    public int size()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Byte getAsObject(int[] indices)
+    {
+        return getValue(indices);
+    }
+
+    @Override
+    public void setToObject(int[] indices, Byte value)
+    {
+        setValue(indices, value);
+    }
+
+    /**
+     * Returns the array in flattened form. Changes to the returned object will change the
+     * multi-dimensional array directly.
+     */
+    public byte[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public byte getValue(int[] indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+    
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void setValue(int[] indices, byte value)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(flattenedArray);
+        result = prime * result + Arrays.hashCode(shape);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDByteArray other = (MDByteArray) obj;
+        if (Arrays.equals(flattenedArray, other.flattenedArray) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(shape, other.shape) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/array/MDDoubleArray.java b/common/source/java/ch/systemsx/cisd/common/array/MDDoubleArray.java
new file mode 100644
index 00000000000..9eb1f2ca52d
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/array/MDDoubleArray.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+import java.util.Arrays;
+
+/**
+ * A multi-dimensional <code>double</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDDoubleArray extends MDArray<Double>
+{
+    private final double[] flattenedArray;
+
+    public MDDoubleArray(long[] dimensions)
+    {
+        this(new double[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDDoubleArray(double[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDDoubleArray(double[] flattenedArray, long[] dimensions, boolean checkDimensions)
+    {
+        this(flattenedArray, MDArray.toInt(dimensions), checkDimensions);
+    }
+
+    public MDDoubleArray(int[] dimensions)
+    {
+        this(new double[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDDoubleArray(double[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDDoubleArray(double[] flattenedArray, int[] shape, boolean checkDimensions)
+    {
+        super(shape);
+        assert flattenedArray != null;
+
+        if (checkDimensions)
+        {
+            final int expectedLength = getLength(shape);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    @Override
+    public int size()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Double getAsObject(int[] indices)
+    {
+        return getValue(indices);
+    }
+
+    @Override
+    public void setToObject(int[] indices, Double value)
+    {
+        setValue(indices, value);
+    }
+
+    /**
+     * Returns the array in flattened form. Changes to the returned object will change the
+     * multi-dimensional array directly.
+     */
+    public double[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public double getValue(int[] indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+    
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void setValue(int[] indices, double value)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(flattenedArray);
+        result = prime * result + Arrays.hashCode(shape);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDDoubleArray other = (MDDoubleArray) obj;
+        if (Arrays.equals(flattenedArray, other.flattenedArray) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(shape, other.shape) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/array/MDFloatArray.java b/common/source/java/ch/systemsx/cisd/common/array/MDFloatArray.java
new file mode 100644
index 00000000000..b8c462e84c6
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/array/MDFloatArray.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+import java.util.Arrays;
+
+/**
+ * A multi-dimensional <code>float</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDFloatArray extends MDArray<Float>
+{
+    private final float[] flattenedArray;
+
+    public MDFloatArray(long[] dimensions)
+    {
+        this(new float[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDFloatArray(float[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDFloatArray(float[] flattenedArray, long[] dimensions, boolean checkDimensions)
+    {
+        this(flattenedArray, MDArray.toInt(dimensions), checkDimensions);
+    }
+
+    public MDFloatArray(int[] dimensions)
+    {
+        this(new float[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDFloatArray(float[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDFloatArray(float[] flattenedArray, int[] shape, boolean checkDimensions)
+    {
+        super(shape);
+        assert flattenedArray != null;
+
+        if (checkDimensions)
+        {
+            final int expectedLength = getLength(shape);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    @Override
+    public int size()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Float getAsObject(int[] indices)
+    {
+        return getValue(indices);
+    }
+
+    @Override
+    public void setToObject(int[] indices, Float value)
+    {
+        setValue(indices, value);
+    }
+
+    /**
+     * Returns the array in flattened form. Changes to the returned object will change the
+     * multi-dimensional array directly.
+     */
+    public float[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public float getValue(int[] indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+    
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void setValue(int[] indices, float value)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(flattenedArray);
+        result = prime * result + Arrays.hashCode(shape);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDFloatArray other = (MDFloatArray) obj;
+        if (Arrays.equals(flattenedArray, other.flattenedArray) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(shape, other.shape) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/array/MDIntArray.java b/common/source/java/ch/systemsx/cisd/common/array/MDIntArray.java
new file mode 100644
index 00000000000..6b81423ee52
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/array/MDIntArray.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+import java.util.Arrays;
+
+/**
+ * A multi-dimensional <code>int</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDIntArray extends MDArray<Integer>
+{
+    private final int[] flattenedArray;
+
+    public MDIntArray(long[] dimensions)
+    {
+        this(new int[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDIntArray(int[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDIntArray(int[] flattenedArray, long[] dimensions, boolean checkDimensions)
+    {
+        this(flattenedArray, MDArray.toInt(dimensions), checkDimensions);
+    }
+
+    public MDIntArray(int[] dimensions)
+    {
+        this(new int[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDIntArray(int[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDIntArray(int[] flattenedArray, int[] shape, boolean checkDimensions)
+    {
+        super(shape);
+        assert flattenedArray != null;
+
+        if (checkDimensions)
+        {
+            final int expectedLength = getLength(shape);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    @Override
+    public int size()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Integer getAsObject(int[] indices)
+    {
+        return getValue(indices);
+    }
+
+    @Override
+    public void setToObject(int[] indices, Integer value)
+    {
+        setValue(indices, value);
+    }
+
+    /**
+     * Returns the array in flattened form. Changes to the returned object will change the
+     * multi-dimensional array directly.
+     */
+    public int[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public int getValue(int[] indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+    
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void setValue(int[] indices, int value)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(flattenedArray);
+        result = prime * result + Arrays.hashCode(shape);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDIntArray other = (MDIntArray) obj;
+        if (Arrays.equals(flattenedArray, other.flattenedArray) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(shape, other.shape) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/array/MDLongArray.java b/common/source/java/ch/systemsx/cisd/common/array/MDLongArray.java
new file mode 100644
index 00000000000..63252c9047a
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/array/MDLongArray.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+import java.util.Arrays;
+
+/**
+ * A multi-dimensional <code>long</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDLongArray extends MDArray<Long>
+{
+    private final long[] flattenedArray;
+
+    public MDLongArray(long[] dimensions)
+    {
+        this(new long[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDLongArray(long[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDLongArray(long[] flattenedArray, long[] dimensions, boolean checkDimensions)
+    {
+        this(flattenedArray, MDArray.toInt(dimensions), checkDimensions);
+    }
+
+    public MDLongArray(int[] dimensions)
+    {
+        this(new long[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDLongArray(long[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDLongArray(long[] flattenedArray, int[] shape, boolean checkDimensions)
+    {
+        super(shape);
+        assert flattenedArray != null;
+
+        if (checkDimensions)
+        {
+            final int expectedLength = getLength(shape);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    @Override
+    public int size()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Long getAsObject(int[] indices)
+    {
+        return getValue(indices);
+    }
+
+    @Override
+    public void setToObject(int[] indices, Long value)
+    {
+        setValue(indices, value);
+    }
+
+    /**
+     * Returns the array in flattened form. Changes to the returned object will change the
+     * multi-dimensional array directly.
+     */
+    public long[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public long getValue(int[] indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+    
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void setValue(int[] indices, long value)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(flattenedArray);
+        result = prime * result + Arrays.hashCode(shape);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDLongArray other = (MDLongArray) obj;
+        if (Arrays.equals(flattenedArray, other.flattenedArray) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(shape, other.shape) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/array/MDShortArray.java b/common/source/java/ch/systemsx/cisd/common/array/MDShortArray.java
new file mode 100644
index 00000000000..c3181947f41
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/array/MDShortArray.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+import java.util.Arrays;
+
+/**
+ * A multi-dimensional <code>short</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDShortArray extends MDArray<Short>
+{
+    private final short[] flattenedArray;
+
+    public MDShortArray(long[] dimensions)
+    {
+        this(new short[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDShortArray(short[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDShortArray(short[] flattenedArray, long[] dimensions, boolean checkDimensions)
+    {
+        this(flattenedArray, MDArray.toInt(dimensions), checkDimensions);
+    }
+
+    public MDShortArray(int[] dimensions)
+    {
+        this(new short[getLength(dimensions)], dimensions, true);
+    }
+
+    public MDShortArray(short[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    public MDShortArray(short[] flattenedArray, int[] shape, boolean checkDimensions)
+    {
+        super(shape);
+        assert flattenedArray != null;
+
+        if (checkDimensions)
+        {
+            final int expectedLength = getLength(shape);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    @Override
+    public int size()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Short getAsObject(int[] indices)
+    {
+        return getValue(indices);
+    }
+
+    @Override
+    public void setToObject(int[] indices, Short value)
+    {
+        setValue(indices, value);
+    }
+
+    /**
+     * Returns the array in flattened form. Changes to the returned object will change the
+     * multi-dimensional array directly.
+     */
+    public short[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public short getValue(int[] indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+    
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void setValue(int[] indices, short value)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(flattenedArray);
+        result = prime * result + Arrays.hashCode(shape);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDShortArray other = (MDShortArray) obj;
+        if (Arrays.equals(flattenedArray, other.flattenedArray) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(shape, other.shape) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/array/MDArraytest.java b/common/sourceTest/java/ch/systemsx/cisd/common/array/MDArraytest.java
new file mode 100644
index 00000000000..bf4d685fec8
--- /dev/null
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/array/MDArraytest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.array;
+
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+
+import static org.testng.AssertJUnit.*;
+
+/**
+ * Test cases for {@link MDArray}.
+ *
+ * @author Bernd Rinn
+ */
+public class MDArraytest
+{
+    
+    static class TestMDArray extends MDArray<Void>
+    {
+        protected TestMDArray(int[] shape)
+        {
+            super(shape);
+            // TODO Auto-generated constructor stub
+        }
+
+        @Override
+        public Void getAsObject(int[] indices)
+        {
+            return null;
+        }
+
+        @Override
+        public void setToObject(int[] indices, Void value)
+        {
+        }
+
+        @Override
+        public int size()
+        {
+            return 0;
+        }
+    }
+
+    @Test
+    public void testGetLength()
+    {
+        assertEquals(0, MDArray.getLength(new int[] { 0 }));
+        assertEquals(1, MDArray.getLength(new int[] { 1 }));
+        assertEquals(15, MDArray.getLength(new int[] { 5, 3 }));
+        assertEquals(1, MDArray.getLength(new int[] { 1, 1, 1 }));
+        assertEquals(8, MDArray.getLength(new int[] { 2, 2, 2 }));
+        assertEquals(2, MDArray.getLength(new int[] { 1, 1, 2 }));
+        assertEquals(2, MDArray.getLength(new int[] { 1, 2, 1 }));
+        assertEquals(2, MDArray.getLength(new int[] { 2, 1, 1 }));
+        assertEquals(50, MDArray.getLength(new int[] { 10, 1, 5 }));
+        assertEquals(50, MDArray.getLength(new long[] { 10, 1, 5 }));
+    }
+    
+    @Test
+    public void testToInt()
+    {
+        assertTrue(Arrays.equals(new int[] { 1, 2, 3 }, MDArray.toInt(new long[] { 1, 2, 3 })));
+        assertTrue(Arrays.equals(new int[] { }, MDArray.toInt(new long[] { })));
+    }
+    
+    @Test
+    public void testComputeIndex()
+    {
+        TestMDArray array;
+        array = new TestMDArray(new int[] { 33 });
+        assertEquals(17, array.computeIndex(new int[] { 17 }));
+        array = new TestMDArray(new int[] { 100, 10 });
+        assertEquals(10 * 42 + 17, array.computeIndex(new int[] { 42, 17 }));
+        array = new TestMDArray(new int[] { 2, 7, 3 });
+        assertEquals(3 * 7 * 1 + 3 * 2 + 3, array.computeIndex(new int[] { 1, 2, 3 }));
+    }
+}
-- 
GitLab