| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Indirection is the ability to modify or access an array at a set of selected index values. Blitz++ provides several forms of indirection:
I of rows and a list
J of columns, and you want to modify the array at all (i,j) positions
where i is in I and j is in J. This is a cartesian
product of the index sets I and J.

In all cases, Blitz++ expects a Standard Template Library container. Some
useful STL containers are list<>, vector<>, deque<> and
set<>. Documentation of these classes is often provided with your
compiler, or see also the good documentation at
http://www.sgi.com/Technology/STL/. STL containers are used because
they are widely available and provide easier manipulation of "sets" than
Blitz++ arrays. For example, you can easily expand and merge sets which are
stored in STL containers; doing this is not so easy with Blitz++ arrays,
which are designed for numerical work.
STL containers are generally included by writing
#include <list> // for list<> #include <vector> // for vector<> #include <deque> // for deque<> #include <set> // for set<> |
The [] operator is overloaded on arrays so that the syntax
array[container] provides an indirect view of the array. So far,
this indirect view may only be used as an lvalue (i.e. on the left-hand side
of an assignment statement).
The examples in the next sections are available in the Blitz++ distribution in `<examples/indirect.cpp>'.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The simplest kind of indirection uses a list of points. For one-dimensional arrays, you can just use an STL container of integers. Example:
Array<int,1> A(5), B(5); A = 0; B = 1, 2, 3, 4, 5; vector<int> I; I.push_back(2); I.push_back(4); I.push_back(1); A[I] = B; |
After this code, the array A contains [ 0 2 3 0 5 ].
Note that arrays on the right-hand-side of the assignment must have the same
shape as the array on the left-hand-side (before indirection). In the
statement A[I] = B, A and B must have the same shape, not I and B.
For multidimensional arrays, you can use an STL container of
TinyVector<int,N_rank> objects. Example:
Array<int,2> A(4,4), B(4,4); A = 0; B = 10*tensor::i + tensor::j; typedef TinyVector<int,2> coord; list<coord> I; I.push_back(coord(1,1)); I.push_back(coord(2,2)); A[I] = B; |
After this code, the array A contains:
0 0 0 0 0 11 0 0 0 0 22 0 0 0 0 0 |
(The tensor::i notation is explained in the section on index
placeholders 3.6 Index placeholders).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The Cartesian product of the sets I, J and K is the set of (i,j,k) tuples for which i is in I, j is in J, and k is in K.
Blitz++ implements cartesian-product indirection using an adaptor which takes a set of STL containers and iterates through their Cartesian product. Note that the cartesian product is never explicitly created. You create the Cartesian-product adaptor by calling the function:
template<class T_container> indexSet(T_container& c1, T_container& c2, ...) |
The returned adaptor can then be used in the [] operator of an array
object.
Here is a two-dimensional example:
Array<int,2> A(6,6), B(6,6); A = 0; B = 10*tensor::i + tensor::j; vector<int> I, J; I.push_back(1); I.push_back(2); I.push_back(4); J.push_back(0); J.push_back(2); J.push_back(5); A[indexSet(I,J)] = B; |
After this code, the A array contains:
0 0 0 0 0 0 10 0 12 0 0 15 20 0 22 0 0 25 0 0 0 0 0 0 40 0 42 0 0 45 0 0 0 0 0 0 |
All the containers used in a cartesian product must be the same type (e.g.
all vector<int> or all set<TinyVector<int,2> >), but they may
be different sizes. Singleton containers (containers containing a single
value) are fine.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
You can also do indirection with a container of one-dimensional strips. This is useful when you want to manipulate some arbitrarily-shaped, well-connected subdomain of an array. By representing the subdomain as a list of strips, you allow Blitz++ to operate on vectors, rather than scattered points; this is much more efficient.
Strips are represented by objects of type RectDomain<N>, where
N is the dimensionality of the array. The RectDomain<N> class
can be used to represent any rectangular subdomain, but for indirection it
is only used to represent strips.
You create a strip by using this function:
RectDomain<N> strip(TinyVector<int,N> start,
int stripDimension, int ubound);
|
The start parameter is where the strip starts; stripDimension
is the dimension in which the strip runs; ubound is the last index
value for the strip. For example, to create a 2-dimensional strip from
(2,5) to (2,9), one would write:
TinyVector<int,2> start(2,5); RectDomain<2> myStrip = strip(start,secondDim,9); |
Here is a more substantial example which creates a list of strips representing a circle subset of an array:
const int N = 7;
Array<int,2> A(N,N), B(N,N);
typedef TinyVector<int,2> coord;
A = 0;
B = 1;
double centre_i = (N-1)/2.0;
double centre_j = (N-1)/2.0;
double radius = 0.8 * N/2.0;
// circle will contain a list of strips which represent a circular
// subdomain.
list<RectDomain<2> > circle;
for (int i=0; i < N; ++i)
{
double jdist2 = pow2(radius) - pow2(i-centre_i);
if (jdist2 < 0.0)
continue;
int jdist = int(sqrt(jdist2));
coord startPos(i, int(centre_j - jdist));
circle.push_back(strip(startPos, secondDim, int(centre_j + jdist)));
}
// Set only those points in the circle subdomain to 1
A[circle] = B;
|
After this code, the A array contains:
0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 |
| [ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |