Interpreting masked array assignments

To understand how to interpret masked array assignments, you need to understand the concepts of a control mask (mc) and a pending control mask (mp):
  • The mc is an array of type logical whose value determines which elements of an array in a where_assignment_statement will be defined. This value is determined by the execution of one of the following:
    • a WHERE statement
    • a WHERE construct statement
    • an ELSEWHERE statement
    • a masked ELSEWHERE statement
    • an END WHERE statement
    The value of mc is cumulative; the compiler determines the value using the mask expressions of surrounding WHERE statements and the current mask expression. Subsequent changes to the value of entities in a mask_expr have no effect on the value of mc. The compiler evaluates the mask_expr only once for each WHERE statement, WHERE construct statement, or masked ELSEWHERE statement.
  • The mp is a logical array that provides information to the next masked assignment statement at the same nesting level on the array elements not defined by the current WHERE statement, WHERE construct statement, or masked ELSEWHERE statement.
The following describes how the compiler interprets statements in a WHERE, WHERE construct, masked ELSEWHERE, ELSEWHERE, or END WHERE statement. It describes the effect on mc and mp and any further behavior of the statements, in order of occurrence.
  • WHERE statement
    • If the WHERE statement is nested in a WHERE construct, the following occurs:
      1. mc becomes mc .AND. mask_expr.
      2. After the compiler executes the WHERE statement, mc has the value it had prior to the execution of the WHERE statement.
    • Otherwise, mc becomes the mask_expr.
  • WHERE construct
    • If the WHERE construct is nested in another WHERE construct, the following occurs:
      1. mp becomes mc .AND. (.NOT. mask_expr).
      2. mc becomes mc .AND. mask_expr.
    • Otherwise:
      1. The compiler evaluates the mask_expr, and assigns mc the value of that mask_expr.
      2. mp becomes .NOT. mask_expr.
  • Masked ELSEWHERE statement
    The following occurs:
    1. mc becomes mp.
    2. mp becomes mc .AND. (.NOT. mask_expr).
    3. mc becomes mc .AND. mask_expr.
  • ELSEWHERE statement
    The following occurs:
    1. mc becomes mp. No new mp value is established.
  • END WHERE statement

    After the compiler executes an END WHERE statement, mc and mp have the values they had prior to the execution of the corresponding WHERE construct statement.

  • where_assignment_statement

    The compiler assigns the values of the expr that correspond to the true values of mc to the corresponding elements of the variable.

If a non-elemental function reference occurs in the expr or variable of a where_assignment_statement or in a mask_expr, the compiler evaluates the function without any masked control; that is, it fully evaluates all of the function's argument expressions and then it fully evaluates the function. If the result is an array and the reference is not within the argument list of a non-elemental function, the compiler selects elements corresponding to true values in mc for use in evaluating the expr, variable, or mask_expr.

If an elemental intrinsic operation or function reference occurs in the expr or variable of a where_assignment_statement or in a mask_expr, and is not within the argument list of a non-elemental function reference, the compiler performs the operation or evaluates the function only for the elements corresponding to true values in mc.

If an array constructor appears in a where_assignment_statement or in a mask_expr, the compiler evaluates the array constructor without any masked control and then executes the where_assignment_statement or evaluates the mask_expr.

The execution of a function reference in the mask_expr of a WHERE statement is allowed to affect entities in the where_assignment_statement. Execution of an END WHERE has no effect.

The following example shows how control masks are updated. In this example, mask1, mask2, mask3, and mask4 are conformable logical arrays, mc is the control mask, and mp is the pending control mask. The compiler evaluates each mask expression once.

Sample code (with statement numbers shown in the comments):
WHERE (mask1)        ! W1 
  WHERE (mask2)      ! W2 
  ...                ! W3 
  ELSEWHERE (mask3)  ! W4 
  ...                ! W5 
  END WHERE          ! W6 
ELSEWHERE (mask4)    ! W7 
...                  ! W8 
ELSEWHERE            ! W9
...                  ! W10
END WHERE            ! W11

The compiler sets control and pending control masks as it executes each statement, as shown below:

Statement W1
    mc = mask1
    mp = .NOT. mask1
Statement W2
    mp = mask1 .AND. (.NOT. mask2)
    mc = mask1 .AND. mask2
Statement W4
    mc = mask1 .AND. (.NOT. mask2)
    mp = mask1 .AND. (.NOT. mask2)
.AND. (.NOT. mask3)

    mc = mask1 .AND. (.NOT. mask2)
.AND. mask3

Statement W6
    mc = mask1
    mp = .NOT. mask1

Statement W7
    mc = .NOT. mask1
    mp = (.NOT. mask1) .AND. (.NOT.
mask4)

    mc = (.NOT. mask1) .AND. mask4
Statement W9
    mc = (.NOT. mask1) .AND. (.NOT.
mask4)

Statement W11
    mc = 0
    mp = 0

The compiler uses the values of the control masks set by statements W2, W4, W7, and W9 when it executes the respective where_assignment_statements W3, W5, W8, and W10.

Migration Tip:

Simplify logical evaluation of arrays

FORTRAN 77 source:
INTEGER A(10,10),B(10,10)
     ⋮
DO I=1,10
  DO J=1,10
    IF (A(I,J).LT.B(I,J)) A(I,J)=B(I,J)
  END DO
END DO
END
Fortran 90 or Fortran 95 source:
INTEGER A(10,10),B(10,10)
     ⋮
WHERE (A.LT.B) A=B
END

Examples

REAL, DIMENSION(10) :: A,B,C,D
WHERE (A>0.0)
  A = LOG(A)          ! Only the positive elements of A
                      !   are used in the LOG calculation.
  B = A               ! The mask uses the original array A
                      !   instead of the new array A.
  C = A / SUM(LOG(A)) ! A is evaluated by LOG, but
                      !   the resulting array is an
                      !   argument to a non-elemental
                      !   function. All elements in A will
                      !   be used in evaluating SUM.
END WHERE

WHERE (D>0.0)
  C = CSHIFT(A, 1)    ! CSHIFT applies to all elements in array A,
                      ! and the array element values of D determine
                      ! which CSHIFT expression determines the
                      ! corresponding element values of C.
ELSEWHERE
  C = CSHIFT(A, 2)
END WHERE
END
The following example shows an array constructor in a WHERE construct statement and in a masked ELSEWHERE mask_expr:
CALL SUB((/ 0, -4, 3, 6, 11, -2, 7, 14 /))

CONTAINS
  SUBROUTINE SUB(ARR)
  INTEGER ARR(:)
  INTEGER N

  N = SIZE(ARR)

  ! Data in array ARR at this point:
  !
  ! A = | 0 -4 3 6 11 -2 7 14 |

  WHERE (ARR < 0)
    ARR = 0
  ELSEWHERE (ARR < ARR((/(N-I, I=0, N-1)/)))
    ARR = 2
  END WHERE

  ! Data in array ARR at this point:
  !
  ! A = | 2 0 3 2 11 0 7 14 |

  END SUBROUTINE
END
The following example shows a nested WHERE construct statement and masked ELSEWHERE statement with a where_construct_name:
INTEGER :: A(10, 10), B(10, 10)
...
OUTERWHERE: WHERE (A < 10)
  INNERWHERE: WHERE (A < 0)
    B = 0
  ELSEWHERE (A < 5) INNERWHERE
    B = 5
  ELSEWHERE INNERWHERE
    B = 10
  END WHERE INNERWHERE
ELSEWHERE OUTERWHERE
  B = A
END WHERE OUTERWHERE
...


Voice your opinion on getting help information Ask IBM compiler experts a technical question in the IBM XL compilers forum Reach out to us