org.eclipse.dataset.AbstractCompoundDataset.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.dataset.AbstractCompoundDataset.java

Source

/*-
 *******************************************************************************
 * Copyright (c) 2011, 2014 Diamond Light Source Ltd.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Peter Chang - initial API and implementation and/or initial documentation
 *******************************************************************************/

package org.eclipse.dataset;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;

/**
 * Generic container class for data that is compound in nature
 * 
 * Each subclass has an array of compound types, items of this array are composed of primitive types
 * 
 * Data items can be Complex, Vector, etc
 * 
 */
public abstract class AbstractCompoundDataset extends AbstractDataset implements CompoundDataset {
    // pin UID to base class
    private static final long serialVersionUID = Dataset.serialVersionUID;

    protected int isize; // number of elements per item

    @Override
    public int getElementsPerItem() {
        return isize;
    }

    @Override
    protected int get1DIndex(final int i) {
        int n = super.get1DIndex(i);
        return stride == null ? isize * n : n;
    }

    @Override
    protected int get1DIndex(final int i, final int j) {
        int n = super.get1DIndex(i, j);
        return stride == null ? isize * n : n;
    }

    @Override
    protected int get1DIndexFromShape(final int... n) {
        return isize * super.get1DIndexFromShape(n);
    }

    @Override
    public Dataset getUniqueItems() {
        throw new UnsupportedOperationException("Cannot sort compound datasets");
    }

    @Override
    public IndexIterator getIterator(final boolean withPosition) {
        if (stride != null)
            return new StrideIterator(isize, shape, stride, offset);
        return withPosition ? getSliceIterator(null, null, null) : new ContiguousIterator(size, isize);
    }

    /**
     * Get an iterator that picks out the chosen element from all items
     * @param element
     * @return an iterator
     */
    public IndexIterator getIterator(int element) {
        if (element < 0)
            element += isize;
        if (element < 0 || element > isize) {
            logger.error("Invalid choice of element: {}/{}", element, isize);
            throw new IllegalArgumentException("Invalid choice of element: " + element + "/" + isize);
        }
        final IndexIterator it = stride != null ? new StrideIterator(isize, shape, stride, offset)
                : new ContiguousIterator(size, isize);

        it.index += element;
        return it;
    }

    @Override
    public IndexIterator getSliceIterator(SliceND slice) {
        if (stride != null)
            return new StrideIterator(isize, shape, stride, offset, slice);

        return new SliceIterator(shape, size, isize, slice);
    }

    /**
     * Constructor required for serialisation.
     */
    public AbstractCompoundDataset() {
    }

    @Override
    public boolean equals(Object obj) {
        if (!super.equals(obj)) {
            return false;
        }
        CompoundDataset other = (CompoundDataset) obj;
        return isize == other.getElementsPerItem();
    }

    @Override
    public int hashCode() {
        return getHash();
    }

    @Override
    public CompoundDataset cast(boolean repeat, int dtype, int isize) {
        return (CompoundDataset) super.cast(repeat, dtype, isize);
    }

    @Override
    public CompoundDataset cast(int dtype) {
        return (CompoundDataset) super.cast(dtype);
    }

    @Override
    abstract public AbstractCompoundDataset clone();

    @Override
    public CompoundDataset flatten() {
        return (CompoundDataset) super.flatten();
    }

    @Override
    public CompoundDataset getBy1DIndex(IntegerDataset index) {
        return (CompoundDataset) super.getBy1DIndex(index);
    }

    @Override
    public CompoundDataset getByBoolean(Dataset selection) {
        return (CompoundDataset) super.getByBoolean(selection);
    }

    @Override
    public CompoundDataset getByIndexes(Object... indexes) {
        return (CompoundDataset) super.getByIndexes(indexes);
    }

    @Override
    public CompoundDataset getSlice(IMonitor mon, int[] start, int[] stop, int[] step) {
        return (CompoundDataset) super.getSlice(mon, start, stop, step);
    }

    @Override
    public CompoundDataset getSlice(IMonitor mon, Slice... slice) {
        return (CompoundDataset) super.getSlice(mon, slice);
    }

    @Override
    public CompoundDataset getSlice(IMonitor mon, SliceND slice) {
        return (CompoundDataset) super.getSlice(mon, slice);
    }

    @Override
    public CompoundDataset getSlice(int[] start, int[] stop, int[] step) {
        return (CompoundDataset) super.getSlice(start, stop, step);
    }

    @Override
    public CompoundDataset getSlice(Slice... slice) {
        return (CompoundDataset) super.getSlice(slice);
    }

    @Override
    public CompoundDataset getSlice(SliceND slice) {
        return (CompoundDataset) super.getSlice(slice);
    }

    @Override
    abstract public AbstractCompoundDataset getSlice(SliceIterator iterator);

    @Override
    public CompoundDataset getSliceView(int[] start, int[] stop, int[] step) {
        return (CompoundDataset) super.getSliceView(start, stop, step);
    }

    @Override
    public CompoundDataset getSliceView(Slice... slice) {
        return (CompoundDataset) super.getSliceView(slice);
    }

    @Override
    public CompoundDataset getSliceView(SliceND slice) {
        return (CompoundDataset) super.getSliceView(slice);
    }

    @Override
    public CompoundDataset getTransposedView(int... axes) {
        return (CompoundDataset) super.getTransposedView(axes);
    }

    @Override
    abstract public AbstractCompoundDataset getView();

    @Override
    public CompoundDataset ifloorDivide(Object o) {
        return (CompoundDataset) super.ifloorDivide(o);
    }

    @Override
    public CompoundDataset mean(boolean ignoreNaNs, int axis) {
        return (CompoundDataset) super.mean(ignoreNaNs, axis);
    }

    @Override
    public CompoundDataset mean(int axis) {
        return (CompoundDataset) super.mean(axis);
    }

    @Override
    public CompoundDataset peakToPeak(int axis) {
        return (CompoundDataset) super.peakToPeak(axis);
    }

    @Override
    public CompoundDataset product(int axis) {
        return (CompoundDataset) super.product(axis);
    }

    @Override
    public CompoundDataset reshape(int... shape) {
        return (CompoundDataset) super.reshape(shape);
    }

    @Override
    public CompoundDataset rootMeanSquare(int axis) {
        return (CompoundDataset) super.rootMeanSquare(axis);
    }

    @Override
    public CompoundDataset setSlice(Object obj, int[] start, int[] stop, int[] step) {
        return (CompoundDataset) super.setSlice(obj, start, stop, step);
    }

    @Override
    public CompoundDataset setSlice(Object object, Slice... slice) {
        return (CompoundDataset) super.setSlice(object, slice);
    }

    @Override
    public CompoundDataset sort(Integer axis) {
        throw new UnsupportedOperationException("Cannot sort dataset");
    }

    @Override
    public CompoundDataset squeezeEnds() {
        return (CompoundDataset) super.squeezeEnds();
    }

    @Override
    public CompoundDataset squeeze() {
        return (CompoundDataset) super.squeeze();
    }

    @Override
    public CompoundDataset squeeze(boolean onlyFromEnd) {
        return (CompoundDataset) super.squeeze(onlyFromEnd);
    }

    @Override
    public CompoundDataset stdDeviation(int axis) {
        return (CompoundDataset) super.stdDeviation(axis);
    }

    @Override
    public CompoundDataset sum(boolean ignoreNaNs, int axis) {
        return (CompoundDataset) super.sum(ignoreNaNs, axis);
    }

    @Override
    public CompoundDataset sum(int axis) {
        return (CompoundDataset) super.sum(axis);
    }

    @Override
    public CompoundDataset swapAxes(int axis1, int axis2) {
        return (CompoundDataset) super.swapAxes(axis1, axis2);
    }

    @Override
    public synchronized CompoundDataset synchronizedCopy() {
        return clone();
    }

    @Override
    public CompoundDataset transpose(int... axes) {
        return (CompoundDataset) super.transpose(axes);
    }

    @Override
    public CompoundDataset typedProduct(int dtype, int axis) {
        return (CompoundDataset) super.typedProduct(dtype, axis);
    }

    @Override
    public CompoundDataset typedSum(int dtype, int axis) {
        return (CompoundDataset) super.typedSum(dtype, axis);
    }

    @Override
    public CompoundDataset variance(int axis) {
        return (CompoundDataset) super.variance(axis);
    }

    public static double[] toDoubleArray(final Object b, final int itemSize) {
        double[] result = null;

        // ensure array is of given length
        if (b instanceof Number) {
            result = new double[itemSize];
            double val = ((Number) b).doubleValue();
            for (int i = 0; i < itemSize; i++)
                result[i] = val;
        } else if (b instanceof double[]) {
            result = (double[]) b;
            if (result.length < itemSize) {
                result = new double[itemSize];
                int ilen = result.length;
                for (int i = 0; i < ilen; i++)
                    result[i] = ((double[]) b)[i];
            }
        } else if (b instanceof List<?>) {
            result = new double[itemSize];
            List<?> jl = (List<?>) b;
            int ilen = jl.size();
            if (ilen > 0 && !(jl.get(0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++) {
                result[i] = toReal(jl.get(i));
            }
        } else if (b.getClass().isArray()) {
            result = new double[itemSize];
            int ilen = Array.getLength(b);
            if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++)
                result[i] = ((Number) Array.get(b, i)).doubleValue();
        } else if (b instanceof Complex) {
            if (itemSize > 2) {
                logger.error("Complex number will not fit in compound dataset");
                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
            }
            Complex cb = (Complex) b;
            switch (itemSize) {
            default:
            case 0:
                break;
            case 1:
                result = new double[] { cb.getReal() };
                break;
            case 2:
                result = new double[] { cb.getReal(), cb.getImaginary() };
                break;
            }
        } else if (b instanceof Dataset) {
            Dataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toDoubleArray(db.getObjectAbs(0), itemSize);
        } else if (b instanceof IDataset) {
            IDataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toDoubleArray(db.getObject(new int[db.getRank()]), itemSize);
        }

        return result;
    }

    public static float[] toFloatArray(final Object b, final int itemSize) {
        float[] result = null;

        if (b instanceof Number) {
            result = new float[itemSize];
            float val = ((Number) b).floatValue();
            for (int i = 0; i < itemSize; i++)
                result[i] = val;
        } else if (b instanceof float[]) {
            result = (float[]) b;
            if (result.length < itemSize) {
                result = new float[itemSize];
                int ilen = result.length;
                for (int i = 0; i < ilen; i++)
                    result[i] = ((float[]) b)[i];
            }
        } else if (b instanceof List<?>) {
            result = new float[itemSize];
            List<?> jl = (List<?>) b;
            int ilen = jl.size();
            if (ilen > 0 && !(jl.get(0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++) {
                result[i] = (float) toReal(jl.get(i));
            }
        } else if (b.getClass().isArray()) {
            result = new float[itemSize];
            int ilen = Array.getLength(b);
            if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++)
                result[i] = ((Number) Array.get(b, i)).floatValue();
        } else if (b instanceof Complex) {
            if (itemSize > 2) {
                logger.error("Complex number will not fit in compound dataset");
                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
            }
            Complex cb = (Complex) b;
            switch (itemSize) {
            default:
            case 0:
                break;
            case 1:
                result = new float[] { (float) cb.getReal() };
                break;
            case 2:
                result = new float[] { (float) cb.getReal(), (float) cb.getImaginary() };
                break;
            }
        } else if (b instanceof Dataset) {
            Dataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toFloatArray(db.getObjectAbs(0), itemSize);
        } else if (b instanceof IDataset) {
            IDataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toFloatArray(db.getObject(new int[db.getRank()]), itemSize);
        }

        return result;
    }

    public static long[] toLongArray(final Object b, final int itemSize) {
        long[] result = null;

        if (b instanceof Number) {
            result = new long[itemSize];
            long val = ((Number) b).longValue();
            for (int i = 0; i < itemSize; i++)
                result[i] = val;
        } else if (b instanceof long[]) {
            result = (long[]) b;
            if (result.length < itemSize) {
                result = new long[itemSize];
                int ilen = result.length;
                for (int i = 0; i < ilen; i++)
                    result[i] = ((long[]) b)[i];
            }
        } else if (b instanceof List<?>) {
            result = new long[itemSize];
            List<?> jl = (List<?>) b;
            int ilen = jl.size();
            if (ilen > 0 && !(jl.get(0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++) {
                result[i] = toLong(jl.get(i));
            }
        } else if (b.getClass().isArray()) {
            result = new long[itemSize];
            int ilen = Array.getLength(b);
            if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++)
                result[i] = ((Number) Array.get(b, i)).longValue();
        } else if (b instanceof Complex) {
            if (itemSize > 2) {
                logger.error("Complex number will not fit in compound dataset");
                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
            }
            Complex cb = (Complex) b;
            switch (itemSize) {
            default:
            case 0:
                break;
            case 1:
                result = new long[] { (long) cb.getReal() };
                break;
            case 2:
                result = new long[] { (long) cb.getReal(), (long) cb.getImaginary() };
                break;
            }
        } else if (b instanceof Dataset) {
            Dataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toLongArray(db.getObjectAbs(0), itemSize);
        } else if (b instanceof IDataset) {
            IDataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toLongArray(db.getObject(new int[db.getRank()]), itemSize);
        }

        return result;
    }

    public static int[] toIntegerArray(final Object b, final int itemSize) {
        int[] result = null;

        if (b instanceof Number) {
            result = new int[itemSize];
            int val = ((Number) b).intValue();
            for (int i = 0; i < itemSize; i++)
                result[i] = val;
        } else if (b instanceof int[]) {
            result = (int[]) b;
            if (result.length < itemSize) {
                result = new int[itemSize];
                int ilen = result.length;
                for (int i = 0; i < ilen; i++)
                    result[i] = ((int[]) b)[i];
            }
        } else if (b instanceof List<?>) {
            result = new int[itemSize];
            List<?> jl = (List<?>) b;
            int ilen = jl.size();
            if (ilen > 0 && !(jl.get(0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++) {
                result[i] = (int) toLong(jl.get(i));
            }
        } else if (b.getClass().isArray()) {
            result = new int[itemSize];
            int ilen = Array.getLength(b);
            if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++)
                result[i] = (int) ((Number) Array.get(b, i)).longValue();
        } else if (b instanceof Complex) {
            if (itemSize > 2) {
                logger.error("Complex number will not fit in compound dataset");
                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
            }
            Complex cb = (Complex) b;
            switch (itemSize) {
            default:
            case 0:
                break;
            case 1:
                result = new int[] { (int) cb.getReal() };
                break;
            case 2:
                result = new int[] { (int) cb.getReal(), (int) cb.getImaginary() };
                break;
            }
        } else if (b instanceof Dataset) {
            Dataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toIntegerArray(db.getObjectAbs(0), itemSize);
        } else if (b instanceof IDataset) {
            IDataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toIntegerArray(db.getObject(new int[db.getRank()]), itemSize);
        }

        return result;
    }

    public static short[] toShortArray(final Object b, final int itemSize) {
        short[] result = null;

        if (b instanceof Number) {
            result = new short[itemSize];
            short val = ((Number) b).shortValue();
            for (int i = 0; i < itemSize; i++)
                result[i] = val;
        } else if (b instanceof short[]) {
            result = (short[]) b;
            if (result.length < itemSize) {
                result = new short[itemSize];
                int ilen = result.length;
                for (int i = 0; i < ilen; i++)
                    result[i] = ((short[]) b)[i];
            }
        } else if (b instanceof List<?>) {
            result = new short[itemSize];
            List<?> jl = (List<?>) b;
            int ilen = jl.size();
            if (ilen > 0 && !(jl.get(0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++) {
                result[i] = (short) toLong(jl.get(i));
            }
        } else if (b.getClass().isArray()) {
            result = new short[itemSize];
            int ilen = Array.getLength(b);
            if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++)
                result[i] = (short) ((Number) Array.get(b, i)).longValue();
        } else if (b instanceof Complex) {
            if (itemSize > 2) {
                logger.error("Complex number will not fit in compound dataset");
                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
            }
            Complex cb = (Complex) b;
            switch (itemSize) {
            default:
            case 0:
                break;
            case 1:
                result = new short[] { (short) cb.getReal() };
                break;
            case 2:
                result = new short[] { (short) cb.getReal(), (short) cb.getImaginary() };
                break;
            }
        } else if (b instanceof Dataset) {
            Dataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toShortArray(db.getObjectAbs(0), itemSize);
        } else if (b instanceof IDataset) {
            IDataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toShortArray(db.getObject(new int[db.getRank()]), itemSize);
        }

        return result;
    }

    public static byte[] toByteArray(final Object b, final int itemSize) {
        byte[] result = null;

        if (b instanceof Number) {
            result = new byte[itemSize];
            final byte val = ((Number) b).byteValue();
            for (int i = 0; i < itemSize; i++)
                result[i] = val;
        } else if (b instanceof byte[]) {
            result = (byte[]) b;
            if (result.length < itemSize) {
                result = new byte[itemSize];
                int ilen = result.length;
                for (int i = 0; i < ilen; i++)
                    result[i] = ((byte[]) b)[i];
            }
        } else if (b instanceof List<?>) {
            result = new byte[itemSize];
            List<?> jl = (List<?>) b;
            int ilen = jl.size();
            if (ilen > 0 && !(jl.get(0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++) {
                result[i] = (byte) toLong(jl.get(i));
            }
        } else if (b.getClass().isArray()) {
            result = new byte[itemSize];
            int ilen = Array.getLength(b);
            if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
                logger.error("Given array was not of a numerical primitive type");
                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
            }
            ilen = Math.min(itemSize, ilen);
            for (int i = 0; i < ilen; i++)
                result[i] = (byte) ((Number) Array.get(b, i)).longValue();
        } else if (b instanceof Complex) {
            if (itemSize > 2) {
                logger.error("Complex number will not fit in compound dataset");
                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
            }
            Complex cb = (Complex) b;
            switch (itemSize) {
            default:
            case 0:
                break;
            case 1:
                result = new byte[] { (byte) cb.getReal() };
                break;
            case 2:
                result = new byte[] { (byte) cb.getReal(), (byte) cb.getImaginary() };
                break;
            }
        } else if (b instanceof Dataset) {
            Dataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toByteArray(db.getObjectAbs(0), itemSize);
        } else if (b instanceof IDataset) {
            IDataset db = (Dataset) b;
            if (db.getSize() != 1) {
                logger.error("Given dataset must have only one item");
                throw new IllegalArgumentException("Given dataset must have only one item");
            }
            return toByteArray(db.getObject(new int[db.getRank()]), itemSize);
        }

        return result;
    }

    abstract protected double getFirstValue(final int i);

    abstract protected double getFirstValue(final int i, final int j);

    abstract protected double getFirstValue(final int... pos);

    @Override
    public boolean getBoolean(final int i) {
        return getFirstValue(i) != 0;
    }

    @Override
    public boolean getBoolean(final int i, final int j) {
        return getFirstValue(i, j) != 0;
    }

    @Override
    public boolean getBoolean(final int... pos) {
        return getFirstValue(pos) != 0;
    }

    @Override
    public byte getByte(final int i) {
        return (byte) getFirstValue(i);
    }

    @Override
    public byte getByte(final int i, final int j) {
        return (byte) getFirstValue(i, j);
    }

    @Override
    public byte getByte(final int... pos) {
        return (byte) getFirstValue(pos);
    }

    @Override
    public short getShort(final int i) {
        return (short) getFirstValue(i);
    }

    @Override
    public short getShort(final int i, final int j) {
        return (short) getFirstValue(i, j);
    }

    @Override
    public short getShort(final int... pos) {
        return (short) getFirstValue(pos);
    }

    @Override
    public int getInt(final int i) {
        return (int) getFirstValue(i);
    }

    @Override
    public int getInt(final int i, final int j) {
        return (int) getFirstValue(i, j);
    }

    @Override
    public int getInt(final int... pos) {
        return (int) getFirstValue(pos);
    }

    @Override
    public long getLong(final int i) {
        return (long) getFirstValue(i);
    }

    @Override
    public long getLong(final int i, final int j) {
        return (long) getFirstValue(i, j);
    }

    @Override
    public long getLong(final int... pos) {
        return (long) getFirstValue(pos);
    }

    @Override
    public float getFloat(final int i) {
        return (float) getFirstValue(i);
    }

    @Override
    public float getFloat(final int i, final int j) {
        return (float) getFirstValue(i, j);
    }

    @Override
    public float getFloat(final int... pos) {
        return (float) getFirstValue(pos);
    }

    @Override
    public double getDouble(final int i) {
        return getFirstValue(i);
    }

    @Override
    public double getDouble(final int i, final int j) {
        return getFirstValue(i, j);
    }

    @Override
    public double getDouble(final int... pos) {
        return getFirstValue(pos);
    }

    @Override
    public void getDoubleArray(final double[] darray, final int i) {
        getDoubleArrayAbs(get1DIndex(i), darray);
    }

    @Override
    public void getDoubleArray(final double[] darray, final int i, final int j) {
        getDoubleArrayAbs(get1DIndex(i, j), darray);
    }

    @Override
    public void getDoubleArray(final double[] darray, final int... pos) {
        getDoubleArrayAbs(get1DIndex(pos), darray);
    }

    @Override
    protected Number fromDoubleToNumber(double x) {
        return null;
    }

    /**
     * Calculate minimum and maximum for a dataset
     */
    protected void calculateHash() {
        IndexIterator iter = getIterator();
        double hash = 0;
        while (iter.hasNext()) {
            for (int j = 0; j < isize; j++) {
                final double val = getElementDoubleAbs(iter.index + j);
                if (Double.isInfinite(val) || Double.isNaN(val)) {
                    hash = (hash * 19) % Integer.MAX_VALUE;
                } else {
                    hash = (hash * 19 + val) % Integer.MAX_VALUE;
                }
            }
        }

        int ihash = ((int) hash) * 19 + getDtype() * 17 + getElementsPerItem();
        setStoredValue(STORE_SHAPELESS_HASH, ihash);
    }

    private int getHash() {
        Object value = getStoredValue(STORE_HASH);
        if (value == null) {
            value = getStoredValue(STORE_SHAPELESS_HASH);
            if (value == null) {
                calculateHash();
                value = getStoredValue(STORE_SHAPELESS_HASH);
            }

            int ihash = (Integer) value;
            int rank = shape.length;
            for (int i = 0; i < rank; i++) {
                ihash = ihash * 17 + shape[i];
            }
            storedValues.put(STORE_HASH, ihash);
            return ihash;
        }

        return (Integer) value;
    }

    @Override
    protected void calculateSummaryStats(boolean ignoreNaNs, final boolean ignoreInfs, String name) {
        IndexIterator iter = getIterator();
        SummaryStatistics[] stats = new SummaryStatistics[isize];
        for (int i = 0; i < isize; i++)
            stats[i] = new SummaryStatistics();

        double[] vals = new double[isize];
        while (iter.hasNext()) {
            boolean okay = true;
            for (int i = 0; i < isize; i++) {
                final double val = getElementDoubleAbs(iter.index + i);
                if (ignoreNaNs && Double.isNaN(val)) {
                    okay = false;
                    break;
                }
                if (ignoreInfs && Double.isInfinite(val)) {
                    okay = false;
                    break;
                }
                vals[i] = val;
            }
            if (!okay)
                continue;
            for (int i = 0; i < isize; i++)
                stats[i].addValue(vals[i]);
        }

        // now all the calculations are done, add the values into store
        if (storedValues == null)
            storedValues = new HashMap<String, Object>();
        else
            storedValues.clear();

        for (int i = 0; i < isize; i++)
            storedValues.put(name + i, stats[i]);
    }

    @Override
    protected void calculateSummaryStats(final boolean ignoreNaNs, final boolean ignoreInfs, final int axis) {
        int rank = getRank();

        int[] oshape = getShape();
        int alen = oshape[axis];
        oshape[axis] = 1;

        int[] nshape = squeezeShape(oshape, false);

        IntegerDataset count = new IntegerDataset(nshape);
        CompoundDoubleDataset sum = new CompoundDoubleDataset(isize, nshape);
        CompoundDoubleDataset mean = new CompoundDoubleDataset(isize, nshape);
        CompoundDoubleDataset var = new CompoundDoubleDataset(isize, nshape);

        IndexIterator qiter = count.getIterator(true);
        int[] qpos = qiter.getPos();
        int[] spos = oshape;
        double[] darray = new double[isize];

        while (qiter.hasNext()) {
            int i = 0;
            for (; i < axis; i++) {
                spos[i] = qpos[i];
            }
            spos[i++] = 0;
            for (; i < rank; i++) {
                spos[i] = qpos[i - 1];
            }

            final SummaryStatistics[] stats = new SummaryStatistics[isize];
            for (int k = 0; k < isize; k++) {
                stats[k] = new SummaryStatistics();
            }
            for (int j = 0; j < alen; j++) {
                spos[axis] = j;
                getDoubleArray(darray, spos);
                boolean skip = false;
                for (int k = 0; k < isize; k++) {
                    double v = darray[k];
                    if (ignoreNaNs && Double.isNaN(v)) {
                        skip = true;
                        break;
                    }
                    if (ignoreInfs && Double.isInfinite(v)) {
                        skip = true;
                        break;
                    }
                }
                if (!skip)
                    for (int k = 0; k < isize; k++) {
                        stats[k].addValue(darray[k]);
                    }
            }

            count.setAbs(qiter.index, (int) stats[0].getN());

            for (int k = 0; k < isize; k++) {
                darray[k] = stats[k].getSum();
            }
            sum.set(darray, qpos);
            for (int k = 0; k < isize; k++) {
                darray[k] = stats[k].getMean();
            }
            mean.set(darray, qpos);
            for (int k = 0; k < isize; k++) {
                darray[k] = stats[k].getVariance();
            }
            var.set(darray, qpos);
        }
        setStoredValue(storeName(ignoreNaNs, ignoreInfs, STORE_COUNT + "-" + axis), count);
        storedValues.put(storeName(ignoreNaNs, ignoreInfs, STORE_SUM + "-" + axis), sum);
        storedValues.put(storeName(ignoreNaNs, ignoreInfs, STORE_MEAN + "-" + axis), mean);
        storedValues.put(storeName(ignoreNaNs, ignoreInfs, STORE_VAR + "-" + axis), var);
    }

    @Override
    public Number max(boolean... switches) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public CompoundDataset max(boolean ignoreNaNs, int axis) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public CompoundDataset max(int axis) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public Number min(boolean... switches) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public CompoundDataset min(boolean ignoreNaNs, int axis) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public CompoundDataset min(int axis) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public Number positiveMin(boolean ignoreInvalids) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public Number positiveMax(boolean ignoreNaNs, boolean ignoreInfs) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public Number positiveMin(boolean ignoreNaNs, boolean ignoreInfs) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public int[] maxPos(boolean ignoreNaNs) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    @Override
    public int[] minPos(boolean ignoreNaNs) {
        logger.error("Cannot compare compound numbers");
        throw new UnsupportedOperationException("Cannot compare compound numbers");
    }

    protected final static String STORE_STATS_ITEM_NAME = STORE_STATS + "=";

    @Override
    public double[] maxItem() {
        final String n = storeName(false, STORE_STATS_ITEM_NAME);
        if (isize < 1)
            return new double[0];
        if (getStoredValue(n + 0) == null) {
            calculateSummaryStats(false, false, n);
        }

        double[] results = new double[isize];
        for (int i = 0; i < isize; i++) {
            results[i] = ((SummaryStatistics) storedValues.get(n + i)).getMax();
        }
        return results;
    }

    @Override
    public double[] minItem() {
        final String n = storeName(false, STORE_STATS_ITEM_NAME);
        if (isize < 1)
            return new double[0];
        if (getStoredValue(n + 0) == null) {
            calculateSummaryStats(false, false, n);
        }

        double[] results = new double[isize];
        for (int i = 0; i < isize; i++) {
            results[i] = ((SummaryStatistics) storedValues.get(n + i)).getMin();
        }
        return results;
    }

    @Override
    public Object sum() {
        final String n = storeName(false, STORE_STATS_ITEM_NAME);
        if (isize < 1)
            return new double[0];
        if (getStoredValue(n + 0) == null) {
            calculateSummaryStats(false, false, n);
        }

        double[] results = new double[isize];
        for (int i = 0; i < isize; i++) {
            results[i] = ((SummaryStatistics) storedValues.get(n + i)).getSum();
        }
        return results;
    }

    private static Object fromDoublesToBiggestPrimitives(double[] x, int dtype) {
        switch (dtype) {
        case Dataset.BOOL:
        case Dataset.INT8:
        case Dataset.INT16:
        case Dataset.INT32:
            int[] i32 = new int[x.length];
            for (int i = 0; i < x.length; i++)
                i32[i] = (int) (long) x[i];
            return i32;
        case Dataset.INT64:
            long[] i64 = new long[x.length];
            for (int i = 0; i < x.length; i++)
                i64[i] = (long) x[i];
            return i64;
        case Dataset.FLOAT32:
            float[] f32 = new float[x.length];
            for (int i = 0; i < x.length; i++)
                f32[i] = (float) x[i];
            return f32;
        case Dataset.FLOAT64:
            return x;
        }
        return null;
    }

    @Override
    public Object typedSum(int dtype) {
        return fromDoublesToBiggestPrimitives((double[]) sum(), dtype);
    }

    @Override
    public Object mean(boolean... switches) {
        final String n = storeName(false, STORE_STATS_ITEM_NAME);
        if (isize < 1)
            return new double[0];
        if (getStoredValue(n + 0) == null) {
            calculateSummaryStats(false, false, n);
        }

        double[] results = new double[isize];
        for (int i = 0; i < isize; i++) {
            results[i] = ((SummaryStatistics) storedValues.get(n + i)).getMean();
        }
        return results;
    }

    @Override
    public Number variance() {
        final String n = storeName(false, STORE_STATS_ITEM_NAME);
        if (isize < 1)
            return Double.NaN;
        if (getStoredValue(n + 0) == null) {
            calculateSummaryStats(false, false, n);
        }

        double result = 0;
        for (int i = 0; i < isize; i++)
            result += ((SummaryStatistics) storedValues.get(n + i)).getVariance();
        return result;
    }

    @Override
    public Number rootMeanSquare() {
        final String n = storeName(false, STORE_STATS_ITEM_NAME);
        if (isize < 1)
            return Double.NaN;
        if (getStoredValue(n + 0) == null) {
            calculateSummaryStats(false, false, n);
        }

        double result = 0;
        for (int i = 0; i < isize; i++) {
            final SummaryStatistics stats = (SummaryStatistics) storedValues.get(n + i);
            final double mean = stats.getMean();
            result += stats.getVariance() + mean * mean;
        }
        return Math.sqrt(result);
    }

    @Override
    public CompoundDataset getError() {
        Dataset ed = getInternalError();
        if (ed == null)
            return null;

        if (ed.getSize() != size || ed.getElementsPerItem() != isize) {
            CompoundDataset errors = new CompoundDoubleDataset(isize, shape);
            errors.setSlice(ed);
            return errors;
        }
        return (CompoundDataset) ed;
    }

    @Override
    public double getError(final int i) {
        return calcError(getInternalErrorArray(true, i));
    }

    @Override
    public double getError(final int i, final int j) {
        return calcError(getInternalErrorArray(true, i, j));
    }

    @Override
    public double getError(final int... pos) {
        return calcError(getInternalErrorArray(true, pos));
    }

    private double calcError(double[] es) {
        if (es == null)
            return 0;

        // assume elements are independent
        double e = 0;
        for (int k = 0; k < isize; k++) {
            e += es[k];
        }

        return Math.sqrt(e);
    }

    @Override
    public double[] getErrorArray(final int i) {
        return getInternalErrorArray(false, i);
    }

    @Override
    public double[] getErrorArray(final int i, final int j) {
        return getInternalErrorArray(false, i, j);
    }

    @Override
    public double[] getErrorArray(final int... pos) {
        return getInternalErrorArray(false, pos);
    }

    private double[] getInternalErrorArray(final boolean squared, final int i) {
        Dataset sed = squared ? getInternalSquaredError() : getInternalError();
        if (sed == null)
            return null;

        BroadcastStride bs = (BroadcastStride) getStoredValue(STORE_BROADCAST);
        int n = bs.get1DIndex(i);
        double[] es = new double[isize];
        if (sed instanceof CompoundDoubleDataset) {
            ((CompoundDoubleDataset) sed).getDoubleArrayAbs(n, es);
            if (sed.getElementsPerItem() != isize) { // ensure error is broadcasted
                Arrays.fill(es, es[0]);
            }
        } else {
            Arrays.fill(es, ((DoubleDataset) sed).getElementDoubleAbs(n));
        }
        return es;
    }

    private double[] getInternalErrorArray(final boolean squared, final int i, final int j) {
        Dataset sed = squared ? getInternalSquaredError() : getInternalError();
        if (sed == null)
            return null;

        BroadcastStride bs = (BroadcastStride) getStoredValue(STORE_BROADCAST);
        int n = bs.get1DIndex(i, j);
        double[] es = new double[isize];
        if (sed instanceof CompoundDoubleDataset) {
            ((CompoundDoubleDataset) sed).getDoubleArrayAbs(n, es);
            if (sed.getElementsPerItem() != isize) { // ensure error is broadcasted
                Arrays.fill(es, es[0]);
            }
        } else {
            Arrays.fill(es, ((DoubleDataset) sed).getElementDoubleAbs(n));
        }
        return es;
    }

    private double[] getInternalErrorArray(final boolean squared, final int... pos) {
        Dataset sed = squared ? getInternalSquaredError() : getInternalError();
        if (sed == null)
            return null;

        BroadcastStride bs = (BroadcastStride) getStoredValue(STORE_BROADCAST);
        int n = bs.get1DIndex(pos);
        double[] es = new double[isize];
        if (sed instanceof CompoundDoubleDataset) {
            ((CompoundDoubleDataset) sed).getDoubleArrayAbs(n, es);
            if (sed.getElementsPerItem() != isize) { // ensure error is broadcasted
                Arrays.fill(es, es[0]);
            }
        } else {
            Arrays.fill(es, ((DoubleDataset) sed).getElementDoubleAbs(n));
        }
        return es;
    }
}