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

ucar.ma2.Array Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */
package ucar.ma2;

import javax.annotation.Nonnull;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.nio.*;

/**
 * Superclass for implementations of multidimensional arrays. An Array has a classType which gives
 * the Class of its elements, and a shape which describes the number of elements in each index.
 * The rank is the number of indices. A scalar Array has rank = 0. An
 * Array may have arbitrary rank. The Array size is the total number of elements, which must be less than
 * 2^31 (about 2x10^9).
 * 

* Actual data storage is done with Java 1D arrays and stride index calculations. * This makes our Arrays rectangular, i.e. no "ragged arrays" where different elements * can have different lengths as in Java multidimensional arrays, which are arrays of arrays. *

* Each primitive Java type (boolean, byte, char, short, int, long, float, double) has a corresponding concrete * implementation, e.g. ArrayBoolean, ArrayDouble. Reference types are all implemented using the ArrayObject class, * with the exceptions of the reference types that correspond to the primitive types, eg Double.class is mapped to * double.class. *

* For efficiency, each Array type implementation has concrete subclasses for ranks 0-7, eg ArrayDouble.D0 is a double * array of rank 0, ArrayDouble.D1 is a double array of rank 1, etc. These type and rank specific classes are convenient * to work with when you know the type and rank of the Array. Ranks greater than 7 are handled by the type-specific * superclass e.g. ArrayDouble. The Array class itself is used for fully general handling of any type and rank array. * Use the Array.factory() methods to create Arrays in a general way. *

* The stride index calculations allow logical views to be efficiently implemented, eg subset, transpose, slice, etc. * These views use the same data storage as the original Array they are derived from. The index stride calculations are * equally efficient for any composition of logical views. *

* The type, shape and backing storage of an Array are immutable. * The data itself is read or written using an Index or an IndexIterator, which stores any needed state information * for efficient traversal. This makes use of Arrays thread-safe (as long as you dont share the Index or IndexIterator) * except for the possibility of non-atomic read/write on long/doubles. If this is the case, you should probably * synchronize your calls. Presumably 64-bit CPUs will make those operations atomic also. * * @author caron * @see Index * @see IndexIterator */ public abstract class Array { /** * Generate new Array with given dataType and shape and zeroed storage. * * @param dataType instance of DataType. * @param shape shape of the array. * @return new Array or Array.D if 0 <= rank <= 7. */ static public Array factory(DataType dataType, int[] shape) { return factory(dataType, Index.factory(shape), null); } /** * Generate new Array with given dataType, shape, storage. * * @param dataType DataType, eg DataType.DOUBLE. * @param shape shape of the array. * @param storage primitive array of correct type * @return new Array or Array.D if 0 <= rank <= 7. * @throws ClassCastException wrong storage type */ static public Array factory(DataType dataType, int[] shape, Object storage) { return factory(dataType, Index.factory(shape), storage); } /* generate new Array with given type, index and storage */ static public Array factory(DataType dtype, Index index, Object storage) { switch (dtype) { case DOUBLE: return ArrayDouble.factory(index, (double[]) storage); case FLOAT: return ArrayFloat.factory(index, (float[]) storage); case CHAR: return ArrayChar.factory(index, (char[]) storage); case BOOLEAN: return ArrayBoolean.factory(index, (boolean[]) storage); case ENUM4: case UINT: case INT: return ArrayInt.factory(index, dtype.isUnsigned(), (int[]) storage); case ENUM2: case USHORT: case SHORT: return ArrayShort.factory(index, dtype.isUnsigned(), (short[]) storage); case ENUM1: case UBYTE: case BYTE: return ArrayByte.factory(index, dtype.isUnsigned(), (byte[]) storage); case ULONG: case LONG: return ArrayLong.factory(index, dtype.isUnsigned(), (long[]) storage); case STRING: return ArrayObject.factory(dtype, String.class, false, index, (Object[]) storage); case STRUCTURE: return ArrayObject.factory(dtype, StructureData.class, false, index, (Object[]) storage); case SEQUENCE: return ArrayObject.factory(dtype, StructureDataIterator.class, false, index, (Object[]) storage); case OPAQUE: return ArrayObject.factory(dtype, ByteBuffer.class, false, index, (Object[]) storage); } throw new RuntimeException("Cant use this method for datatype "+dtype); // used for VLEN ?? //default: // return ArrayObject.factory(DataType.OBJECT, Object.class, index, (Object[]) storage); // LOOK dont know the object class // } } /** * Make a vlen array * @param shape the outer shape, ie excluding the vlen dimension * @param storage must be an Array type. must not be null * @return ArrayObject */ static public Array makeVlenArray(int[] shape, @Nonnull Array[] storage) { Index index = Index.factory(shape); return ArrayObject.factory(storage[0].getDataType(), storage[0].getClass(), true, index, storage); } /** * Generate new Array with given type, shape, storage. * This should be package private, but is exposed for efficiency. * Normally use factory( Class classType, int [] shape) instead. * storage must be 1D array of type classType. * storage.length must equal product of shapes * storage data needs to be in canonical order * * @param classType element class type, eg double.class. Corresponding Object types like Double.class are * mapped to double.class. Any reference types use ArrayObject. * @param shape array shape * @param storage 1D java array of type classType, except object types like Double.class are mapped to * their corresponding primitive type, eg double.class. * @return Array of given type, shape and storage * @throws IllegalArgumentException storage.length != product of shapes * @throws ClassCastException wrong storage type */ static public Array makeObjectArray(DataType dtype, Class classType, int[] shape, Object storage) { Index index = Index.factory(shape); return ArrayObject.factory(dtype, classType, false, index, (Object[]) storage); } /** * Generate new Array with given type and shape and an Index that always return 0. * * @param dtype data type * @param shape shape of the array. * @param storage primitive array of correct type of length 1 * @return new Array or Array.D if 0 <= rank <= 7. */ static public Array factoryConstant(DataType dtype, int[] shape, Object storage) { Index index = new IndexConstant(shape); // cant go though the factory, must call the general constructor switch (dtype) { case BOOLEAN: return new ArrayBoolean(index, (boolean[]) storage); case BYTE: return new ArrayByte(index, false, (byte[]) storage); case CHAR: return new ArrayChar(index, (char[]) storage); case SHORT: return new ArrayShort(index, false, (short[]) storage); case INT: return new ArrayInt(index, false, (int[]) storage); case LONG: return new ArrayLong(index, false, (long[]) storage); case FLOAT: return new ArrayFloat(index, (float[]) storage); case DOUBLE: return new ArrayDouble(index, (double[]) storage); case ENUM1: case UBYTE: return new ArrayByte(index, true, (byte[]) storage); case ENUM2: case USHORT: return new ArrayShort(index, true, (short[]) storage); case ENUM4: case UINT: return new ArrayInt(index, true, (int[]) storage); case ULONG: return new ArrayLong(index, true, (long[]) storage); case STRING: return new ArrayObject(dtype, String.class, false, index, (Object[]) storage); case STRUCTURE: return new ArrayObject(dtype, StructureData.class, false, index, (Object[]) storage); case SEQUENCE: return new ArrayObject(dtype, StructureDataIterator.class, false, index, (Object[]) storage); case OPAQUE: return new ArrayObject(dtype, ByteBuffer.class, false, index, (Object[]) storage); default: return ArrayObject.factory(DataType.OBJECT, Object.class, false, index, (Object[]) storage); // LOOK dont know the object class } } static public Array makeFromJavaArray(Object javaArray) { return makeFromJavaArray(javaArray, false); } /** * Generate a new Array from a java array of any rank and type. * This makes a COPY of the data values of javaArray of primitive type * LOOK: not sure this works for reference types. * * @param javaArray scalar Object or a java array of any rank and type * @return Array of the appropriate rank and type, with the data copied from javaArray. */ static public Array makeFromJavaArray(Object javaArray, boolean isUnsigned) { // get the rank and type int rank_ = 0; Class componentType = javaArray.getClass(); while (componentType.isArray()) { rank_++; componentType = componentType.getComponentType(); } // get the shape int count = 0; int[] shape = new int[rank_]; Object jArray = javaArray; Class cType = jArray.getClass(); while (cType.isArray()) { shape[count++] = java.lang.reflect.Array.getLength(jArray); jArray = java.lang.reflect.Array.get(jArray, 0); cType = jArray.getClass(); } // create the Array DataType dtype = DataType.getType(componentType, isUnsigned); Array aa = factory(dtype, shape); // copy the original array IndexIterator aaIter = aa.getIndexIterator(); reflectArrayCopyIn(javaArray, aa, aaIter); return aa; } static private void reflectArrayCopyIn(Object jArray, Array aa, IndexIterator aaIter) { Class cType = jArray.getClass().getComponentType(); if (cType.isPrimitive()) { aa.copyFrom1DJavaArray(aaIter, jArray); // subclass does type-specific copy } else { for (int i = 0; i < java.lang.reflect.Array.getLength(jArray); i++) // recurse reflectArrayCopyIn(java.lang.reflect.Array.get(jArray, i), aa, aaIter); } } static private void reflectArrayCopyOut(Object jArray, Array aa, IndexIterator aaIter) { Class cType = jArray.getClass().getComponentType(); //if (cType.isPrimitive()) { // Rob Weingruber May 11, 2011 if (!cType.isArray()) { aa.copyTo1DJavaArray(aaIter, jArray); // subclass does type-specific copy } else { for (int i = 0; i < java.lang.reflect.Array.getLength(jArray); i++) // recurse reflectArrayCopyOut(java.lang.reflect.Array.get(jArray, i), aa, aaIter); } } /** * Cover for System.arraycopy(). Works with the underlying data arrays. * ArraySrc and ArrayDst must be the same primitive type. * Exposed for efficiency; use at your own risk. * * @param arraySrc copy from here : if not in canonical order, an extra copy will be done * @param srcPos starting at * @param arrayDst copy to here : must be in canonical order * @param dstPos starting at * @param len number of elements to copy */ static public void arraycopy(Array arraySrc, int srcPos, Array arrayDst, int dstPos, int len) { // deal with special case if (arraySrc.isConstant()) { double d = arraySrc.getDouble(0); for (int i = dstPos; i < dstPos + len; i++) arrayDst.setDouble(i, d); return; } Object src = arraySrc.get1DJavaArray(arraySrc.getDataType()); // ensure canonical order Object dst = arrayDst.getStorage(); System.arraycopy(src, srcPos, dst, dstPos, len); } /** * Make a 1D array from a start and incr. * * @param dtype data type of result. must be convertible to double. * @param npts number of points * @param start starting values * @param incr increment * @return 1D array */ static public Array makeArray(DataType dtype, int npts, double start, double incr) { Array result = Array.factory(dtype, new int[]{npts}); IndexIterator dataI = result.getIndexIterator(); for (int i = 0; i < npts; i++) { double val = start + i * incr; dataI.setDoubleNext(val); } return result; } /** * Make an 1D array from a list of strings. * * @param dtype data type of the array. * @param stringValues list of strings. * @return resulting 1D array. * @throws NumberFormatException if string values not parseable to specified data type */ static public Array makeArray(DataType dtype, List stringValues) throws NumberFormatException { Array result = Array.factory(dtype, new int[]{stringValues.size()}); IndexIterator dataI = result.getIndexIterator(); for (String s : stringValues) { if (dtype == DataType.STRING) { dataI.setObjectNext(s); } else if (dtype == DataType.LONG) { if (dtype.isUnsigned()) { BigInteger biggy = new BigInteger(s); dataI.setLongNext(biggy.longValue()); // > 63 bits will become "negetive". } else { long val = Long.parseLong(s); dataI.setLongNext(val); } } else { // this works for other numerics (LOOK not unsigned) double val = Double.parseDouble(s); dataI.setDoubleNext(val); } } return result; } /** * Make an 1D array from an array of strings. * * @param dtype data type of the array. Assumed unsigned * @param stringValues list of strings. * @return resulting 1D array. * @throws NumberFormatException if string values not parseable to specified data type */ static public Array makeArray(DataType dtype, String[] stringValues) throws NumberFormatException { return makeArray(dtype, Arrays.asList(stringValues)); } /** * Add extra outermost dimension with len = 1. * * @param org original array * @return rank1 array of rank + 1 */ static public Array makeArrayRankPlusOne(Array org) { int[] shape = new int[org.getRank() + 1]; System.arraycopy(org.getShape(), 0, shape, 1, org.getRank()); shape[0] = 1; return factory(org.getDataType(), shape, org.getStorage()); } ///////////////////////////////////////////////////// protected final DataType dataType; protected final Index indexCalc; protected final int rank; // for subclasses only protected Array(DataType dataType, int[] shape) { this.dataType = dataType; this.rank = shape.length; this.indexCalc = Index.factory(shape); } protected Array(DataType dataType, Index index) { this.dataType = dataType; this.rank = index.getRank(); this.indexCalc = index; } /** * Return the computed datatype for this array * * @return the data type */ public DataType getDataType() { return this.dataType; } /** * Get an Index object used for indexed access of this Array. * * @return an Index for this Array * @see Index */ public Index getIndex() { return (Index) indexCalc.clone(); } /** * Get an index iterator for traversing the array in canonical order. * * @return an IndexIterator for this Array * @see IndexIterator */ public IndexIterator getIndexIterator() { return indexCalc.getIndexIterator(this); } /** * Get the number of dimensions of the array. * * @return number of dimensions of the array */ public int getRank() { return rank; } /** * Get the shape: length of array in each dimension. * * @return array whose length is the rank of this * Array and whose elements represent the length of each of its indices. */ public int[] getShape() { return indexCalc.getShape(); } /** * Get the total number of elements in the array. * * @return total number of elements in the array */ public long getSize() { return indexCalc.getSize(); } /** * Get the total number of bytes in the array. * * @return total number of bytes in the array */ public long getSizeBytes() { DataType dtype = DataType.getType(this); return indexCalc.getSize() * dtype.getSize(); } /** * Get an index iterator for traversing a section of the array in canonical order. * This is equivalent to Array.section(ranges).getIterator(); * * @param ranges list of Ranges that specify the array subset. * Must be same rank as original Array. * A particular Range: 1) may be a subset, or 2) may be null, meaning use entire Range. * @return an IndexIterator over the named range. * @throws InvalidRangeException if ranges is invalid */ public IndexIterator getRangeIterator(List ranges) throws InvalidRangeException { return section(ranges).getIndexIterator(); } /* * Get an index iterator for traversing the array in arbitrary order. * Use this if you dont care what order the elements are returned, eg if you are summing an Array. * To get an iteration in order, use getIndexIterator(), which returns a fast iterator if possible. * * @return an IndexIterator for traversing the array in arbitrary order. * @deprecated use getIndexIterator * public IndexIterator getIndexIteratorFast() { return indexCalc.getIndexIteratorFast(this); } */ /** * Get the element class type of this Array * * @return the class of the element */ public abstract Class getElementType(); /** * Get underlying primitive array storage. * Exposed for efficiency, use at your own risk. * * @return underlying primitive array storage */ public abstract Object getStorage(); // So it turns out that non-public, non-protected abstract // methods cannot be overridden in classes in other packages. // If the methods are declared protected, however, they // can be overridden; just one of those Java things. // // So, modify the following methods to be protected: // copyFrom1DJavaArray, copyTo1DJavaArray, and createView. // // This has consequences all over ucar.ma2. // used to create Array from java array abstract protected void copyFrom1DJavaArray(IndexIterator iter, Object javaArray); abstract protected void copyTo1DJavaArray(IndexIterator iter, Object javaArray); /** * create new Array with given Index and the same backing store * * @param index use this Index * @return a view of the Array using the given Index */ abstract protected Array createView(Index index); /** * Create a new Array as a subsection of this Array, with rank reduction. * No data is moved, so the new Array references the same backing store as the original. * * @param ranges list of Ranges that specify the array subset. * Must be same rank as original Array. * A particular Range: 1) may be a subset, or 2) may be null, meaning use entire Range. * If Range[dim].length == 1, then the rank of the resulting Array is reduced at that dimension. * @return the new Array * @throws InvalidRangeException if ranges is invalid */ public Array section(List ranges) throws InvalidRangeException { return createView(indexCalc.section(ranges)); } /** * Create a new Array as a subsection of this Array, with rank reduction. * No data is moved, so the new Array references the same backing store as the original. *

* * @param origin int array specifying the starting index. Must be same rank as original Array. * @param shape int array specifying the extents in each dimension. * This becomes the shape of the returned Array. Must be same rank as original Array. * If shape[dim] == 1, then the rank of the resulting Array is reduced at that dimension. * @return the new Array * @throws InvalidRangeException if ranges is invalid */ public Array section(int[] origin, int[] shape) throws InvalidRangeException { return section(origin, shape, null); } /** * Create a new Array as a subsection of this Array, with rank reduction. * No data is moved, so the new Array references the same backing store as the original. *

* * @param origin int array specifying the starting index. Must be same rank as original Array. * @param shape int array specifying the extents in each dimension. * This becomes the shape of the returned Array. Must be same rank as original Array. * If shape[dim] == 1, then the rank of the resulting Array is reduced at that dimension. * @param stride int array specifying the strides in each dimension. If null, assume all ones. * @return the new Array * @throws InvalidRangeException if ranges is invalid */ public Array section(int[] origin, int[] shape, int[] stride) throws InvalidRangeException { List ranges = new ArrayList<>(origin.length); if (stride == null) { stride = new int[origin.length]; for (int i = 0; i < stride.length; i++) stride[i] = 1; } for (int i = 0; i < origin.length; i++) ranges.add(new Range(origin[i], origin[i] + stride[i] * shape[i] - 1, stride[i])); return createView(indexCalc.section(ranges)); } /** * Create a new Array as a subsection of this Array, without rank reduction. * No data is moved, so the new Array references the same backing store as the original. * Vlen is transferred over unchanged. * * @param ranges list of Ranges that specify the array subset. * Must be same rank as original Array. * A particular Range: 1) may be a subset, or 2) may be null, meaning use entire Range. * @return the new Array * @throws InvalidRangeException if ranges is invalid */ public Array sectionNoReduce(List ranges) throws InvalidRangeException { return createView(indexCalc.sectionNoReduce(ranges)); } /** * Create a new Array as a subsection of this Array, without rank reduction. * No data is moved, so the new Array references the same backing store as the original. * * @param origin int array specifying the starting index. Must be same rank as original Array. * @param shape int array specifying the extents in each dimension. * This becomes the shape of the returned Array. Must be same rank as original Array. * @param stride int array specifying the strides in each dimension. If null, assume all ones. * @return the new Array * @throws InvalidRangeException if ranges is invalid */ public Array sectionNoReduce(int[] origin, int[] shape, int[] stride) throws InvalidRangeException { List ranges = new ArrayList<>(origin.length); if (stride == null) { stride = new int[origin.length]; for (int i = 0; i < stride.length; i++) stride[i] = 1; } for (int i = 0; i < origin.length; i++) { if (shape[i] < 0) // VLEN ranges.add(Range.VLEN); else ranges.add(new Range(origin[i], origin[i] + stride[i] * shape[i] - 1, stride[i])); } return createView(indexCalc.sectionNoReduce(ranges)); } /** * Create a new Array using same backing store as this Array, by * fixing the specified dimension at the specified index value. This reduces rank by 1. * * @param dim which dimension to fix * @param value at what index value * @return a new Array */ public Array slice(int dim, int value) { int[] origin = new int[rank]; int[] shape = getShape(); origin[dim] = value; shape[dim] = 1; try { return sectionNoReduce(origin, shape, null).reduce(dim); // preserve other dim 1 } catch (InvalidRangeException e) { throw new IllegalArgumentException(); } } /** * Create a copy of this Array, copying the data so that physical order is the same as * logical order * * @return the new Array */ public Array copy() { Array newA = factory(getDataType(), getShape()); MAMath.copy(newA, this); return newA; } /** * This gets the equivalent java array of the wanted type, in correct order. * It avoids copying if possible. * * @param wantType returned object will be an array of this type. This must be convertible to it. * @return java array of type want */ public Object get1DJavaArray(DataType wantType) { if (wantType == getDataType()) { if (indexCalc.isFastIterator()) return getStorage(); // already in order else return copyTo1DJavaArray(); // gotta copy } // gotta convert to new type Array newA = factory(wantType, getShape()); MAMath.copy(newA, this); return newA.getStorage(); } /** * @deprecated use get1DJavaArray(DataType wantType) */ public Object get1DJavaArray(Class wantType) { DataType want = DataType.getType(wantType, isUnsigned()); return get1DJavaArray(want); } /** * This gets the data as a ByteBuffer, in correct order. * It avoids copying if possible. * Only for numeric types (byte, short, int, long, double, float) * * @return equivilent data in a ByteBuffer */ public ByteBuffer getDataAsByteBuffer() { throw new UnsupportedOperationException(); } public ByteBuffer getDataAsByteBuffer(ByteOrder order) { throw new UnsupportedOperationException(); } public ByteBuffer getDataAsByteBuffer(int capacity, ByteOrder order) { ByteBuffer bb = ByteBuffer.allocate(capacity); if(order != null) bb.order(order); return bb; } /** * Create an Array from a ByteBuffer * * @param dtype type of data * @param shape shape of data; if null, then use int[]{bb.limit()} * @param bb data is in here * @return equivilent Array */ public static Array factory(DataType dtype, int[] shape, ByteBuffer bb) { int size; Array result; switch (dtype) { case ENUM1: case UBYTE: case BYTE: size = bb.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setByte(i, bb.get(i)); return result; case CHAR: size = bb.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setByte(i, bb.get(i)); return result; case ENUM2: case USHORT: case SHORT: ShortBuffer sb = bb.asShortBuffer(); size = sb.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setShort(i, sb.get(i)); return result; case ENUM4: case UINT: case INT: IntBuffer ib = bb.asIntBuffer(); size = ib.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setInt(i, ib.get(i)); return result; case ULONG: case LONG: LongBuffer lb = bb.asLongBuffer(); size = lb.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setLong(i, lb.get(i)); return result; case FLOAT: FloatBuffer ffb = bb.asFloatBuffer(); size = ffb.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setFloat(i, ffb.get(i)); return result; case DOUBLE: DoubleBuffer db = bb.asDoubleBuffer(); size = db.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setDouble(i, db.get(i)); return result; } throw new UnsupportedOperationException("" + dtype); } /** * Copy this array to a 1D Java primitive array of type getElementType(), with the physical order * of the result the same as logical order. * * @return a Java 1D array of type getElementType(). */ public Object copyTo1DJavaArray() { Array newA = copy(); return newA.getStorage(); } /** * Copy this array to a n-Dimensional Java primitive array of type getElementType() * and rank getRank(). Makes a copy of the data. * * @return a Java ND array of type getElementType(). */ public Object copyToNDJavaArray() { Object javaArray; try { javaArray = java.lang.reflect.Array.newInstance(getElementType(), getShape()); } catch (Exception e) { throw new IllegalArgumentException(e); } // copy data IndexIterator iter = getIndexIterator(); reflectArrayCopyOut(javaArray, this, iter); return javaArray; } /** * Create a new Array using same backing store as this Array, by * flipping the index so that it runs from shape[index]-1 to 0. * * @param dim dimension to flip * @return the new Array */ public Array flip(int dim) { return createView(indexCalc.flip(dim)); } /** * Create a new Array using same backing store as this Array, by * transposing two of the indices. * * @param dim1 transpose these two indices * @param dim2 transpose these two indices * @return the new Array */ public Array transpose(int dim1, int dim2) { return createView(indexCalc.transpose(dim1, dim2)); } /** * Create a new Array using same backing store as this Array, by * permuting the indices. * * @param dims the old index dims[k] becomes the new kth index. * @return the new Array * @throws IllegalArgumentException: wrong rank or dim[k] not valid */ public Array permute(int[] dims) { return createView(indexCalc.permute(dims)); } /** * Create a new Array by copying this Array to a new one with given shape * * @param shape the new shape * @return the new Array * @throws IllegalArgumentException new shape is not conformable */ public Array reshape(int[] shape) { Array result = factory(this.getDataType(), shape); if (result.getSize() != getSize()) throw new IllegalArgumentException("reshape arrays must have same total size"); Array.arraycopy(this, 0, result, 0, (int) getSize()); return result; } /** * Reshape this array without copying data * * @param shape the new shape * @return the new Array, using same backing object * @throws IllegalArgumentException new shape is not conformable */ public Array reshapeNoCopy(int[] shape) { Array result = factory(this.getDataType(), shape, getStorage()); if (result.getSize() != getSize()) throw new IllegalArgumentException("reshape arrays must have same total size"); return result; } /** * Create a new Array using same backing store as this Array, by * eliminating any dimensions with length one. * * @return the new Array, or the same array if no reduction was done */ public Array reduce() { Index ri = indexCalc.reduce(); if (ri == indexCalc) return this; return createView(ri); } /** * Create a new Array using same backing store as this Array, by * eliminating the specified dimension. * * @param dim dimension to eliminate: must be of length one, else IllegalArgumentException * @return the new Array */ public Array reduce(int dim) { return createView(indexCalc.reduce(dim)); } ////////////////////////////////////////////////////////////// /** * Find whether the underlying data should be interpreted as unsigned. * Only affects byte, short, int, and long. * When true, conversions to wider types are handled correctly. * * @return true if the data is an unsigned integer type. */ public boolean isUnsigned() { return dataType.isUnsigned(); } /** * If this is a constant array * * @return If this is a constant array */ public boolean isConstant() { return indexCalc instanceof IndexConstant; } public boolean isVlen() { return false; } /////////////////////////////////////////////////// /* these are the type-specific element accessors */ /////////////////////////////////////////////////// /** * Get the array element at the current element of ima, as a double. * * @param ima Index with current element set * @return value at index cast to double if necessary. */ public abstract double getDouble(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. */ public abstract void setDouble(Index ima, double value); /** * Get the array element at the current element of ima, as a float. * * @param ima Index with current element set * @return value at index cast to float if necessary. */ public abstract float getFloat(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. */ public abstract void setFloat(Index ima, float value); /** * Get the array element at the current element of ima, as a long. * * @param ima Index with current element set * @return value at index cast to long if necessary. */ public abstract long getLong(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. */ public abstract void setLong(Index ima, long value); /** * Get the array element at the current element of ima, as a int. * * @param ima Index with current element set * @return value at index cast to int if necessary. */ public abstract int getInt(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. */ public abstract void setInt(Index ima, int value); /** * Get the array element at the current element of ima, as a short. * * @param ima Index with current element set * @return value at index cast to short if necessary. */ public abstract short getShort(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. */ public abstract void setShort(Index ima, short value); /** * Get the array element at the current element of ima, as a byte. * * @param ima Index with current element set * @return value at index cast to float if necessary. */ public abstract byte getByte(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. */ public abstract void setByte(Index ima, byte value); /** * Get the array element at the current element of ima, as a char. * * @param ima Index with current element set * @return value at index cast to char if necessary. */ public abstract char getChar(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. */ public abstract void setChar(Index ima, char value); /** * Get the array element at the current element of ima, as a boolean. * * @param ima Index with current element set * @return value at index cast to boolean if necessary. * @throws ForbiddenConversionException if underlying array not boolean */ public abstract boolean getBoolean(Index ima); /** * Set the array element at the current element of ima. * * @param ima Index with current element set * @param value the new value; cast to underlying data type if necessary. * @throws ForbiddenConversionException if underlying array not boolean */ public abstract void setBoolean(Index ima, boolean value); /** * Get the array element at index as an Object. * The returned value is wrapped in an object, eg Double for double * * @param ima element Index * @return Object value at index * @throws ArrayIndexOutOfBoundsException if index incorrect rank or out of bounds */ public abstract Object getObject(Index ima); /** * Set the array element at index to the specified value. * the value must be passed wrapped in the appropriate Object (eg Double for double) * * @param ima Index with current element set * @param value the new value. * @throws ArrayIndexOutOfBoundsException if index incorrect rank or out of bounds * @throws ClassCastException if Object is incorrect type */ abstract public void setObject(Index ima, Object value); //// these are for optimized access with no need to check index values //// elem is the index into the backing data abstract public double getDouble(int elem); abstract public void setDouble(int elem, double val); abstract public float getFloat(int elem); abstract public void setFloat(int elem, float val); abstract public long getLong(int elem); abstract public void setLong(int elem, long value); abstract public int getInt(int elem); abstract public void setInt(int elem, int value); abstract public short getShort(int elem); abstract public void setShort(int elem, short value); abstract public byte getByte(int elem); abstract public void setByte(int elem, byte value); abstract public char getChar(int elem); abstract public void setChar(int elem, char value); abstract public boolean getBoolean(int elem); abstract public void setBoolean(int elem, boolean value); abstract public Object getObject(int elem); abstract public void setObject(int elem, Object value); public String toString() { StringBuilder sbuff = new StringBuilder(); IndexIterator ii = getIndexIterator(); while (ii.hasNext()) { Object data = ii.getObjectNext(); if (data instanceof Number && isUnsigned()) { // 'data' is unsigned, but will be treated as signed when we print it below, because Java only has signed // types. If it is large enough ( >= 2^(BIT_WIDTH-1) ), its most-significant bit will be interpreted as the // sign bit, which will result in an invalid (negative) value being printed. To prevent that, we're going // to widen the number before printing it. data = DataType.widenNumber((Number) data); } sbuff.append(data); sbuff.append(" "); } return sbuff.toString(); } /** * Create a string representation of the shape of this Array. * * @return string representation of the shape */ public String shapeToString() { int[] shape = getShape(); if (shape.length == 0) return ""; StringBuilder sb = new StringBuilder(); sb.append('('); for (int i = 0; i < shape.length; i++) { int s = shape[i]; if (i > 0) sb.append(","); sb.append(s); } sb.append(')'); return sb.toString(); } ///////////////////////////////////////////////////////////////////////////////////////// // can we replace with replace with foreach ?? private IndexIterator ii; // local iterator /** * Check if more elements in the local iterator. * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety. * You cannot call any of the array.nextXXX() methods without calling hasNext() first. * If you are not sure of the state of the iterator, you must reset it before use. Example: *

   * arr.resetLocalIterator();
   * while (arr.hasNext()) {
   * double val = mdata.nextDouble();
   * ..
   * }
   * <.pre>
   *
   * @return true if there are more elements in the iteration
   */
  public boolean hasNext() {
    if (null == ii) ii = getIndexIterator();
    return ii.hasNext();
  }

  /**
   * Return the next object in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as an Object, same as IndexIterator.getObjectNext().
   */
  public Object next() {
    return ii.getObjectNext();
  }

  /**
   * Return the next double in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a double, same as IndexIterator.getDoubleNext().
   */
  public double nextDouble() {
    return ii.getDoubleNext();
  }

  /**
   * Return the next float in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a float, same as IndexIterator.getFloatNext().
   */
  public float nextFloat() {
    return ii.getFloatNext();
  }

  /**
   * Return the next byte in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a byte, same as IndexIterator.getByteNext().
   */
  public byte nextByte() {
    return ii.getByteNext();
  }

  /**
   * Return the next short in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a short, same as IndexIterator.getShortNext().
   */
  public short nextShort() {
    return ii.getShortNext();
  }

  /**
   * Return the next int in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a int, same as IndexIterator.getIntNext().
   */
  public int nextInt() {
    return ii.getIntNext();
  }

  /**
   * Return the next long in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a long, same as IndexIterator.getLongNext().
   */
  public long nextLong() {
    return ii.getLongNext();
  }

  /**
   * Return the next char in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a char, same as IndexIterator.getCharNext().
   */
  public char nextChar() {
    return ii.getCharNext();
  }

  /**
   * Return the next boolean in the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   *
   * @return next element as a boolean, same as IndexIterator.getBooleanNext().
   */
  public boolean nextBoolean() {
    return ii.getBooleanNext();
  }

  /**
   * Reset the local iterator.
   * Uses the local iterator, which is not thread-safe. Use getIndexIterator if you need thread-safety.
   */
  public void resetLocalIterator() {
    ii = null;
  }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy