Essential Math Module User’s Guide : Chapter 3 Vector, Matrix, and Array Classes : Subscripting
Subscripting
Subscripting allows you to access individual elements, as well as groups of elements, from within vectors, matrices, and arrays. The simplest form of subscripting accesses a single element by using integers as the subscripts, as shown in the code below. As with built-in C and C++ arrays, indices begin at 0.
 
x = v(4) + 1; // Access element 4 in vector v
cout << M(2,3); // Print element 2,3 in matrix M
A(1,3,2) = 2; // Set element 1,3,2 in 3D array A to 2
 
You can also use subscripting to create new views that access groups of elements at the same time. With this kind of subscripting, you can create vectors, matrices, and arrays that refer to selected elements of a vector, matrix, or array, or you can perform an operation on selected elements. Subscripting groups of elements can virtually eliminate loops over vectors, matrices, and arrays. This in turn can streamline your code, allow optimized basic linear algebra subroutines (BLAS), and simplify porting to an array processor or other specialized hardware.
In the next two sections, we discuss two forms of subscripting. In “Subscripting with Character Strings”, we describe how to use character strings to subscript groups of elements. The resulting syntax is easy to read and understand, but unfortunately the subscripts cannot be dynamically altered very easily. This limits their usefulness to situations where the subscript is known at compile time. A more general way to achieve the same capabilities, using subscript classes, is discussed in “Advanced Subscripting”.
Subscripting with Character Strings
The form of a character string subscript is x:y:z. This selects elements x through y, with an increment of z. If the last part, :z, is left out, then all the elements from x through y are selected. Here is an example using the class RWMathVec<T>:
 
RWMathVec<int> v = "[0 1 2 3 4 5 6]";
cout << v("0:2"); // prints [0 1 2]
cout << v("3:1"); // prints [3 2 1]
cout << v("0:6:2"); // prints [0 2 4 6]
 
Any of the parts of the subscript can be omitted. Thus 3: selects all elements from the third to the last, :2 selects all elements up to and including the second element, ::2 selects every other element starting with the first, 1::2 selects every other element starting with the second, and : selects all elements. Here is how to set up a vector containing an alternating sequence of 1s and 0s:
 
RWMathVec<int> v(10);
v("::2") = 1;
v("1::2") = 0; // v = [ 1 0 1 0 1 0 1 0 1 0 ]
A subscripting operation always produces a new view of existing data. In the examples thus far, this new view is temporary and unnamed. It is just as easy to create new named views:
 
RWGenMat<double> A(3,3);
RWGenMat<double> Atl = A("0:1","0:1");
Here the matrices A and Atl are alternative views of the same data. Since Atl is an alias for the data in the top left corner of the matrix A, the following statement changes A as well as Atl:
 
Atl = 0; // sets upper left corner of A to zero
Just as with copy constructors, you can avoid this aliasing property by using the copy() and deepenShallowCopy() member functions.
If you examine the overloaded declarations for operator() in the vector, matrix, and array header files, you will see that none of them take character strings as arguments. This is because subscripting is not done with the character strings themselves. Instead, temporary objects of type RWSlice are constructed automatically by C++ with the constructor RWSlice(const char*), and these temporary objects are used by the subscripting operation. If you use an index more than once, it may be helpful to construct the RWSlice object explicitly. For example, the following segment of code sets up an 8 x 8 matrix with a chessboard pattern where white squares contain a 1 and black squares contain a -1.
 
RWGenMat<double> board(8,8, rwUninitialized);
RWSlice I("0::2"); // selects odd elements
RWSlice J("1::2"); // selects even elements
board(I,I) = board(J,J) = 1; // sets white squares
board(I,J) = board(J,I) = -1; // sets black squares
Advanced Subscripting
The limitation of character string indexing is that the indices are static. For example, it is difficult to use character strings to subscript all entries from i through j, where i and j are C++ integer variables. For this situation, we must construct subscripting objects explicitly. Here is an example:
 
int i,j;
RWMathVec<double> v;
.
.
.
v(RWRange(i,j)) = 7; // all elements i through j
v(RWRange(i,j,2)) = 0; // every other element from i
// to j
The subscripts in this example are temporary objects of type RWRange. In all, there are five types which may be used as subscripts:
Integers and character strings, discussed in the previous sections
Three subscript classes:
RWRange objects, which select a range of elements, as in the above example;
RWToEnd objects, which select all elements from a given element on;
RWSlice objects, which select a set of elements with a given length and start position.
All three subscripting classes optionally allow an increment between successive selected elements. In addition, the global object RWAll selects all elements. Any of the subscript types may be mixed in any statement, and all the types may be used for vectors, matrices, and three-dimensional and four-dimensional arrays. In each case, the object returned by the subscripting operation is a new view of the existing data.
Note that if you examine the vector, matrix, and array header files, you see that there are really only two types of subscripts used in the definitions of operator(): int and const RWSlice&. All the other subscript types are automatically converted to instances of RWSlice by the compiler, either because they are already RWSlice objects (RWAll), because they are subclasses of RWSlice (RWRange and RWToEnd), or because a conversion constructor exists (char*). Since the subclasses RWRange and RWToEnd merely provide additional methods of constructing an RWSlice, without adding data or redefining functions, you can safely construct an RWSlice object from any subscript type without losing information. This can be useful in cases where you want to construct and use a subscript without knowing the precise type.
Here is an example showing how you can use subscripting to view planes of data in a 3-D array:
 
RWMathArray<double> A(10,10,10, rwUninitialized);
RWGenMat<double> xyplane = A(5,RWAll,RWAll);
RWGenMat<double> xzplane = A(RWAll,5,RWAll);
RWGenMat<double> yzplane = A(RWAll,RWAll,5);
Finally, here is how to create the three views used as the example in “Data and Views.”
 
RWGenMat<double> A("3x3 [ 1 4 7 2 5 8 3 6 9 ]");
RWRange I(0,1);
RWGenMat<double> Atl = A(I,I);
RWMathVec<double> v = A(1,RWAll);