SlicesΒΆ

View slices.chpl on GitHub

This example program demonstrates the use of array slicing and reindexing.

In this program, diagonal blocks (or slices) of A are initialized according to the row indices of the diagonal block.

(i,j) = i, for all (i,j) in diagonal blocks

If the block has been reindexed, then each diagonal block is initialized with the same values. If the block has not been reindexed, then the block has the same indices as the full array, so each diagonal block is initialized with different values.

(Incomplete diagonal blocks are not initialized. If blk does not divide into n evenly, the last diagonal block of A will be uninitialized.)

Three different cases are given, to show different ways of slicing arrays, with and without reindexing. Array aliases are declared for the diagonal blocks in two of the three cases. One of these array aliases uses reindexing of the domain of the array alias. The initialization of the blocks is handled in either initBlock or initBlock2. The procedure initBlock does not reindex the domain of the input array while initBlock2 does.

Configuration variables for n and blk where the array A is n * n and blk is the size of the diagonal subblock.

config const n = 10,
             blk = 2;

proc main() {

Variable declarations for the range vec, and for the domain D and array A. vec is used to define the ranges of each dimension of D and it is later used in the iterator for the for loop statements which call the init procedure for each diagonal block of A.

const vec = 1..n;
var D = {vec,vec};
var A:[D] int;

D0 is a domain which is used to reindex the diagonal blocks of A.

var D0 = {1..blk, 1..blk};

Each of the following three for loop statements uses the iterator blockIter to yield a range subvec that is then used to define subvec * subvec blocks along the diagonal of A.

Case 1: No reindexing of the diagonal blocks. The array slice is sent directly to initBlock.

writeln("Initializing the diagonal blocks of A.");
writeln("No reindexing of diagonal blocks.");
for subvec in blockIter(vec,blk) {
  initBlock(A[subvec,subvec]);
}

writeln(A);
writeln();

A is reset to zero between each case. (This step is not necessary, but done to show that each case starts with a zero array.)

A = 0;

Case 2: An array alias with reindexing is used to point to each diagonal block, and that array alias is sent to initBlock.

writeln("Initializing the diagonal blocks of A.");
writeln("Reindexing of each diagonal block in alias declaration. ");
for subvec in blockIter(vec,blk) {
  ref Ablock = A[subvec,subvec].reindex(D0);
  initBlock(Ablock);
}

writeln(A);
writeln();

A = 0;

Case 3: An array alias is used to point to each diagonal block and is reindexed to use 1-based indexing in order to meet the requirements of the initBlock2() routine.

writeln("Initializing the diagonal blocks of A.");
writeln("Reindexing of array argument in init procedure definition. ");
for subvec in blockIter(vec,blk) {
  ref Ablock = A[subvec,subvec].reindex(1..blk, 1..blk);
  initBlock2(Ablock);
}

writeln(A);
writeln();
} // main()

The iterator blockIter yields a range that defines a subset of vec, which is always of length blk.

iter blockIter(vec:range,blk) {
  for i in vec by blk {
    if (i + blk-1 <= vec.high) then
      yield i..i+blk-1;
  }
}

This procedure sets each element of A to be the value of its row index.

proc initBlock(ref A) {
  for (i,j) in A.domain {
    A(i,j) = i;
  }
}

This procedure requires the domain of the array argument to be {1..blk,1..blk}. It sets each element of A to be the value of its row index.

proc initBlock2(ref A: [1..blk,1..blk]) {
  for (i,j) in A.domain {
    A(i,j) = i;
  }
}