6.2 Data Parallel Array Operations

This section explains Fortran 90 array terminology, array assignment syntax, and FORALL structures.

6.2.1 Array Terminology

An array consists of elements that extend in one or more dimensions to represent columns, rows, planes, and so on. The number of dimensions in an array is called the rank of the array. The number of elements in a dimension is called the extent of the array in that dimension. The shape of an array is its rank, and its extent in each dimension. The size of an array is the product of the extents.

REAL, DIMENSION(10, 5:24, -5:M) :: A
REAL, DIMENSION(0:9, 20, M+6)   :: B

This example uses entity-oriented declaration syntax. The rank of A is 3, the shape of A is (10, 20, (M+6)), the extent of A in the second dimension is 20, and the size of A is 10 * 20 * (M+6).

Arrays can be zero-sized if the extent of any dimension is zero (certain restrictions apply to programs containing zero-sized arrays). The rank must be fixed at the time the program is written, but the extents in any dimension and the upper and lower bounds do not have to be fixed until the array comes into existence. Two arrays are conformable if they have the same shape, that is, the same rank and the same extents in corresponding dimensions; A and B are conformable.

For More Information:

6.2.2 Fortran 90 Array Assignment

Fortran 90 array assignment statements allow operations on entire arrays to be expressed more simply than was possible in Fortran 77. These array assignment statements are parallelized by the Digital Fortran 90 compiler for increased performance. A DO loop that is used to accomplish an array assignment will be parallelized only if it is marked with the INDEPENDENT directive.

For More Information:

6.2.2.1 Whole Array Assignment

In Fortran 90, the usual intrinsic operations for scalars (arithmetic, comparison, and logical) can be applied to arrays, provided the arrays are of the same shape. For example, if A, B, and C are two-dimensional arrays of the same shape, the statement C = A + B assigns each element of C with a value equal to the sum of the corresponding elements of A and B.

In more complex cases, this assignment syntax can have the effect of drastically simplifying the code. For instance, consider the case of three-dimensional arrays, such as the arrays dimensioned in the following declaration:

REAL D(10, 5:24, -5:M), E(0:9, 20, M+6)

In Fortran 77 syntax, an assignment to every element of D requires triply-nested loops, such as:

DO i = 1, 10
  DO j = 5, 24
    DO k= -5, M
      D(i,j,k) = 2.5*D(i,j,k) + E(i-1,j-4,k+6) + 2.0
    END DO
  END DO
END DO

In Fortran 90, this code can be expressed in a single line:

D = 2.5*D + E + 2.0

Routines coded in array assignment syntax are parallelized by the Digital Fortran 90 compiler for high performance under PSE. DO loops are parallelized only if they are marked with the INDEPENDENT directive.

In the example just given, the Fortran 90 version is parallelized by the Digital Fortran 90 compiler. The DO-loop version, however, is not eligible to be marked with the INDEPENDENT directive, and is therefore not parallelized.

For More Information:

6.2.2.2 Array Subsections

You can reference parts of arrays ("array subsections") using a notation known as subscript triplet notation. In subscript triplet notation, up to three parameters are specified for each dimension of the array. When a range of values is intended, the syntax of a subscript triplet is:

[a]:[b][:c]

Where a is the lower bound, b is the upper bound, and c is the stride (increment). The first colon is mandatory when a range of values is specified, even if a, b and c are all omitted. Default values are used when any (or all) of a, b, or c are omitted, as follows:

When a single value, rather than a range of values, is desired for a given dimension, a single parameter is specified, with no colons.

For example, consider the following code fragment, composed of an array declaration and an array subsection assignment:

REAL A(100, 100)
A(1,1:100:2) = 7

The assignment statement assigns a value of 7 to all the elements in the subsection of the array represented by the expression A(1,1:100:2). For the first dimension of the expression, the 1 is a single parameter, specifying a constant value of 1 for the first dimension. For the second dimension, the notation 1:100:2 is a subscript triplet in which 1 is the lower bound, 100 is the upper bound, and 2 is the stride. Therefore, the array subsection assignment in the code fragment assigns a value of 7 to the odd elements of the first row of A.

In the same array A, the four elements A(1,1), A(100,1), A(1, 100), and A(100, 100) reference the four corners of A. A(1:100:99, 1:100:99) is a 2 by 2 array section referencing all four corners. A(1, :) references the entire first row of A, because the colon is a place holder referencing the entire declared range of the second dimension. Similarly, A(100,:) references the entire last row of A.

As seen in Section 6.2.2.1, many whole array assignments can be expressed in a single line in Fortran 90. Similarly, many array subsection assignments can also be done in a single line. For example, consider the array subsection assignment expressed by this Fortran 77 DO loop:

DO x = k+1, n
  A(x, k) = A(x, k) / A(k, k)
END DO

Using Fortran 90 array assignment syntax, this same assignment requires only a single line:

A(k+1:n, k) = A(k+1:n, k) / A(k, k)

Fortran 90 array assignment syntax can also be used to assign a scalar to every element of an array:

REAL A(16, 32), S
A = S/2

For More Information:

6.2.3 FORALL

The FORALL statement is part of the ANSI Fortran 95 standard. FORALL is a natural idiom for expressing parallelism, and is parallelized by the Digital Fortran 90 compiler for high performance under PSE.

FORALL is a more generalized form of Fortran 90 array assignment syntax that allows a wider variety of array assignments to be expressed. For example, the diagonal of an array cannot be represented as a single array section. It can, however, be expressed in a FORALL statement:

REAL, DIMENSION(n, n) :: A
FORALL (i=1:n)  A(i, i) = 1

The FORALL/END FORALL structure can be used to include multiple assignment statements:

FORALL (i=k+1:n, j=k+1:n)
  A(i, j) = A(i, j) - A(i, k)*A(k, j)
  B(i, j) = A(i, j) + 1
END FORALL

In a FORALL/END FORALL structure, each line is computed separately. A FORALL/END FORALL structure produces exactly the same result as a separate FORALL statement for each line. The previous FORALL/END FORALL structure is equivalent to the following:

FORALL (i=k+1:n, j=k+1:n) A(i, j) = A(i, j) - A(i, k)*A(k, j)
FORALL (i=k+1:n, j=k+1:n) B(i, j) = A(i, j) + 1

Although FORALL structures serve the same purpose as some DO loops did in Fortran 77, a FORALL structure is an assignment statement (not a loop), and in many cases produces a different result from an analogous DO loop. For a comparison of DO loops and FORALL structures, see Section 2.2.3.

6.2.4 The INDEPENDENT Directive

Some DO loops are eligible to be tagged with the INDEPENDENT directive, which allows for parallel execution. This is very useful for converting pre-existing Fortran 77 code to HPF.

A loop is eligible be tagged INDEPENDENT if the iterations can be performed in any order (forwards, backwards, or even random) and still produce the same result. For example:

!HPF$ INDEPENDENT
      DO I=1, 100
        A(I) = B(I)
      END DO

Place the INDEPENDENT directive on the line immediately before the DO loop you wish to mark.

When DO loops are nested, you must evaluate each nesting level separately to determine whether it is eligible for the INDEPENDENT directive. For example:

      DO n = 100, 1, -1
!HPF$   INDEPENDENT, NEW(j)
        DO i = k+1, n
!HPF$     INDEPENDENT
          DO j = k+1, n
            A(i, j) = A(i, j) - A(i, k)*A(k, j) + n
          END DO
        END DO
      END DO

In this code fragment, each of the two inner DO loops can be marked INDEPENDENT, because the iterations of these loops can be performed in any random order without affecting the results. However, the outer loop cannot be marked independent, because its iterations must be performed in sequential order, or the results will be altered.

The NEW(j) keyword tells the compiler that in each iteration, the inner DO loop variable j is unrelated to the j from the previous iteration. Digital's compiler currently requires the NEW keyword in order to parallelize nested INDEPENDENT DO loops.

The three parallel structures (Fortran 90 array syntax, FORALL, and INDEPENDENT DO loops) differ from each other in syntax and semantics. Each has advantages and disadvantages. For a comparison between them, see Section 2.2.3.

A number of restrictions must be adhered to for INDEPENDENT DO loops to be successfully parallelized. For more information, refer to the Release Notes.

Unline FORALLs, INDEPENDENT DO loops can contain calls to procedures that are not PURE. However, special ON HOME RESIDENT syntax must be used for INDEPENDENT loops that contain procedure calls. For more information, refer to the Release Notes.

For More Information:

6.2.5 Vector-Valued Subscripts

Vector-valued subscripts provide a more general way to select a subset of array elements than subscript triplet notation (subscript triplet notation is explained previously, Section 6.2.2.2). A vector-valued subscript is a one- dimensional array of type INTEGER (a vector) that is used as a subscript for one dimension of another array. The elements of this index vector select the elements of the indexed array to be in the subsection. For example, consider the following code fragment:

INTEGER A(3)
INTEGER B(6, 4)
FORALL (i=1:3) A(i) = 2*i - 1
B(A, 3) = 12

In this code fragment, the FORALL statement assigns the values (/1, 3, 5/) to the index vector A. The assignment statement uses these three values to decide which elements of B to assign a value of 12. Using these values, it assigns a value of 12 to B(1, 3), B(3, 3), and B(5, 3).

A vector-valued subscript with duplicate values must not occur on the left-hand side of an assignment statement, because this could lead to indeterminate program results. For example, the following code fragment is illegal:

INTEGER A(4)
INTEGER B(0:5, 4)
FORALL (i=1:4) A(i) = (i-2)*(i-3)
FORALL (i=1:4) B(A(i), 4) = i        ! Illegal assignment !

In this example, the first FORALL statement assigns to A the values (/2, 0, 0, 2/). However, the values that are assigned in the second FORALL statement are impossible to predict. The second FORALL statement assigns two different values to B(2, 4), and two different values to B(0, 4). Unlike a DO loop, which makes assignments in a predictable sequential order, a FORALL construct is a parallel structure that can assign values to many array elements simultaneously. It is impossible to predict which of the duplicate values assigned to these elements will remain after the execution of the statement is completed.

Because it is costly in terms of performance for the compiler to check for duplicate elements in vector-valued subscripts, illegal code does not necessarily generate an error message. It is up to the programmer to avoid this mistake.

The HPF library routine COPY_SCATTER permits duplicate values on the left side of an assignment statement. COPY_SCATTER is subject to certain restrictions and can produce indeterminate program results. See the online man page for copy_scatter.

6.2.6 Entity-Oriented Declaration Syntax

In Fortran 90, arrays can be organized either by attribute, as in FORTRAN 77, or by entity. The :: notation is used in the entity- oriented declaration form, in which you can group the type, the attributes, and the optional initialization value of an entity into a single statement. For example:

INTEGER, DIMENSION(4), PARAMETER :: PERMUTATION = (/1,3,2,4/)

6.2.7 SEQUENCE and NOSEQUENCE Directives

The SEQUENCE directive indicates that data objects in a procedure depend upon array element order or storage association. The SEQUENCE directive warns the compiler not to map data across processors. You can use the SEQUENCE directive with or without a list of arrays. The form of the directive without a list of arrays is:

!HPF$ SEQUENCE

This form of the directive instructs the compiler to assume that all arrays in this procedure depend on sequence association. The form of the directive with a list of arrays is:

!HPF$ SEQUENCE X, Y, Z

This directive instructs the compiler that only X, Y, and Z rely upon sequence association.

Arrays with the SEQUENCE attribute may not be named in a DISTRIBUTE or ALIGN directive. Array operations involving such arrays are performed serially, with no parallel speed-up. Also, DISTRIBUTE or ALIGN directives may not appear in the same procedure as a SEQUENCE directive. An error message is generated at compile time if an array with the SEQUENCE attribute is improperly named in a DISTRIBUTE or ALIGN directive.

In programs compiled with the -wsf option, element order and storage association apply only when explicitly requested with the SEQUENCE directive. When the -wsf option is not used, sequence association is always in place.

The NOSEQUENCE directive asserts that named data objects, or all data objects in a procedure, do not depend on array element order or storage association. The form of this directive is:

!HPF$ NOSEQUENCE

The NOSEQUENCE directive is the default when the -wsf option is used. The SEQUENCE directive is the default when the -wsf option is not used.

6.2.8 Out of Range Subscripts

In older versions of Fortran, some programmers developed the practice of using out of range subscripts, as in the following (illegal) example:

REAL A(50, 50)
DO i = 1, 2500
  A(i, 1) = 8
END DO

This code is illegal, although it can produce correct results in nonparallel implementations of Fortran. Referencing an out of range subscript does not necessarily generate an error message. However, in cases where the variable referenced is distributed, use of such code causes an application to stall or produce incorrect results when executed in parallel on a PSE cluster.

The -check_bounds command-line option is not compatible with parallel HPF programs. The -check_bounds option should not be used together with the -wsf option.