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

ucar.ma2.Array Maven / Gradle / Ivy

Go to download

The NetCDF-Java Library is a Java interface to NetCDF files, as well as to many other types of scientific data formats.

There is a newer version: 4.3.22
Show newest version
/*
 * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
 *
 * Portions of this software were developed by the Unidata Program at the
 * University Corporation for Atmospheric Research.
 *
 * Access and use of this software shall impose the following obligations
 * and understandings on the user. The user is granted the right, without
 * any fee or cost, to use, copy, modify, alter, enhance and distribute
 * this software, and any derivative works thereof, and its supporting
 * documentation for any purpose whatsoever, provided that this entire
 * notice appears in all copies of the software, derivative works and
 * supporting documentation.  Further, UCAR requests that the user credit
 * UCAR/Unidata in any publications that result from the use of this
 * software or in any product that includes this software. The names UCAR
 * and/or Unidata, however, may not be used in any advertising or publicity
 * to endorse or promote any products or commercial entity unless specific
 * written permission is obtained from UCAR/Unidata. The user also
 * understands that UCAR/Unidata is not obligated to provide the user with
 * any support, consulting, training or assistance of any kind with regard
 * to the use, operation and performance of this software nor to provide
 * the user with any updates, revisions, new versions or "bug fixes."
 *
 * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
 */
package ucar.ma2;

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 { /* implementation notes. Could create interface for Ranges, ScatterIndex and pass array of that (?) */ /** * Generate new Array with given type 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) { Index index = Index.factory(shape); return factory(dataType.getPrimitiveClassType(), index); } /** * Generate new Array with given type and shape and zeroed storage. * * @param classType element Class type, eg double.class. * @param shape shape of the array. * @return new Array or Array.D if 0 <= rank <= 7. */ static public Array factory(Class classType, int[] shape) { Index index = Index.factory(shape); return factory(classType, index); } /* generate new Array with given type and shape and zeroed storage */ static private Array factory(Class classType, Index index) { if ((classType == double.class) || (classType == Double.class)) return ArrayDouble.factory(index); else if ((classType == float.class) || (classType == Float.class)) return ArrayFloat.factory(index); else if ((classType == long.class) || (classType == Long.class)) return ArrayLong.factory(index); else if ((classType == int.class) || (classType == Integer.class)) return ArrayInt.factory(index); else if ((classType == short.class) || (classType == Short.class)) return ArrayShort.factory(index); else if ((classType == byte.class) || (classType == Byte.class)) return ArrayByte.factory(index); else if ((classType == char.class) || (classType == Character.class)) return ArrayChar.factory(index); else if ((classType == boolean.class) || (classType == Boolean.class)) return ArrayBoolean.factory(index); else return ArrayObject.factory(classType, index); } /** * /** Generate new Array with given type, 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. */ static public Array factory(DataType dataType, int[] shape, Object storage) { return factory(dataType.getPrimitiveClassType(), shape, 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 factory(Class classType, int[] shape, Object storage) { Index indexCalc = Index.factory(shape); return factory(classType, indexCalc, storage); } static private Array factory(Class classType, Index indexCalc, Object storage) { if ((classType == double.class) || (classType == Double.class)) return ArrayDouble.factory(indexCalc, (double[]) storage); else if ((classType == float.class) || (classType == Float.class)) return ArrayFloat.factory(indexCalc, (float[]) storage); else if ((classType == long.class) || (classType == Long.class)) return ArrayLong.factory(indexCalc, (long[]) storage); else if ((classType == int.class) || (classType == Integer.class)) return ArrayInt.factory(indexCalc, (int[]) storage); else if ((classType == short.class) || (classType == Short.class)) return ArrayShort.factory(indexCalc, (short[]) storage); else if ((classType == byte.class) || (classType == Byte.class)) return ArrayByte.factory(indexCalc, (byte[]) storage); else if ((classType == char.class) || (classType == Character.class)) return ArrayChar.factory(indexCalc, (char[]) storage); else if ((classType == boolean.class) || (classType == Boolean.class)) return ArrayBoolean.factory(indexCalc, (boolean[]) storage); else return ArrayObject.factory(classType, indexCalc, (Object[]) storage); } /** * Generate new Array with given type and shape and an Index that always return 0. * * @param classType element Class type, eg double.class. * @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(Class classType, int[] shape, Object storage) { Index index = new IndexConstant(shape); if ((classType == double.class) || (classType == Double.class)) return new ArrayDouble(index, (double[]) storage); else if ((classType == float.class) || (classType == Float.class)) return new ArrayFloat(index, (float[]) storage); else if ((classType == long.class) || (classType == Long.class)) return new ArrayLong(index, (long[]) storage); else if ((classType == int.class) || (classType == Integer.class)) return new ArrayInt(index, (int[]) storage); else if ((classType == short.class) || (classType == Short.class)) return new ArrayShort(index, (short[]) storage); else if ((classType == byte.class) || (classType == Byte.class)) return new ArrayByte(index, (byte[]) storage); else if ((classType == char.class) || (classType == Character.class)) return new ArrayChar(index, (char[]) storage); else if ((classType == boolean.class) || (classType == Boolean.class)) return new ArrayBoolean(index, (boolean[]) storage); else return new ArrayObject(classType, index, (Object[]) storage); } /** * Generate a new Array from a java array of any rank and type. * This makes a COPY of the data values of javaArray. * 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 factory(Object javaArray) { // get the rank and type int rank_ = 0; Class componentType = javaArray.getClass(); while (componentType.isArray()) { rank_++; componentType = componentType.getComponentType(); } /* if( rank_ == 0) throw new IllegalArgumentException("Array.factory: not an array"); if( !componentType.isPrimitive()) throw new UnsupportedOperationException("Array.factory: not a primitive array"); */ // 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 Array aa = factory(componentType, 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()) { 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 stringValues) throws NumberFormatException { Array result = Array.factory(dtype.getPrimitiveClassType(), new int[]{stringValues.size()}); IndexIterator dataI = result.getIndexIterator(); for (String s : stringValues) { if (dtype == DataType.STRING) { dataI.setObjectNext(s); } else if (dtype == DataType.LONG) { long val = Long.parseLong(s); dataI.setLongNext(val); } else { 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. * @param stringValues list of strings. * @return resulting 1D array. * @throws NumberFormatException if string values not parssable to specified data type */ static public Array makeArray(DataType dtype, String[] stringValues) throws NumberFormatException { Array result = Array.factory(dtype.getPrimitiveClassType(), new int[]{stringValues.length}); IndexIterator dataI = result.getIndexIterator(); for (String s : stringValues) { if (dtype == DataType.STRING) { dataI.setObjectNext(s); } else if (dtype == DataType.LONG) { long val = Long.parseLong(s); dataI.setLongNext(val); } else { double val = Double.parseDouble(s); dataI.setDoubleNext(val); } } return result; } ///////////////////////////////////////////////////// protected final Index indexCalc; protected final int rank; protected boolean unsigned; private IndexIterator ii; // local iterator // for subclasses only protected Array(int[] shape) { rank = shape.length; indexCalc = Index.factory(shape); } protected Array(Index index) { rank = index.getRank(); indexCalc = index; } /** * 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 object used for indexed access of this Array. * * @return an Index for this Array */ public Index getIndexPrivate() { return indexCalc; } /** * 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( getElementType()); 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(); /** * 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 Array createView(Index index); /** * Get underlying primitive array storage. * Exposed for efficiency, use at your own risk. * * @return underlying primitive array storage */ public abstract Object getStorage(); // used to create Array from java array abstract void copyFrom1DJavaArray(IndexIterator iter, Object javaArray); abstract void copyTo1DJavaArray(IndexIterator iter, Object javaArray); /** * 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. * * @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++) 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(getElementType(), getShape()); MAMath.copy(newA, this); newA.setUnsigned( isUnsigned()); return newA; } /** * This gets the equivilent 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 copyTo1DJavaArray */ public Object get1DJavaArray(Class wantType) { if (wantType == getElementType()) { 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(); } /** * 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(); } /** * 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 BYTE: if (shape == null) shape = new int[]{bb.limit()}; return factory(dtype, shape, bb.array()); case CHAR: size = bb.limit(); if (shape == null) shape = new int[]{size}; result = factory(dtype, shape); for (int i = 0; i < size; i++) result.setChar(i, (char) bb.get(i)); return result; case ENUM2: 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 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 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.getElementType(), shape); if (result.getSize() != getSize()) throw new IllegalArgumentException("reshape arrays must have same total size"); result.setUnsigned( isUnsigned()); 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.getElementType(), 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, and int. * When true, conversions to wider types are handled correctly. * * @return true if the data is unsigned integer type. */ public boolean isUnsigned() { return unsigned; } /** * If this is a constant array * @return If this is a constant array */ public boolean isConstant() { return indexCalc instanceof IndexConstant; } /** * Set whether the data should be interpreted as unsigned. * Only valid for byte, short, and int. * When true, conversions to wider types are handled correctly. * * @param unsigned true if unsigned */ public void setUnsigned(boolean unsigned) { this.unsigned = unsigned; } /* * Set the name of one of the indices. * @param dim which index? * @param indexName name of index * public void setIndexName( int dim, String indexName) { indexCalc.setIndexName( dim, indexName); } /* * Get the name of one of the indices. * @param dim which index? * @return name of index, or null if none. * public String getIndexName( int dim) { return indexCalc.getIndexName( dim); } */ /////////////////////////////////////////////////// /* 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(); 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(); } /** * 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