Классификация переменных в parfor- Циклы

Обзор

MATLAB® Coder™ классифицирует переменные в parfor- цикл в одну из категорий в следующей таблице. Это не поддерживает переменные, которые это не может классифицировать. Если parfor- цикл содержит переменные, которые не могут быть исключительно категоризированы или если переменная нарушает свои ограничения категории, parfor- цикл генерирует ошибку.

КлассификацияОписание
ЦиклСлужит индексом цикла для массивов
НарезанныйМассив, сегменты которого управляются различными итерациями цикла
Широковещательная передачаПеременная задала перед циклом, значение которого используется в цикле, но не присваивается в цикле
СокращениеНакапливает значение через итерации цикла, независимо от порядка итерации
ВременныйПеременная создается в цикле, но различающаяся нарезанная или переменные сокращения, не доступные вне цикла

Каждая из этих переменных классификаций появляется в этом фрагменте кода:

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

Нарезанные переменные

Нарезанная переменная является той, значение которой может быть разбито в сегменты или срезы, на которых затем используют отдельно различные потоки. Каждая итерация цикла работает над различным срезом массива.

В следующем примере, срезе A состоит из одного элемента того массива:

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

Характеристики нарезанной переменной

Переменная в parfor- цикл нарезан, если он имеет следующие характеристики:

  • Тип Индексации Первого уровня — первый уровень индексации является круглыми скобками, ().

  • Фиксированный Список индексов — В круглой скобке первого уровня, список индексов является тем же самым для всех случаев данной переменной.

  • Форма Индексации — В рамках списка индексов для переменной, точно один индекс включает переменную цикла.

  • Форма Массива — В присвоении нарезанной переменной, правой стороной присвоения не является [] или '' (эти операторы указывают на удаление элементов).

Тип Индексации Первого уровня. Для нарезанной переменной первый уровень индексации заключен в круглые скобки, (). Например, A(...). Если вы ссылаетесь на переменную запись через точку использования, A.x, переменная не нарезана.

Переменный A слева не нарезан; переменная A справа нарезан:

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

Фиксированный Список индексов. В круглых скобках первого уровня индексации нарезанной переменной список индексов является тем же самым для всех случаев данной переменной.

Переменный B слева не нарезан потому что B индексируется i и i+1 в различных местах. Переменный B справа нарезан.

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

Форма Индексации. В рамках списка индексов для нарезанной переменной один индекс имеет форму i, i+k, i-k, k+i, или k-i.

  • i переменная цикла.

  • k константа или простая (неиндексируемая) переменная.

  • Любой индекс является константой, простой переменной, двоеточием, или end.

Когда вы используете другие переменные наряду с переменной цикла, чтобы индексировать массив, вы не можете установить эти переменные в цикле. Эти переменные являются постоянными по выполнению целого parfor оператор. Вы не можете объединить переменную цикла с собой, чтобы сформировать выражение индекса.

В следующих примерах, i переменная цикла, j и k неиндексированные переменные.

Переменная A не нарезанаПеременная A нарезана
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)

Форма Массива. Нарезанная переменная должна обеспечить постоянную форму. В следующих примерах, переменной A не нарезан:

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

Широковещательно передайте переменные

Широковещательная переменная является переменной кроме переменной цикла или нарезанной переменной, которая не изменяется в цикле.

Переменные сокращения

Переменная сокращения накапливает значение, которое зависит от всех итераций вместе, но независимо от порядка итерации.

Этот пример показывает parfor- цикл, который использует скалярное присвоение сокращения. Это использует переменную x сокращения накапливать сумму через 10 итерации цикла. Порядок выполнения итераций на потоках не имеет значения.

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

Где expr выражение MATLAB, переменные сокращения появляются с обеих сторон оператора присваивания.

X = X + exprX = expr + X
X = X - exprСмотрите присвоения сокращения, ассоциативность и коммутативность функций сокращения
X = X .* exprX = expr .* X
X = X * exprX = expr * X
X = X & exprX = expr & X
X = X | exprX = expr | X
X = min(X, expr)X = min(expr, X)
X = max(X, expr)X = max(expr, X)
X=f(X, expr)
Функциональный f должна быть пользовательская функция.
X = f(expr, X)
Смотрите присвоения сокращения, ассоциативность и коммутативность функций сокращения

Каждый из позволенных операторов упоминается как присвоение сокращения. Переменная сокращения может появиться только в присвоениях этого типа.

Следующий пример показывает типичное использование переменной X сокращения:

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

Этот цикл эквивалентен следующему, где каждый d(i) вычисляется различной итерацией:

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

Если цикл был постоянным клиентом for- цикл, переменная X в каждой итерации получил бы ее значение или прежде, чем ввести цикл или от предыдущей итерации цикла. Однако эта концепция не применяется к parfor- циклы.

В parfor- цикл, значение X не обновляется непосредственно в каждом потоке. Скорее сложения d(i) сделаны в каждом потоке, с i передвижение на подмножество 1:n будучи выполняемым на том потоке. Программное обеспечение затем накапливает результаты в X.

Точно так же сокращение:

r=r<op> x(i)
эквивалентно:
r=r<op>x(1)] <op>x(2)...<op>x(n)
Операция <op> сначала применяется к x(1)...x(n), затем частичный результат применяется к r.

Если операция <op> берет два входных параметров, это должно соответствовать одному из следующих критериев:

  • Возьмите два аргумента typeof(x(i)) и возвратите typeof(x(i))

  • Возьмите один аргумент typeof(r) и один из typeof(x(i)) и возвратите typeof(r)

Правила для переменных сокращения

Используйте ту же функцию сокращения или операцию во всех присвоениях сокращения.  Для переменной сокращения необходимо использовать ту же функцию сокращения или операцию во всех присвоениях сокращения для той переменной. В следующем примере, parfor- цикл слева не допустим, потому что присвоение сокращения использует + в одном экземпляре и * в другом.

Недопустимое использование переменной сокращенияДопустимое использование переменной сокращения
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

Ограничения на параметр функции сокращения и возвращают типы.  Сокращение r=r<op> x(i), должен взять аргументы typeof(x(i)) и возвратите typeof(x(i)) или возьмите аргументы typeof(r) и typeof(x(i)) и возвратите typeof(r).

В следующем примере, в недопустимом цикле, r фиксированная точка и 2 не. Чтобы устранить эту проблему, бросьте 2 быть тем же типом как r.

Недопустимое использование переменной сокращенияДопустимое использование переменной сокращения
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

В следующем примере сокращение функционирует fcn недопустимо, потому что это не обрабатывает случай когда вход u фиксированная точка. (+ и * операции являются автоматически полиморфными.) Необходимо записать полиморфную версию fcn обрабатывать ожидаемые входные типы.

Недопустимое использование переменной сокращенияДопустимое использование переменной сокращения
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

Присвоения сокращения, ассоциативность и коммутативность функций сокращения

Присвоения сокращения. MATLAB Coder не позволяет переменным сокращения быть считанными где угодно в parfor- цикл кроме операторов сокращения. В следующем примере, вызов foo(r) после оператора r=r+i сокращения заставляет цикл быть недопустимым.

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

Ассоциативность в Присвоениях Сокращения. Если вы используете пользовательский функциональный f в определении переменной сокращения, чтобы получить детерминированное поведение parfor- циклы, сокращение функционирует f должно быть ассоциативным.

Примечание

Если f не ассоциативно, MATLAB Coder не генерирует ошибку. Необходимо записать код, который выполняет этой рекомендации.

Быть ассоциативным, функциональный f должен удовлетворить следующему для всего aB, и c:

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

Коммутативность в Присвоениях Сокращения. Некоторые ассоциативные функции, включая +, ., min, и max, являются также коммутативными. Таким образом, они удовлетворяют следующему для всего a и b:

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

Функциональный f из сокращения присвоение должно быть коммутативным. Если f не коммутативное, различное выполнение цикла, может привести к различным ответам.

Если f известное некоммутативное встроенное, программное обеспечение принимает, что является коммутативным.

Временные переменные

Временная переменная является переменной, которая является целью прямого, неиндексируемого присвоения, но не является переменной сокращения. В следующем parfor- цикл, a и d временные переменные:

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

В отличие от поведения a for- цикл, перед каждой итерацией parfor- цикл, MATLAB Coder эффективно очищает временные переменные. Поскольку итерации должны быть независимыми, значения временных переменных не могут быть переданы от одной итерации цикла другому. Поэтому временные переменные должны быть установлены в теле parfor- цикл, так, чтобы их значения были заданы отдельно для каждой итерации.

Временная переменная в контексте parfor оператор отличается от переменной с тем же именем, которое существует вне цикла.

Неинициализированные временные файлы

Поскольку временные переменные очищены в начале каждой итерации, MATLAB Coder может обнаружить определенные случаи, в которых итерация через цикл использует временную переменную, прежде чем это будет установлено в той итерации. В этом случае MATLAB Coder выпускает статическую ошибку, а не ошибку времени выполнения, потому что существует мало точки в разрешении выполнения продолжить, если ошибка времени выполнения произойдет. Например, предположите, что вы пишете:

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

Этот цикл приемлем как обычный for- цикл, но как parfor- цикл, b временная переменная, потому что она происходит непосредственно как цель присвоения в цикле. Поэтому это очищено в начале каждой итерации, таким образом, ее использование в условии if является неинициализированным. (Если вы изменяете parfor к for, значение b принимает последовательное выполнение цикла, так, чтобы do_something(i) выполняется только для нижних значений i до b набор false.)