Note: This page has been translated by MathWorks. Please click here

To view all translated materals including this page, select Japan from the country navigator on the bottom of this page.

To view all translated materals including this page, select Japan from the country navigator on the bottom of this page.

MATLAB^{®} supports an important exception, called reduction,
to the rule that loop iterations must be independent. A *reduction
variable* accumulates a value that depends on all the iterations
together, but is independent of the iteration order. MATLAB allows
reduction variables in `parfor`

-loops.

Reduction variables appear on both sides of an assignment statement,
such as any of the following, where `expr`

is a MATLAB expression.

`X = X + expr` | `X = expr + X` |

`X = X - expr` | See Associativity in Reduction Assignments in Requirements for Reduction Assignments |

`X = X .* expr` | `X = expr .* X` |

`X = X * expr` | `X = expr * X` |

`X = X & expr` | `X = expr & X` |

`X = X | expr` | `X = expr | X` |

`X = [X, expr]` | `X = [expr, X]` |

`X = [X; expr]` | `X = [expr; X]` |

`X = min(X, expr)` | `X = min(expr, X)` |

`X = max(X, expr)` | `X = max(expr, X)` |

`X = union(X, expr)` | `X = union(expr, X)` |

`X = intersect(X, expr)` | `X = intersect(expr, X)` |

Each of the allowed statements listed in this table is referred
to as a *reduction assignment*. By definition,
a reduction variable can appear only in assignments of this type.

The general form of a reduction assignment is

`X = f(X, expr)` | `X = f(expr, X)` |

The following example shows a typical usage of a reduction variable `X`

.

X = ...; % Do some initialization of X parfor i = 1:n X = X + d(i); end

This loop is equivalent to the following, where you calculate
each `d(i)`

by a different iteration.

X = X + d(1) + ... + d(n)

In a regular `for`

-loop, the variable `X`

would
get its value either before entering the loop or from the previous
iteration of the loop. However, this concept does not apply to `parfor`

-loops.

In a `parfor`

-loop, the value of `X`

is
never transmitted from client to workers or from worker to worker.
Rather, additions of `d(i)`

are done in each worker,
with `i`

ranging over the subset of `1:n`

being
performed on that worker. The results are then transmitted back to
the client, which adds the partial sums of the workers into `X`

.
Thus, workers do some of the additions, and the client does the rest.

If your `parfor`

code does not adhere to
the guidelines and restrictions labeled as **Required**,
you get an error. MATLAB catches some of these errors at the
time it reads the code, and others when it executes the code. These
errors are labeled as **Required (static)** or **Required (dynamic)** respectively. Guidelines
that do not cause errors are labeled as **Recommended**.
You can use MATLAB Code Analyzer to help `parfor`

-loops
comply with the guidelines.

The following requirements further define the reduction assignments associated with a given variable.

Required (static): For any
reduction variable, the same reduction function or operation must
be used in all reduction assignments for that variable. |

The `parfor`

-loop on the left is not valid
because the reduction assignment uses `+`

in one
instance, and `[,]`

in another. The `parfor`

-loop
on the right is valid.

Invalid | Valid |
---|---|

parfor i = 1:n if testLevel(k) A = A + i; else A = [A, 4+i]; end % loop body continued end | parfor i = 1:n if testLevel(k) A = A + i; else A = A + i + 5*k; end % loop body continued end |

Required (static): If the
reduction assignment uses `*` , `[,]` ,
or `[;]` , then `X` must be consistently
specified as the first or second argument in every reduction assignment. |

The `parfor`

-loop on the left is not valid
because the order of items in the concatenation is not consistent
throughout the loop. The `parfor`

-loop on the right
is valid.

Invalid | Valid |
---|---|

parfor i = 1:n if testLevel(k) A = [A, 4+i]; else A = [r(i), A]; end % loop body continued end | parfor i = 1:n if testLevel(k) A = [A, 4+i]; else A = [A, r(i)]; end % loop body continued end |

*Reduction Assignments.* In addition to the
specific forms of reduction assignment listed in the table in Reduction Variables, the only other (and
more general) form of a reduction assignment is

`X = f(X, expr)` | `X = f(expr, X)` |

Required (static): `f` can
be a function or a variable. If `f` is a variable,
then you cannot change `f` in the `parfor` body
(in other words, it is a broadcast variable). |

If `f`

is a variable, then for all practical
purposes its value at run time is a function handle. However, as long
as the right side can be evaluated, the resulting value is stored
in `X`

.

The `parfor`

-loop on the left does not execute
correctly because the statement `f = @times`

causes `f`

to
be classified as a temporary variable. Therefore `f`

is
cleared at the beginning of each iteration. The `parfor`

-loop
on the right is correct, because it does not assign `f`

inside
the loop.

Invalid | Valid |
---|---|

f = @(x,k)x * k; parfor i = 1:n a = f(a,i); % loop body continued f = @times; % Affects f end | f = @(x,k)x * k; parfor i = 1:n a = f(a,i); % loop body continued end |

The operators `&&`

and `||`

are
not listed in the table in Reduction Variables. Except for `&&`

and `||`

,
all the matrix operations of MATLAB have a corresponding function `f`

,
such that `u op v`

is equivalent to `f(u,v)`

.
For `&&`

and `||`

, such
a function cannot be written because `u&&v`

and `u||v`

might
or might not evaluate `v`

. However, `f(u,v)`

*always* evaluates `v`

before
calling `f`

. Therefore `&&`

and `||`

are
excluded from the table of allowed reduction assignments for a `parfor`

-loop.

Every reduction assignment has an associated function `f`

.
The properties of `f`

that ensure deterministic behavior
of a parfor statement are discussed in the following sections.

*Associativity in Reduction Assignments.* The following practice
is recommended for the function `f`

, as used in the
definition of a reduction variable. However, this rule does not generate
an error if not adhered to. Therefore, it is up to you to ensure that
your code meets this recommendation.

Recommended: To get deterministic
behavior of `parfor` -loops, the reduction function `f` must
be associative. |

To be associative, the function `f`

must satisfy
the following for all `a`

, `b`

,
and `c`

.

f(a,f(b,c)) = f(f(a,b),c)

The classification rules for variables, including reduction
variables, are purely syntactic. They cannot determine whether the `f`

you
have supplied is truly associative or not. Associativity is assumed,
but if you violate this rule, each execution of the loop might result
in different answers.

The addition of mathematical real numbers is associative. However,
the addition of floating-point numbers is only approximately associative.
Different executions of this `parfor`

statement might
produce values of `X`

with different round-off errors.
You cannot avoid this cost of parallelism.

For example, the statement on the left yields 1, while the statement
on the right returns 1 + `eps`

:

(1 + eps/2) + eps/2 1 + (eps/2 + eps/2)

Except for the minus operator (`-`

), all special
cases listed in the table in Reduction Variables have a corresponding (approximately)
associative function. MATLAB calculates the assignment `X = X - expr`

by
using `X = X + (-expr)`

. (So, technically, the function for calculating this
reduction assignment is `plus`

, not `minus`

.)
However, the assignment `X = expr - X`

cannot be written using an associative function, which
explains its exclusion from the table.

*Commutativity in Reduction Assignments.* Some associative
functions, including `+`

, `.*`

, `min`

, and `max`

, `intersect`

, and `union`

,
are also commutative. That is, they satisfy the following for all `a`

and `b`

.

f(a,b) = f(b,a)

Noncommutative functions include `*`

(because
matrix multiplication is not commutative for matrices in which both
dimensions have size greater than one), `[,]`

, and `[;]`

.
Noncommutativity is the reason that consistency in the order of arguments
to these functions is required. As a practical matter, a more efficient
algorithm is possible when a function is commutative as well as associative,
and `parfor`

is optimized to exploit commutativity.

Recommended: Except in the
cases of `*` , `[,]` , and `[;]` ,
the function `f` of a reduction assignment must be
commutative. If `f` is not commutative, different
executions of the loop might result in different answers. |

Violating the restriction on commutativity in a function used for reduction could result in unexpected behavior, even if it does not generate an error.

Unless `f`

is a known noncommutative built-in
function, it is assumed to be commutative. There is currently no way
to specify a user-defined, noncommutative function in `parfor`

.

*Overloading in Reduction Assignments.* Most associative
functions `f`

have an identity element `e`

,
so that for any `a`

, the following holds true.

f(e,a) = a = f(a,e)

Examples of identity elements for some functions are listed here.

Function | Identity Element |
---|---|

`+` | `0` |

`*` and `.*` | `1` |

`[,]` and `[;]` | `[]` |

`&` | `true` |

`|` | `false` |

MATLAB uses the identity elements of reduction functions when it knows them. So, in addition to associativity and commutativity, also keep identity elements in mind when overloading these functions.

Recommended: An overload of
`+` , `*` , `.*` , `[,]` ,
or `[;]` must be associative if it is used in a reduction
assignment in a `parfor` -loop. The overload must
treat the respective identity element in the table (all with class `double` )
as an identity element. |

Recommended: An overload of `+` , `.*` , `union` ,
or `intersect` must be commutative. |

There is no way to specify the identity element for a function.
In these cases, the behavior of `parfor`

is less
efficient than for functions with a known identity element, but the
results are correct.

Similarly, because of the special treatment of ```
X =
X - expr
```

, the following is recommended.

Recommended: An overload of
the minus operator (`-` ) must obey the mathematical
law that `X - (` is equivalent to `(X - ` . |

Suppose that each iteration of a loop performs some calculation, and you are interested in finding which iteration of a loop produces the maximum value. This reduction exercise makes an accumulation across multiple iterations of a loop. Your reduction function must compare iteration results, until the maximum value can be determined after all iterations are compared.

First consider the reduction function itself. To compare one iteration result against another, the function requires as input the current result and the known maximum from other iterations so far. Each of the two inputs is a vector containing iteration results and iteration number.

function mc = comparemax(A, B) % Custom reduction function for 2-element vector input if A(1) >= B(1) % Compare the two input data values mc = A; % Return the vector with the larger result else mc = B; end

Inside the loop, each iteration calls the reduction function
(`comparemax`

), passing in a pair of two-element
vectors:

The accumulated maximum and its iteration index, which is the reduction variable

`cummax`

The iteration value and index

If the data value of the current iteration is greater than the
maximum in `cummmax`

, the function returns a vector
of the new value and its iteration number. Otherwise, the function
returns the existing maximum and its iteration number.

Each iteration calls the reduction function `comparemax`

to
compare its own data `[dat i]`

to data already accumulated
in `cummax`

. Try the following code for this loop.

% First element of cummax is maximum data value % Second element of cummax is where (iteration) maximum occurs cummax = [0 0]; % Initialize reduction variable parfor ii = 1:100 dat = rand(); % Simulate some actual computation cummax = comparemax(cummax, [dat ii]); end disp(cummax);

Was this topic helpful?