|
|
| |||||||||||||||||||||
| Non-Core Java packages it uses: | none |
| Analogous Package in v1.3: | n/a |
Java's support for efficient access to multidimensional arrays is
somewhat lacking. To make up for this shortcoming, Horizon uses the
ncsa.horizon.arrayND package access and manipulate
multidimensional array data.
Purpose: to provide fast, flexible access to multi-dimensional arrays by:
System.arraycopy().
The main player in this package is the abstract
ArrayND
class. Its interface gives access to the array elements, while hiding
the details of how the elements are actually stored. It also provides
methods for accessing subregions of the array. This package also
provides the
NDArrayIndexOutOfBoundsException,
the N-dimensional analogue to the
ArrayIndexOutOfBoundsException, for handling
out-of-bounds conditions.
An implementation of the
ArrayND
class specializes in a particular storage strategy that is optimized
for certain kinds of access; thus, it is very easy to mix different
storage strategies within the same application. This is a
particularly useful feature when your application uses different third
party data readers (as Horizon does), each with their own storage
strategy. All the diverse array data can be given a uniform interface
by wrapping each by an appropriate
ArrayND
implementation.
This package currently comes with the following implementations of
the
ArrayND
class:
| NormalArrayND | This implementation wraps around a normal Java multidimensional array. |
| ReverseNormalArrayND | This implementation also wraps around a normal Java multidimensional array; however, you would use this if the ordering of the axes is reversed from you need in your application. That is, you use this class when the element that you expect to be located at array[1][2][3] is actually located at array[3][2][1]. |
| FlatArrayND | This implementation is used when the multi-dimensional data is stored in a 1-dimensional array such that the data along the first axis (e.g. the axis associated with "1" in array[1][2][3]) varies most rapidly. |
| NaturalFlatArrayND | This implementation is used when the multi-dimensional data is stored in a 1-dimensional array such that the data along the last axis (e.g. the axis associated with "3" in array[1][2][3]) varies most rapidly. It's referred to as "Natural" because it is as if the 1-D arrays in a normal multidimensional Java array were strung together end-to-end. |
| VirtualSubArrayND | This implementation wraps around around another ArrayND in order to give access to a subset of the array. It is as if one copied out the subset into a new ArrayND without actually doing the potentially expensive copy. |
The above implementations all implement the
SingleObjectStorage
interface which allow the user direct access to the storage object.
The
FlatArrayStorage
and
NDArrayStorage
interfaces help identify what that storage object is.
One way you might iterate through a multidimensional array is with a
multidimensional array index--i.e. a 1-D integer array--which you
would would use to access each element and then iterate within some
loop structure. This fairly easy and efficient if you know the type
and dimensionality of the array at compile-time. When you don't know
these properties, you could use the
ArrayND
class and its getElement() method to access each
element. (You could even use the
VolumeIterator
class to help you iterate the index.) However, this is not a very
efficient way to move through your data because you would be using a
random-access method to access in a non-random way. Our experience
has shown this scheme to be painfully slow for large arrays.
Part of the problem with using multidimensional array data efficiently
is that Java's support for array data is primarily oriented toward 1-D
arrays. In particular, the Array.get() and
System.arraycopy() methods treat the input arrays as 1-D
arrays. The
ncsa.horizon.arrayND package, therefore, takes advantage of
this fact with classes that give the user access to multidimensional
arrays in 1-D chunks. This allows the user to maximize the
use of Array.get() and System.arraycopy()
which are native methods and are therefore the fastest way to handle
the data.
The two important classes used to step through the arrays are
Chunkerator
and
ArrayChunk.
A
Chunkerator
object holds a pointer to 1-D arrays within the storage of an
ArrayND
instance. As it is iterated, the pointer steps through each 1-D array
in order. Access to these 1-D arrays are returned to the user in the
form of an
ArrayChunk
which not only gives the user a reference to the 1-D array, but also
instructs the how to access it in terms of a starting position,
length, and stride. With this scheme, access, updating, copying, and
subsampling all can be made fast and efficient. For examples of their
use, see the
Chunkerator
and
ArrayChunk
APIs.
All of the above
ArrayND
implementations support chunking (via the
Chunkable
interface) and therefore can be iterated through using a
Chunkerator.
Our own tests have shown improvements of factors between 8 and 10 in
speed over random-access schemes.
Other classes related to chunking include:
| Chunkable | This interface indicates that an indicates that data can be accessed in 1-D chunks. |
| ChunkableArrayND | This is an abstract class that
inherits from
ArrayND
and enforces chunking support by also "implementing" the
Chunkable
interface. |
| NoSuchChunkException | This exception is thrown when one attempts to access a non-existant array chunk. |
|
|