MATLAB ® поддерживает важное исключение, называемое сокращением, для правила, согласно которому итерации цикла должны быть независимыми. Понижающая переменная накапливает значение, которое зависит от всех итераций вместе, но не зависит от порядка итераций. MATLAB позволяет использовать переменные сокращения вparfor-контуры.
Переменные сокращения появляются на обеих сторонах инструкции назначения, например, на любой из следующих, где expr является выражением MATLAB.
X = X + expr | X = expr + X |
X = X - expr
| См. раздел Ассоциативность в назначениях сокращения в требованиях к назначениям сокращения |
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) |
Каждый из допустимых операторов, перечисленных в этой таблице, называется назначением сокращения. По определению, переменная сокращения может отображаться только в присвоениях этого типа.
Общая форма присвоения сокращения:
X = f(X, expr) | X = f(expr, X) |
В следующем примере показано типичное использование переменной сокращения X.
X = 0; % Do some initialization of X parfor i = 1:n X = X + d(i); end
Этот цикл эквивалентен следующему, где вычисляется каждый d(i) другой итерацией.
X = X + d(1) + ... + d(n)
В обычном for-loop, переменная X получит его значение либо перед входом в цикл, либо из предыдущей итерации цикла. Однако это понятие не относится к parfor-контуры.
В parfor-loop, значение X никогда не передается от клиента к работникам или от работника к работнику. Скорее, добавления d(i) выполняются в каждом работнике, с i диапазон по подмножеству 1:n выполняется на этом работнике. Результаты затем передаются обратно клиенту, который добавляет частичные суммы работников в X. Таким образом, некоторые дополнения делают работники, а остальное - клиент.
Если ваш parfor код не соответствует рекомендациям и ограничениям, помеченным как обязательный, вы получаете ошибку. MATLAB обнаруживает некоторые из этих ошибок при чтении кода, а другие - при его выполнении. Эти ошибки помечены как обязательные (статические) или обязательные (динамические) соответственно. Рекомендации, не вызывающие ошибок, помечены как рекомендуемые. Для помощи можно использовать MATLAB Code Analyzer. parfor-контуры соответствуют инструкциям.
Следующие требования дополнительно определяют назначения сокращения, связанные с данной переменной.
| Обязательное (статическое): Для любой переменной сокращения одна и та же функция сокращения или операция должна использоваться во всех назначениях сокращения для этой переменной. |
parfor-loop слева недопустим, так как назначение сокращения использует + в одном случае, и [,] в другом. parforПараметр -loop справа допустим.
| Инвалид | Действительный |
|---|---|
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 |
Обязательное (статическое): Если используется назначение сокращения *, [,], или [;], то X должен быть последовательно указан в качестве первого или второго аргумента в каждом назначении сокращения. |
parfor-loop слева недопустим, так как порядок элементов в конкатенации не согласован по всему циклу. parforПараметр -loop справа допустим.
| Инвалид | Действительный |
|---|---|
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 |
| Обязательный (статический): нельзя индексировать или индексировать переменную сокращения. |
Код слева недопустим, так как он пытается индексировать aи поэтому MATLAB не может классифицировать его как переменную сокращения. Для его исправления в коде справа используется неиндексированная переменная.
| Инвалид | Действительный |
|---|---|
a.x = 0 parfor i = 1:10 a.x = a.x + 1; end |
tmpx = 0 parfor i = 1:10 tmpx = tmpx + 1; end a.x = tmpx; |
Назначения сокращения. В дополнение к конкретным формам назначения сокращения, перечисленным в таблице переменных сокращения, единственной другой (и более общей) формой назначения сокращения является
X = f(X, expr) | X = f(expr, X) |
Обязательный (статический): f может быть функцией или переменной. Если f является переменной, то вы не можете изменить f в parfor тело (другими словами, это вещательная переменная). |
Если f является переменной, то для всех практических целей ее значением во время выполнения является дескриптор функции. Однако, пока может быть вычислена правая сторона, результирующее значение сохраняется в X.
parfor-loop слева выполняется неправильно, поскольку инструкция f = @times причины f классифицируется как временная переменная. Поэтому f очищается в начале каждой итерации. parfor-loop справа правильный, так как он не назначает f внутри петли.
| Инвалид | Действительный |
|---|---|
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 |
Операторы && и || не перечислены в таблице переменных сокращения. За исключением && и ||, все матричные операции MATLAB имеют соответствующую функцию f, такой, что u op v эквивалентно f(u,v). Для && и ||, такая функция не может быть записана, поскольку u&&v и u||v может или не может оценить v. Однако f(u,v)
всегда оценивает v перед вызовом f. Поэтому && и || исключены из таблицы разрешенных назначений сокращения для parfor-луп.
Каждое назначение сокращения имеет соответствующую функцию f. Свойства f которые обеспечивают детерминированное поведение оператора parfor, рассматриваются в следующих разделах.
Ассоциативность в назначениях сокращения. Для функции рекомендуется следующая практика f, как используется в определении переменной сокращения. Однако это правило не создает ошибки, если оно не соблюдается. Поэтому вы должны убедиться, что ваш код соответствует этой рекомендации.
Рекомендуется: Чтобы получить детерминированное поведение parfor-циклы, функция редукции f должен быть ассоциативным. |
Чтобы быть ассоциативной, функция f должны удовлетворять следующим требованиям для всех a, b, и c.
f(a,f(b,c)) = f(f(a,b),c)
Правила классификации переменных, включая переменные редукции, являются чисто синтаксическими. Они не могут определить, f вы предоставили действительно ассоциативный или нет. Ассоциативность предполагается, но если вы нарушаете это правило, каждое выполнение цикла может привести к различным ответам.
Примечание
Сложение математических вещественных чисел является ассоциативным. Однако добавление чисел с плавающей запятой является только приблизительно ассоциативным. Различные казни этого parfor оператор может создавать значения X с различными ошибками округления. Избежать такой стоимости параллелизма невозможно.
Например, оператор слева дает 1, а оператор справа возвращает 1 + eps:
(1 + eps/2) + eps/2 1 + (eps/2 + eps/2)
За исключением оператора «минус» (-), все особые случаи, перечисленные в таблице в переменных сокращения, имеют соответствующую (приблизительно) ассоциативную функцию. MATLAB вычисляет присвоение X = X - expr с помощью X = X + (-expr). (Таким образом, технически функция для вычисления этого присвоения сокращения plus, не minus.) Однако назначение X = expr - X не может быть записан с помощью ассоциативной функции, что объясняет её исключение из таблицы.
Коммутативность в назначениях сокращения. Некоторые ассоциативные функции, в том числе +, .*, min, и max, intersect, и union, также являются коммутативными. То есть удовлетворяют следующим для всех a и b.
f(a,b) = f(b,a)
К некоммутативным функциям относятся * (поскольку матричное умножение не коммутативно для матриц, в которых оба измерения имеют размер больше единицы), [,], и [;]. Некоммутативность является причиной, по которой требуется последовательность в порядке аргументов к этим функциям. На практике более эффективный алгоритм возможен, когда функция коммутативна, а также ассоциативна, и parfor оптимизирован для использования коммутативности.
Рекомендуется, за исключением случаев *, [,], и [;], функция f назначения сокращения должны быть коммутативными. Если f не является коммутативным, различные выполнения цикла могут привести к различным ответам. |
Нарушение ограничения коммутативности в функции, используемой для уменьшения, может привести к неожиданному поведению, даже если оно не порождает ошибку.
Если f является известной некоммутативной встроенной функцией, предполагается коммутативной. В настоящее время нет возможности указать пользовательскую, некоммутативную функцию в parfor.
Рекомендуется: Перегрузка +, *, .*, [,], или [;] должен быть ассоциативным, если он используется в назначении сокращения в parfor-луп. |
Рекомендуется: Перегрузка +, .*, union, или intersect должен быть коммутативным. |
Аналогичным образом, из-за особого режима X = X - expr, рекомендуется следующее.
Рекомендуется: Перегрузка оператора минус (-) должны подчиняться математическому закону, который X - ( эквивалентно (X - . |
Предположим, что каждая итерация цикла выполняет некоторое вычисление, и вам интересно найти, какая итерация цикла производит максимальное значение. Это упражнение уменьшения делает накопление в нескольких итерациях цикла. Функция сокращения должна сравнивать результаты итерации до тех пор, пока не будет определено максимальное значение после сравнения всех итераций.
Сначала рассмотрим саму функцию сокращения. Для сравнения одного результата итерации с другим функция требует в качестве входных данных текущего результата и известного максимума из других итераций. Каждый из двух входов является вектором, содержащим результаты итерации и номер итерации.
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 end
Внутри цикла каждая итерация вызывает функцию сокращения (comparemax), проходя в паре двухэлементных векторов:
Накопленный максимум и его индекс итерации, который является переменной сокращения cummax
Значение итерации и индекс
Если значение данных текущей итерации больше максимального значения в cummmaxфункция возвращает вектор нового значения и его номер итерации. В противном случае функция возвращает существующий максимум и его номер итерации.
Каждая итерация вызывает функцию сокращения comparemax для сравнения собственных данных [dat i] к данным, уже накопленным в cummax. Попробуйте использовать следующий код для этого цикла.
% 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);
MATLAB классифицирует назначения формы X = expr op X или X = X op expr как операторы сокращения, если они эквивалентны назначениям в скобках X = (expr) op X или X = X op (expr) соответственно. X является переменной, op является оператором сокращения, и expr - выражение с одним или несколькими бинарными операторами редукции. Следовательно, из-за правил приоритета оператора MATLAB, MATLAB может не классифицировать некоторые назначения формы X = expr op1 X op2 expr2 ..., что цепные операторы, как операторы сокращения в parfor-контуры.
В этом примере MATLAB классифицирует X в качестве понижающей переменной, поскольку назначение эквивалентно X = X + (1 * 2).
X = 0; parfor i=1:10 X = X + 1 * 2; end
В этом примере MATLAB классифицирует X как временная переменная, поскольку назначение, эквивалентное X = (X * 1) + 2, не имеет формы X = (expr) op X или X = X op (expr).
X = 0; parfor i=1:10 X = X * 1 + 2; end
Рекомендуется использовать круглые скобки для явного указания приоритета оператора для назначений сокращения цепочки.