Jive reference manual
Array expressions

Jem provides a set of overloaded operators and functions for writing expressions that operate on all elements of one or more arrays. These operators and functions return special array objects, called array expressions, that can be assigned to regular Array objects. Array expressions can also be passed to the overloaded operators and functions to create new array expressions.

Here is an example:

Array<double,2> a ( 10, 10 );
Array<double,2> b ( 10, 10 );
Array<double,2> c ( 10, 10 );
// init a ...
b = 1.0 + sin( a );
c = a * a + pow( b, 2.0 );

This code fragment is equivalent with:

Array<double,2> a ( 10, 10 );
Array<double,2> b ( 10, 10 );
Array<double,2> c ( 10, 10 );
int i, j;
// init a ...
for ( j = 0; j < 10; j++ )
{
for ( i = 0; i < 10; i++ )
{
b(i,j) = 1.0 + sin( a(i,j) );
}
}
for ( j = 0; j < 10; j++ )
{
for ( i = 0; i < 10; i++ )
{
c(i,j) = a(i,j) * a(i,j) + pow( b(i,j), 2.0 );
}
}

An array expression can be viewed as a compound object that comprises a set of operators and functions, and a set of operands. The latter set consists of Array objects, scalars and other array expression objects. For instance, the array expression (1.0 + sin(a)) consists of the + operator, the scalar 1.0 and the array expression sin(a). This last expression comprises the function sin and the Array object a.

An array expression can also be viewed as a type of array that has the same shape as its operands. The elements of an array expression are obtained by applying its operators and functions to the elements of its operands. Thus, the element (i,j) of the array expression (1.0 + sin(a)) equals (1.0 + sin(a(i,j))). Note that this implies that all operators and functions are applied element-wise. This also implies that all operands of an array expression must have the same shape.

If a scalar, such as 1.0, is one of the operands of an array expression, it is implicitly converted to an array-like object that has the same shape as the other operands involved in the array expression. The elements of this array-like object are all equal to the scalar.

Array expressions come in two flavors: rvalue array expressions and lvalue array expressions. An rvalue expression can only be used as the right-hand side in an assignment statement or as the input parameter of a function. An lvalue array expression, on the other hand, can also be used as the left-hand side in an assignment statement and as the output parameters of a function. Note that an lvalue expression can also be used as an rvalue expression.

Almost all overloaded functions and operators provided by jem create rvalue array expressions. At this time, only the select() function creates lvalue array expressions. For more information, see the page on array selections.

The use of array expressions is often more efficient than writing a series of equivalent (nested) loops. One reason is that the implementation of array expressions is based on `expression templates', a technique that makes it possible to avoid creating temporary array objects (see the papers available at http://oonumerics.org for the details). Another reason is that array expressions collapse multiple nested loops into a single loop in the common case that all the operands are stored contiguously in memory. For instance, the statement

b = 1.0 + sin(a);

in the previous example will expand to:

for ( i = 0; i < 100; i++ )
{
b.setFast( i, 1.0 + sin( a.getFast(i) ) );
}

The following sections provide an overview of the overloaded operators and functions that can be used to create array expressions.

Unary operators

#include <jem/base/array/operators.h> or
#include <jem/base/Array.h>.

Supported unary operators:

These operators can be called with either an Array object or an array expression. Each returns an rvalue array expression that applies the unary operator to the elements of the array argument. The elements of the array expression are of the same type as the elements of the array argument.

The unary operators are defined in the header file <jem/base/array/operators.h>. They are also available through the general header file <jem/base/Array.h>.

Binary operators

#include <jem/base/array/operators.h> or
#include <jem/base/Array.h>.

Supported binary arithmetic operators:

Supported binary bitwise operators:

Supported binary logical operators:

Supported comparison operators:

All the operators listed above can be called with two Array objects, two array expressions, or one Array object and one array expression. They can also be called with an Array object and a scalar, or an array expression and a scalar. They return an rvalue array expression that applies the operator to the elements of the array arguments and/or scalar argument. The elements of the array arguments and/or the scalar argument must be of the same type; one can not, for instance, add an integer array to a floating point array.

All operators except the comparison operators return an array expression of which the elements are of the same type as the elements of the array arguments and/or scalar argument. The comparison operators return an array expression of which the elements are of type bool.

The binary operators are defined in the header file <jem/base/array/operators.h>. They are also available through the general header file <jem/base/Array.h>.

Unary functions

#include <jem/base/array/intrinsics.h> or
#include <jem/base/Array.h>.

The following unary functions can be called with an Array object or an array expression:

Each function returns an rvalue array expression that applies the function to the elements of the array argument. The elements of the array expression are of the same type as the elements of the array argument.

The unary functions listed above are defined in the header file <jem/base/array/intrinsics.h>. They are also available through the general header file <jem/base/Array.h>.

Binary functions

#include <jem/base/array/intrinsics.h> or
#include <jem/base/Array.h>.

The binary function pow can be called with two Array objects, two array expressions, or one Array object and one array expression. It can also be called with an Array object and a scalar, or an array expression and a scalar. The pow function returns an rvalue array expression that applies the pow function to all elements of the array arguments and/or scalar argument. The elements of the returned array expression are of the same type as the elements of the array arguments and/or scalar argument.

The pow funtion is defined in the header file <jem/base/array/intrinsics.h>. It is also available through the general header file <jem/base/Array.h>.

Other functions

#include <jem/base/array/intrinsics.h> or
#include <jem/base/Array.h>.

Two other functions that create rvalue array expressions are castTo and where. The first one can be used to convert the elements of an array from one type to another type. It is called like this:

castTo<T> ( a )

where T is the target type of the conversion, and a is an Array or an array expression. The castTo function returns an rvalue array expression that applies the static_cast<T> operator to all the elements of the array argument. The elements of the returned array expression are of type T.

Example:

Array<float,2> a ( 10, 10 );
Array<int,2> b ( 10, 10 );
// init a ...
b = castTo<int> ( a )

which is the same as:

Array<float,2> a ( 10, 10 );
Array<int,2> b ( 10, 10 );
int i, j;
// init a ...
for ( j = 0; j < 10; j++ )
{
for ( i = 0; i < 10; i++ )
{
b(i,j) = static_cast<int> ( a(i,j) );
}
}

The function where mimicks the conditional operator (?:). It is called as follows:

where ( mask, lhs, rhs )

where mask is an Array object or an array expression with elements of type bool. The arguments lhs and rhs should be Array objects, array expressions, scalars, or a combination of these. The where function returns an rvalue array expression that applies the conditional (?:) operator to all the elements of its three arguments. The elements of the array expression are of the same type as the elements of the array arguments and/or scalar arguments.

Example:

Array<float,2> a ( 10, 10 );
Array<float,2> b ( 10, 10 );
// init a ...
b = where ( a > 1.0, a, 0.0 );

which is equivalent with:

Array<float,2> a ( 10, 10 );
Array<float,2> b ( 10, 10 );
int i, j;
// init a ...
for ( j = 0; j < 10; j++ )
{
for ( i = 0; i < 10; i++ )
{
b(i,j) = ( a(i,j) > 1.0 ) ? a(i,j) : 0.0;
}
}

The funtions castTo and where are defined in the header file <jem/base/array/intrinsics.h>. They are also available through the general header file <jem/base/Array.h>.