Array
Indexing into the array, and positions in general, are given with IPosition
(essentially a vector of integers) objects. That is, an N-dimensional
array requires a length-N IPosition to define a position within the array.
Unlike C, indexing is done with (), not []. Also, the storage order
is the same as in FORTRAN, i.e. memory varies most rapidly with the first
index.
An Array may be standalone, or it may refer to another array, or to
part of another array (by refer we mean that if you change a pixel in
the current array, a pixel in the referred to array also changes, i.e.
they share underlying storage).
The Array classes are intended to operate on relatively large
amounts of data. While they haven't been extensively tuned yet,
they are relatively efficient in terms of speed. Presently they
are not space efficient -- the overhead is about 15 words. While
this will be improved (probably to about 1/2 that), these array
classes are not appropriate for very large numbers of very small
arrays. The Block
Element by element mathematical and logical operations are available
for arrays (defined in aips/ArrayMath.h and aips/ArrayLogical.h).
Because arithmetic and logical functions are split out, it is possible
to create an Array
Array
If compiled with the preprocessor symbol AIPS_DEBUG symbol, array
consistency ("invariants") will be checked in most member
functions, and indexing will be range-checked. This should not be
defined for production runs.
A tutorial for the ArrayClasses is available in the "AIPS++ Programming
Manual."
Create an array of the given shape, i.e. after construction
array.ndim() == shape.nelements() and array.shape() == shape.
The origin of the Array is zero.
Create an array with a given shape and origin.
After construction, this and other reference the same storage.
Frees up storage only if this array was the last reference to it.
This functions is used by the exception handling mechanism we have
defined. It merely calls the destructor. When real exceptions are
available it will be unnecessary.
Set every element of the array to "value." Also could use the
assignment operator which assigns an array from a scalar.
Apply the function to every element of the array. This modifies
the array in place.
This version takes a function which takes a T and returns a T.
Apply the function to every element of the array. This modifies
the array in place.
This version takes a function which takes a const T reference and
returns a T.
After invocation, this array and other reference the same
storage. That is, modifying an element through one will show
up in the other. The arrays appear to be identical;
they have the same shape and origin.
Copy the values in other to this. If the array on the left hand
side has no elements, then it is resized to be the same size as
as the array on the right hand side. Otherwise, the arrays must
conform (same shapes, but origins do not need to be the same).
Set every element of this array to "value". In other words, a scalar
behaves as if it were a constant conformant array.
Copy to this those values in marray whose corresponding elements
in marray's mask are True.
This makes a copy of the array and returns it. This can be
useful for, e.g. making working copies of function arguments
that you can write into.
This ensures that this array does not reference any other storage.
It is occasionally useful to have an array which access the same
storage appear to have a different shape and origin. For example,
Turning an N-dimensional array into a Vector. This will work when
before.nelements() == after.nelements() and if this array refers
to other storage, the increment on all axes must be one (guaranteed,
for example, by unique()).
This member function returns an Array reference which has all degenerate
(length==1) axes removed and the dimensionality reduced appropriately.
If nelements==0 returns a dimension 1 0-length array.
Otherwise returns an array with all length-1 axes remoeved.
Make this array a different shape. Presently the old values are not
copied over to the new array.
Access a single element of the array. This is relatively
expensive. Extensive indexing should be done through one
of the Array specializations (Vector, Matrix, Cube). If
AIPS_DEBUG is defined, index checking will be performed.
Access a single element of the array. This is relatively
expensive. Extensive indexing should be done through one
of the Array specializations (Vector, Matrix, Cube). If
AIPS_DEBUG is defined, index checking will be performed.
Ret a reference to an array which extends from "start" to end."
Along the ith axis, every inc[i]'th element is chosen.
Ret a reference to an array which extends from "start" to end."
The array is masked by the input LogicalArray.
This mask must conform to the array, but it does not need to have the
same origin.
Return a ROMaskedArray.
The array is masked by the input LogicalArray.
This mask must conform to the array, but it does not need to have the
same origin.
The array is masked by the input ROMaskedLogicalArray.
The mask is effectively the AND of the internal LogicalArray
and the internal mask of the ROMaskedLogicalArray.
The ROMaskedLogicalArray must conform to the array, but it does not
need to have the same origin.
Return a ROMaskedArray.
The array is masked by the input ROMaskedLogicalArray.
The mask is effectively the AND of the internal LogicalArray
and the internal mask of the ROMaskedLogicalArray.
The ROMaskedLogicalArray must conform to the array, but it does not
need to have the same origin.
The number of references the underlying storage has assigned to it.
It is 1 unless there are outstanding references to the storage (e.g.,
through a slice). Normally you have no need to do this since the
arrays handle all of the references for you.
The dimensionality of this array.
How many elements does this array have? Product of all axis lengths.
Check to see if the Array is consistent. This is about the same thing
as checking for invariants. If AIPS_DEBUG is defined, this is invoked
after construction and on entry to most member functions.
Are the shapes identical? The origins do NOT need to be the same.
Binary operations will "line up" the arrays at their origins, so
as long as the shapes are the same the Arrays conform.
The IPosition of the first array element. All zero is the default.
When zero based, max_index(i) == shape(i) - 1.
Generally use of this should be shunned, except to use a FORTRAN routine
or something similar. Because you can't know the state of the underlying
data layout (in particular, if there are increments) sometimes the
pointer returned will be to a copy, but often this won't be necessary.
A boolean is returned which tells you if this is a copy (and hence the
storage must be deleted). Note that if you don't do anything unusual,
getStorage followed by putStorage will do the deletion for you (if
required). e.g.:
It would probably be useful to have corresponding "copyin" "copyout"
functions that used a user supplied buffer.
Note that deleteIt is set in this function.
Generally use of this should be shunned, except to use a FORTRAN routine
or something similar. Because you can't know the state of the underlying
data layout (in particular, if there are increments) sometimes the
pointer returned will be to a copy, but often this won't be necessary.
A boolean is returned which tells you if this is a copy (and hence the
storage must be deleted). Note that if you don't do anything unusual,
getStorage followed by putStorage will do the deletion for you (if
required). e.g.:
It would probably be useful to have corresponding "copyin" "copyout"
functions that used a user supplied buffer.
Note that deleteIt is set in this function.
putStorage() is normally called after a call to getStorage() (cf).
The "storage" pointer is set to zero.
If deleteIt is set, delete "storage". Normally freeStorage calls
will follow calls to getStorage. The reason the pointer is "const"
is because only const pointers are released from const arrays.
The "storage" pointer is set to zero.
Array version for major change (used by ArrayIO).
enum did not work properly with cfront 3.0.1), so replaced
by a static inline function. Users won't normally use this.
Macro to define the typeinfo member functions.
Various helper functions that should be deleted.
A helper function to copy one vector to another, both of which might
have strides. This is probably useful enough that it should be made
available more publicly?
Copy a scalar value into a carray with a given stride.
Copyright © 1995 Associated Universities Inc., Washington, D.C.
// axisLengths = [1,2,3,4,5]
IPosition axisLengths(5, 1, 2, 3, 4, 5);
Array<Int> ai(axisLengths); // ai is a 5 dimensional array of
// integers; indices are 0-based
// => ai.nelements() == 120
IPosition origin(5); origin = -1; // origin = [-1,-1,-1,-1,-1]
Array<Int> ai2(axisLengths, origin);// The first element is at index
// "origin".
IPosition zero(5); zero = 0; // [0,0,0,0,0]
//...
ai(zero) = ai2(origin); // Copy first element of ai2 to ai1
Indexing into an N-dimensional array is relatively expensive. Normally
you will index into a Vector, Matrix, or Cube. These may be obtained from
an N-dimensional array by creating a reference, or by using an
ArrayIterator. The "shape" of the array is an IPosition which gives the
length of each axis, and the "origin" of the array is an IPosition which
gives the index of the first array element ([0,0,0...] by default).
Aside from the explicit reference() member function, a user will
most commonly encounter an array which references another array
when he takes an array slice (or section). A slice is a sub-region of
an array (which might also have a stride: every nth row, every mth column,
...).
One way one array can reference another is through the copy
constructor. While this might be what you want, you should
probably use the reference() member function to make it explicit.
The copy constructor is used when arguments are passed by value;
normally functions should not pass Arrays by value, rather they
should pass a reference or a const reference. On the positive
side, returning an array from a function is efficient since no
copying need be done. Later releases of the array classes might
have the copy constructor actually make a copy -- comments solicited.
IPosition lengths(3,10,20,30);
Array<Int> ai(lengths); // A 10x20x30 cube
Cube<Int> ci;
//...
ci.reference(ai1); // ci and ai now reference the same
// storage
ci(0,0,0) = 123; // Can use Cube indexing
ci.xyPlane(2) = 0; // and other member functions
IPosition zero(3,0,0,0);
assert(ai(zero) == 123); // True because ai, ci are references
//...
Array<Int> subArray;
IPosition blc(3,0,0,0), trc(3,5,5,5);
subArray.reference(ai(blc, trc));
subArray = 10; // All of subArray, which is the
// subcube from 0,0,0 to 5,5,5 in
// ai, has the value 10.
While the last example has an array slice referenced explicitly by another
array variable, normally the user will often only use the slice as
a temporary in an expresion, for example:
Array<Complex> array;
IPosition blc, trc, offset;
//...
// Copy from one region of the array into another
array(blc, trc) = array(blc+offset, trc+offset);
Most of the data members and functions which are "protected" should
likely become "private".
Member Description
Array()
Result has dimensionality of one, but nelements is zero. Perhaps
instead it should be a dimension zero, length zero array.
Array(const IPosition &shape)
Array(const IPosition &shape, const IPosition &origin)
Array(const Array<T> &other)
virtual ~Array()
void cleanup()
void set(const T &value)
void apply(T (*function)(T))
void apply(T (*function)(const T &))
virtual void reference(Array<T> &other)
virtual Array<T> &operator=(const Array<T> &other)
IPosition shape(2,10,10); // some shape
Array<Double> ad(shape);
//...
Array<Double> ad2; // N.B. ad2.nelements() == 0
ad2 = ad; // ad2 resizes, then elements
// are copied.
shape = 20;
Array<Double> ad3(shape);
ad3 = ad; // Error: arrays do not conform
Array<T> &operator=(const T &value)
Array<T> &operator= (const ROMaskedArray<T> &marray)
Thrown Exceptions
Array<T> copy() const
void someFunction(const Array<Int> &arg)
{
Array<Int> tmp(arg.copy());
// ...
}
Note that since the copy constructor makes a reference, if we just
created used to copy constructor, modifying "tmp" would also
modify "arg". Clearly another alternative would simply be:
void someFunction(const Array<Int> &arg)
{
Array<Int> tmp;
tmp = arg;
// ...
}
which likely would be simpler to understand. (Should copy()
be deprecated and removed?)
void unique()
Make a copy of this
When a section is taken of an array with non-unity strides,
storage can be wasted if the array which originally contained
all the data goes away. unique() also reclaims storage. This
is an optimization users don't normally need to understand.
IPosition shape(...), blc(...), trc(...), inc(...);
Array<Float> af(shape);
inc = 2; // or anything > 1
Array<Float> aSection.reference(af(blc, trc, inc));
af.reference(anotherArray);
// aSection now references storage that has a stride
// in it, but nothing else is. Storage is wasted.
aSection.unique();
Array<T> reform(const IPosition &shape, const IPosition &origin) const
IPosition squareShape(2,5,5);
Array<Float> square(squareShape);
IPosition lineShape(1,25);
Vector<Float> line(square.reform(lineShape));
// "square"'s storage may now be accessed through Vector "line"
Array<T> nonDegenerate()
virtual void resize(const IPosition &newShape)
virtual void resize(const IPosition &newShape, const IPosition &newOrigin)
const T &operator()(const IPosition &) const
T &operator()(const IPosition &)
Array<T> operator()(const IPosition &start, const IPosition &end, const IPosition &inc)
Array<T> operator()(const IPosition &start, const IPosition &end)
MaskedArray<T> operator() (const LogicalArray &mask)
ROMaskedArray<T> operator() (const LogicalArray &mask) const
MaskedArray<T> operator() (const ROMaskedLogicalArray &mask)
ROMaskedArray<T> operator() (const ROMaskedLogicalArray &mask) const
uInt nrefs() const
uInt ndim() const
uInt nelements() const
virtual Bool ok() const
Bool conform(const Array<T> &other) const
Bool conform(const ROMaskedArray<T> &other) const
IPosition origin() const
IPosition shape() const
The length of each axis.
IPosition end() const
A convenience function: end(i) = origin(i) + shape(i) - 1; i.e. this
is the IPosition of the last element of the Array.
const T *getStorage(Bool &deleteIt) const
Array<Int> a(shape); ...
Bool deleteIt; Int *storage = a.getStorage(deleteIt);
foo(storage, a.nelements()); a.puStorage(storage, deleteIt);
// or a.freeStorage(storage, deleteIt) if a is const.
NB: However, if you only use getStorage, you will have to delete the
pointer yourself using freeStorage().
T *getStorage(Bool &deleteIt)
Array<Int> a(shape); ...
Bool deleteIt; Int *storage = a.getStorage(deleteIt);
foo(storage, a.nelements()); a.puStorage(storage, deleteIt);
// or a.freeStorage(storage, deleteIt) if a is const.
NB: However, if you only use getStorage, you will have to delete the
pointer yourself using freeStorage().
void putStorage(T *&storage, Bool deleteAndCopy)
void freeStorage(const T *&storage, Bool deleteIt) const
static uInt arrayVersion()
rtti_dcl_mbrf_p1(Array<T>, Cleanup)
Array(uInt, const Block<Int> &)
void validateConformance(const Array<T> &) const
void validateIndex(const IPosition &) const
void copyVec(uInt n, T *to, uInt toStride, const T *from, uInt fromStride) const
void Array<T>::copyScalar(uInt n, T *to, uInt toStride, T value) const