Context and ifp()

Sometimes you wish to perform an operation on only a subset of the elements of a vector or matrix. In the following example, we wish to compute the absolute value of a vector A:

ifp (A < 0) B = -A; else B = A; The ifp() statement works much like an if() statement in C, except that it works in parallel, and the condition is a vector or matrix condition. In the example above, the expression A < 0 is a vector condition. In parallel, every element of A is compared with 0, resulting in a boolean value (true or false). (Thus, the result of such a comparison is a booleanVector). The subset of elements (virtual processors) where the expression was true executes the then clause. The subset of elements (virtual processors) where the expression was false executes the else clause, if any. In this example, every element of B will be assigned some value, either -A or A, as appropriate. Note that both clauses are always executed; it's just that a different set of virtual processors are active in each clause.

Here's another example:

ifp (A != 0) B /= A; else B = 0;

ifp() may be nested. Each ifp reduces the size of the set of virtual processors that are active. Thus, in

ifp (A == B) C = 0; // A == B here else ifp (A < B) // A != B here C = -1; // A < B here else C = 1; // A > B here The second ifp() is part of the else clause of the first ifp, so it is only executed by those virtual processors who are active there, i.e., those who found their elements A != B.

Context.

Within one of the clauses of an ifp() statement, as we said, some subset of the virtual processors are active. Some subset of which set of virtual processors? Of those that correspond to the elements in the vector or matrix condition provided to ifp(). Any other vectors or matrices used within the clause must have the same shape , i.e., be a vector of the same size, or a matrix with the same number of rows and columns, as that in the condition expression. (Otherwise, what subset of virtual processors would be active in that vector or matrix?) Thus, in intVector A(10), B(10), C(20); ... ifp (A > 0) B = A; // ok else C = A; // error: C has a different shape

It is often convenient to define

const intVector VP(N, Identity); const intMatrix VProw(N, M, IdentityR); const intMatrix VPcol(N, M, IdentityC); for use in situations that depend on the position, e.g., intVector X(N); ... ifp (VP % 2 == 0) // here we can work with X[i] where i is even else // here we can work with X[i] where i is odd
A subtle point about slices and context: most of the time, slices act like a vector, but they can also act like a matrix. For example, in intVector A(N); intMatrix B(N,N); const intVector VP(N, Identity); const intMatrix VProw(N, N, IdentityR); const intMatrix VPcol(N, N, IdentityC); ... ifp (VP % 2 == 0) B[2][_] = 33; // assign 33 to row 2 of matrix B ifp (VPcol % 2 == 0) B[2][_] = 33; // assign 33 to row 2 of matrix B the context in the first ifp is that of an N-element vector, and in the second ifp is that of an NxN-element matrix. Both have the same effect, however. In other words, when deciding whether the virtual processors of a slice are active, if the context is a vector, the slice is thought of like a vector, and if the context is a matrix, the slice is thought of like a matrix (using the appropriate row or column of the context to determine the activeness of elements in the slice). This shows up in the gauss example.