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 Section 3.9.2, 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 Section 3.9.3.
>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>
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:
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 Section 3.3, "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);>
©Copyright 1999, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.