## Classification of Variables in `parfor`-Loops

### Overview

MATLAB® Coder™ classifies variables inside a `parfor`-loop into one of the categories in the following table. It does not support variables that it cannot classify. If a `parfor`-loop contains variables that cannot be uniquely categorized or if a variable violates its category restrictions, the `parfor`-loop generates an error.

ClassificationDescription
LoopServes as a loop index for arrays
SlicedAn array whose segments are operated on by different iterations of the loop
BroadcastA variable defined before the loop whose value is used inside the loop, but not assigned inside the loop
ReductionAccumulates a value across iterations of the loop, regardless of iteration order
TemporaryA variable created inside the loop, but unlike sliced or reduction variables, not available outside the loop

Each of these variable classifications appears in this code fragment:

```a=0; c=pi; z=0; r=rand(1,10); parfor i=1:10 a=i; % 'a' is a temporary variable z=z+i; % 'z' is a reduction variable b(i)=r(i); % 'b' is a sliced output variable; % 'r' a sliced input variable if i<=c % 'c' is a broadcast variable d=2*a; % 'd' is a temporary variable end end```

### Sliced Variables

A sliced variable is one whose value can be broken up into segments, or slices, which are then operated on separately by different threads. Each iteration of the loop works on a different slice of the array.

In the next example, a slice of `A` consists of a single element of that array:

```parfor i = 1:length(A) B(i) = f(A(i)); end```

#### Characteristics of a Sliced Variable

A variable in a `parfor`-loop is sliced if it has the following characteristics:

• Type of First-Level Indexing — The first level of indexing is parentheses, `()`.

• Fixed Index Listing — Within the first-level parenthesis, the list of indices is the same for all occurrences of a given variable.

• Form of Indexing — Within the list of indices for the variable, exactly one index involves the loop variable.

• Shape of Array — In assigning to a sliced variable, the right-hand side of the assignment is not `[]` or `''` (these operators indicate deletion of elements).

Type of First-Level Indexing. For a sliced variable, the first level of indexing is enclosed in parentheses, `()`. For example, `A(...)`. If you reference a variable using dot notation, `A.x`, the variable is not sliced.

Variable `A` on the left is not sliced; variable `A` on the right is sliced:

```A.q(i,12) A(i,12).q ```

Fixed Index Listing. Within the first-level parentheses of a sliced variable's indexing, the list of indices is the same for all occurrences of a given variable.

Variable `B` on the left is not sliced because `B` is indexed by `i` and `i+1` in different places. Variable `B` on the right is sliced.

 ```parfor i = 1:10 B(i) = B(i+1) + 1; end ``` ```parfor i = 1:10 B(i+1) = B(i+1) + 1; end```

Form of Indexing. Within the list of indices for a sliced variable, one index is of the form `i`, `i+k`, `i-k`, `k+i`, or `k-i`.

• `i` is the loop variable.

• `k` is a constant or a simple (nonindexed) variable.

• Every other index is a constant, a simple variable, colon, or `end`.

When you use other variables along with the loop variable to index an array, you cannot set these variables inside the loop. These variables are constant over the execution of the entire `parfor` statement. You cannot combine the loop variable with itself to form an index expression.

In the following examples, `i` is the loop variable, `j` and `k` are nonindexed variables.

Variable A Is Not SlicedVariable A Is Sliced
```A(i+f(k),j,:,3) A(i,20:30,end) A(i,:,s.field1)```
```A(i+k,j,:,3) A(i,:,end) A(i,:,k)```

Shape of Array. A sliced variable must maintain a constant shape. In the following examples, the variable `A` is not sliced:

```A(i,:) = []; A(end + 1) = i;```

A broadcast variable is a variable other than the loop variable or a sliced variable that is not modified inside the loop.

### Reduction Variables

A reduction variable accumulates a value that depends on all the iterations together, but is independent of the iteration order.

This example shows a `parfor`-loop that uses a scalar reduction assignment. It uses the reduction variable `x` to accumulate a sum across `10` iterations of the loop. The execution order of the iterations on the threads does not matter.

```x = 0; parfor i = 1:10 x = x + i; end x```

Where `expr` is a MATLAB expression, reduction variables appear on both sides of an assignment statement.

 `X = X + expr` `X = expr + X` `X = X - expr` See Reduction Assignments, Associativity, and Commutativity of Reduction Functions `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=f(X, expr)` Function `f` must be a user-defined function. `X = f(expr, X)` See Reduction Assignments, Associativity, and Commutativity of Reduction Functions

Each of the allowed statements is referred to as a reduction assignment. A reduction variable can appear only in assignments of this type.

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 each `d(i)` is calculated by a different iteration:

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

If the loop were a regular `for`-loop, the variable `X` in each iteration 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 not updated directly inside each thread. Rather, additions of `d(i)` are done in each thread, with `i` ranging over the subset of `1:n` being performed on that thread. The software then accumulates the results into `X`.

Similarly, the reduction:

`r=r<op> x(i)`
is equivalent to:
`r=r<op>x(1)] <op>x(2)...<op>x(n)`
The operation `<op>` is first applied to `x(1)...x(n)`, then the partial result is applied to `r`.

If operation `<op>` takes two inputs, it should meet one of the following criteria:

• Take two arguments of `typeof(x(i))` and return `typeof(x(i))`

• Take one argument of `typeof(r)` and one of `typeof(x(i))` and return `typeof(r)`

#### Rules for Reduction Variables

Use the same reduction function or operation in all reduction assignments.  For a reduction variable, you must use the same reduction function or operation in all reduction assignments for that variable. In the following example, the `parfor`-loop on the left is not valid because the reduction assignment uses `+` in one instance, and `*` in another.

Invalid Use of Reduction VariableValid Use of Reduction Variable
```parfor i = 1:n if A > 5*k A = A + 1; else A = A * 2; end ```
```parfor i = 1:n if A > 5*k A = A * 3; else A = A * 2; end ```

Restrictions on reduction function parameter and return types.  A reduction `r=r<op> x(i)`, should take arguments of `typeof(x(i))` and return `typeof(x(i))` or take arguments of `typeof(r)` and `typeof(x(i))` and return `typeof(r)`.

In the following example, in the invalid loop, `r` is a fixed-point type and `2` is not. To fix this issue, cast `2` to be the same type as `r`.

Invalid Use of Reduction VariableValid Use of Reduction Variable
```function r = fiops(in) r=fi(in,'WordLength',20,... 'FractionLength',14,... 'SumMode','SpecifyPrecision',... 'SumWordLength',20,... 'SumFractionLength',14,... 'ProductMode', 'SpecifyPrecision',... 'ProductWordLength',20,... 'ProductFractionLength',14); parfor i = 1:10 r = r*2; end```
```r=fi(in,'WordLength',20,... 'FractionLength',14,... 'SumMode','SpecifyPrecision',... 'SumWordLength',20,... 'SumFractionLength',14,... 'ProductMode','SpecifyPrecision',... 'ProductWordLength',20,... 'ProductFractionLength',14); T = r.numerictype; F = r.fimath; parfor i = 1:10 r = r*fi(2,T,F); end```

In the following example, the reduction function `fcn` is invalid because it does not handle the case when input `u` is fixed point. (The `+` and `*` operations are automatically polymorphic.) You must write a polymorphic version of `fcn` to handle the expected input types.

Invalid Use of Reduction VariableValid Use of Reduction Variable
```function [y0, y1, y2] = pfuserfcn(u) y0 = 0; y1 = 1; [F, N] = fiprops(); y2 = fi(1,N,F); parfor (i=1:numel(u),12) y0 = y0 + u(i); y1 = y1 * u(i); y2 = fcn(y2, u(i)); end end function y = fcn(u, v) y = u * v; end```
```function [y0, y1, y2] = pfuserfcn(u) y0 = 0; y1 = 1; [F, N] = fiprops(); y2 = fi(1,N,F); parfor (i=1:numel(u),12) y0 = y0 + u(i); y1 = y1 * u(i); y2 = fcn(y2, u(i)); end end % fcn handles inputs of type double % and fi function y = fcn(u, v) if isa(u,'double') y = u * v; else [F, N] = fiprops(); y = u * fi(v,N,F); end end function [F, N] = fiprops() N = numerictype(1,96,30); F = fimath('ProductMode',... 'SpecifyPrecision',... 'ProductWordLength',96); end ```

#### Reduction Assignments, Associativity, and Commutativity of Reduction Functions

Reduction Assignments. MATLAB Coder does not allow reduction variables to be read anywhere in the `parfor`-loop except in reduction statements. In the following example, the call `foo(r)` after the reduction statement `r=r+i` causes the loop to be invalid.

```function r = temp %#codegen r = 0; parfor i=1:10 r = r + i; foo(r); end end ```

Associativity in Reduction Assignments. If you use a user-defined function `f` in the definition of a reduction variable, to get deterministic behavior of `parfor`-loops, the reduction function `f` must be associative.

Note

If `f` is not associative, MATLAB Coder does not generate an error. You must write code that meets this recommendation.

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)`

Commutativity in Reduction Assignments. Some associative functions, including `+`, `.`, `min`, and `max`, are also commutative. That is, they satisfy the following for all `a` and `b`:

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

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.

Unless `f` is a known noncommutative built-in, the software assumes that it is commutative.

### Temporary Variables

A temporary variable is a variable that is the target of a direct, nonindexed assignment, but is not a reduction variable. In the following `parfor`-loop, `a` and `d` are temporary variables:

```a = 0; z = 0; r = rand(1,10); parfor i = 1:10 a = i; % Variable a is temporary z = z + i; if i <= 5 d = 2*a; % Variable d is temporary end end ```

In contrast to the behavior of a `for`-loop, before each iteration of a `parfor`-loop, MATLAB Coder effectively clears temporary variables. Because the iterations must be independent, the values of temporary variables cannot be passed from one iteration of the loop to another. Therefore, temporary variables must be set inside the body of a `parfor`-loop, so that their values are defined separately for each iteration.

A temporary variable in the context of the `parfor` statement is different from a variable with the same name that exists outside the loop.

#### Uninitialized Temporaries

Because temporary variables are cleared at the beginning of every iteration, MATLAB Coder can detect certain cases in which an iteration through the loop uses the temporary variable before it is set in that iteration. In this case, MATLAB Coder issues a static error rather than a run-time error, because there is little point in allowing execution to proceed if a run-time error will occur. For example, suppose you write:

``` b = true; parfor i = 1:n if b && some_condition(i) do_something(i); b = false; end ... end ```

This loop is acceptable as an ordinary `for`-loop, but as a `parfor`-loop, `b` is a temporary variable because it occurs directly as the target of an assignment inside the loop. Therefore, it is cleared at the start of each iteration, so its use in the condition of the `if` is uninitialized. (If you change `parfor` to `for`, the value of `b` assumes sequential execution of the loop, so that `do_something(i)` is executed for only the lower values of `i` until `b` is set `false`.)

## Support 평가판 신청