
bzindex(indirection)
bzindex(Array!indirection)
bf(Indirection) is the ability to modify or access an array at a 
set of selected index values.  Blitz++ provides several forms of
indirection: 

startit()

it() bf(Using a list of array positions): this approach is useful
if you need to modify an array at a set of scattered points.

it() bf(Cartesian-product indirection): as an example, for
a two-dimensional array you might have a list tt(I) of
rows and a list tt(J) of columns, and you want to modify
the array at all (i,j) positions where i is in tt(I) and
j is in tt(J).  This is a bf(cartesian product) of
the index sets tt(I) and tt(J).

it() bf(Over a set of strips): for efficiency,
you can represent an arbitrarily-shaped subset of
an array as a list of one-dimensional strips.
This is a useful way of handling bf(Regions Of Interest)
(ROIs).

endit()

figure(indirect)(Three styles of indirection (from top to bottom):
  (1) using a list of array positions; (2) Cartesian-product
  indirection; (3) using a set of strips to represent an
  arbitrarily-shaped subset of an array)(indirect)


bzindex(STL, for indirection)
In all cases, Blitz++ expects a Standard Template Library
container.  Some useful STL containers are
tt(list<>), tt(vector<>), tt(deque<>) and tt(set<>).
Documentation of these classes is often provided
with your compiler, or see also the good documentation
at url(http://www.sgi.com/Technology/STL/)(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
bzverb(
#include <list>   // for list<>
#include <vector> // for vector<>
#include <deque>  // for deque<>
#include <set>    // for set<>
)

bzindex([] operator, for indirection)
The tt([]) operator is overloaded on arrays so that
the syntax tt(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 tt(<examples/indirect.cpp>).

bzsect(Indirection using lists of array positions)

bzindex(Array!indirection!list of positions)
bzindex(indirection!list of positions)

The simplest kind of indirection uses a list of points.
For one-dimensional arrays, you can just use an STL
container of integers.  Example:
bzverb(
  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
tt([ 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 tt(TinyVector<int,N_rank>)
objects.  Example:
bzverb(
  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:

bzverb(
  0   0   0   0
  0  11   0   0
  0   0  22   0
  0   0   0   0
)

(The tt(tensor::i) notation is explained in the section on
index placeholders ref(index-placeholders)).

bzsect(Cartesian-product indirection)

bzindex(Array!indirection!Cartesian-product)
bzindex(indirection!Cartesian-product)

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 bf(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:
bf(bzverb(\
template<class T_container>
indexSet(T_container& c1, T_container& c2, ...)
))
The returned adaptor can then be used in
the tt([]) operator of an array object.

Here is a two-dimensional example:
bzindex(rank-1 update)
bzverb(
  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:
bzverb(
 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 tt(vector<int>) or
all tt(set<TinyVector<int,2> >)), but they may 
be different sizes.  Singleton containers
(containers containing a single value) are fine.


bzsect(Indirection with lists of strips)

bzindex(Array!indirection!list of strips)
bzindex(indirection!list of strips)

You can also do indirection with a container of
one-dimensional bf(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.

bzindex(RectDomain<N>)
Strips are represented by objects of type
tt(RectDomain<N>), where tt(N) is the
dimensionality of the array.  The tt(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:
bzindex(strip())
bf(bzverb(\
RectDomain<N> strip(TinyVector<int,N> start,
    int stripDimension, int ubound);
))
The tt(start) parameter is where the strip
starts; tt(stripDimension) is the dimension
in which the strip runs; tt(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:
bf(bzverb(\
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:
bzverb(
  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:
bzverb(
  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
)

