1

My understanding of forall statements is that they are executed in parallel, while for statements are executed in serial. Indeed, the following code seems to confirm this expectation (i.e., a random sequence only for forall because of threading):

for i in 1..5 do writeln( i * 10 );
10
20
30
40
50

forall i in 1..5 do writeln( i * 10 );
10
50
20
30
40

On the other hand, if I use forall (or equivalent [...]) on the right-hand side as an expression

var A = ( forall i in 1..5 do i * 10 );
var B = [ i in 1..5 ] i * 10;

var X = ( forall a in A do a );
var Y = [ a in A ] a;

var P = ( for i in 1..5 do i * 10 );  // for comparison

writeln( "A = ", A );
writeln( "B = ", B );
writeln( "X = ", X );
writeln( "Y = ", Y );
writeln( "P = ", P );

all the results become the same (i.e., ordered from 10 to 50):

A = 10 20 30 40 50
B = 10 20 30 40 50
X = 10 20 30 40 50
Y = 10 20 30 40 50
P = 10 20 30 40 50

Does this mean that forall expressions on the right-hand side of assignment are always executed in serial? If so, is the corresponding [...] also equivalent to for expressions in this context?

Community
  • 1
  • 1
roygvib
  • 7,218
  • 2
  • 19
  • 36

1 Answers1

3

Good question. You're correct that using forall expressions ( explicit or []-"bracketed" ) in this way generates deterministic results, but the forall expression does still result in a parallel execution.

Expressions like yours effectively result in a zippered iteration, which is defined such that corresponding iterations will match up. For example, in , seeming "whole-array" operations like:

var A, B, C: [1..10] real;
A = B + C;

are equivalent ( promoted ) to an execution of a zippered forall loop:

var A, B, C: [1..10] real;
forall (a, b, c) in zip(A, B, C) do
  a = b + c;

Both of these expressions :
(a) specify parallel execution,
(b) ensure that corresponding elements of A, B, and C arrays are used within each instance of the loop body (otherwise the language would not be very useful).

Taking one of your examples,

...B = [ i in 1..5 ] i * 10...

is equivalent to:

forall (b, v) in zip(B, [i in 1..5] i * 10) do
  b = v;

or:

forall (b, i) in zip(B, 1..5) do
  b = i * 10;

and similarly for the other variations you provided.

This is accomplished in Chapel by using a concept known as leader-follower iterators. These were originally described in a paper published at PGAS 2011 named User-Defined Parallel Zippered Iterators in Chapel whose slides are here. They are also described in a Chapel primer on parallel iterators.

user3666197
  • 1
  • 6
  • 50
  • 92
Brad
  • 3,839
  • 7
  • 25
  • Thanks very much for your explanation. I will read the suggested paper and primer pages carefully later. This needs more experience... Thanks :) – roygvib May 04 '17 at 18:52
  • 3
    The paper and primer are very much about how parallel zippered loops are implemented such that correspondence between the values yielded by the expressions is preserved. The following users guide section describes more about the equivalence between promoted expressions and zippered iteration: http://chapel.cray.com/docs/latest/users-guide/datapar/promotion.html – Brad May 04 '17 at 19:04
  • I'm not sure it came across in Brad's answer, but a statement like var B = [ i in 1..5 ] i; creates a new array variable B to store the result of the forall loop. This is a form of "promoted expression" that Brad mentioned. – mppf May 04 '17 at 19:37