MATLAB Language                
            Векторизация
        
        
            
    Поиск…
Элементные операции
 MATLAB поддерживает (и поощряет) векторизованные операции над векторами и матрицами. 
 Например, предположим, что мы имеем A и B , две n m матрицы и хотим, чтобы C являлось элементарным произведением соответствующих элементов (т. Е. C(i,j) = A(i,j)*B(i,j) ). 
Не-векторизованный способ с использованием вложенных циклов выглядит следующим образом:
C = zeros(n,m);
for ii=1:n
    for jj=1:m
        C(ii,jj) = A(ii,jj)*B(ii,jj);
    end
end
 Однако векторизованный способ выполнения этого заключается в использовании элементарного оператора .* : 
C = A.*B;
-  Для получения дополнительной информации об умножении элемента в MATLAB см. Документацию о times.
- Дополнительные сведения о различиях между операциями массива и матрицы см. В разделе « Массивные и матричные операции» в документации MATLAB.
Сумма, средняя, prod & co
Для случайного вектора
v = rand(10,1);
если вы хотите получить сумму своих элементов, НЕ используйте цикл
s = 0;
for ii = 1:10
    s = s + v(ii);
end 
 но использовать векторизованную способность функции sum() 
s = sum(v);
 Функции, такие как sum() , mean() , prod() и другие, имеют возможность работать непосредственно по строкам, столбцам или другим измерениям. 
Например, учитывая случайную матрицу
A = rand(10,10);
среднее значение для каждого столбца равно
m = mean(A,1);
среднее значение для каждой строки равно
m = mean(A,2)
Все вышеперечисленные функции работают только с одним измерением, но что, если вы хотите суммировать всю матрицу? Вы можете использовать:
s = sum(sum(A))
 Но что, если есть ND-массив? применяя sum по sum на sum ... не похоже на лучший вариант, вместо этого используйте оператор : vectorize для вашего массива: 
s = sum(A(:))
и это приведет к одному числу, которое является суммой всего вашего массива, не имеет значения, сколько у него размеров.
Использование bsxfun
 Довольно часто причина, по которой код был написан в цикле for заключается в вычислении значений из «ближайших». Функция bsxfun часто может использоваться для этого более сжатым способом. 
 Например, предположим, что вы хотите выполнить операцию по столбцу на матрице B , вычитая из нее среднее значение каждого столбца: 
B = round(randn(5)*10);                  % Generate random data 
A = zeros(size(B));                      % Preallocate array
for col = 1:size(B,2);                    % Loop over columns
    A(:,col) = B(:,col) - mean(B(:,col));   % Subtract means 
end 
 Этот метод неэффективен, если B большой, часто из-за того, что MATLAB должен перемещать содержимое переменных в памяти. Используя bsxfun , можно выполнить одну и ту же работу аккуратно и легко только в одной строке: 
A = bsxfun(@minus, B, mean(B));
 Здесь @minus является дескриптором функции для оператора minus ( - ) и будет применяться между элементами двух матриц B и mean(B) . Возможны и другие функции, даже пользовательские. 
 Затем предположим, что вы хотите добавить вектор строки v в каждую строку в матрице A : 
v = [1,  2,  3];
A = [8,  1,  6
     3,  5,  7
     4,  9,  2];
Наивный подход - использовать цикл ( не делайте этого ):
B = zeros(3);
for row = 1:3
    B(row,:) = A(row,:) + v;
end
 Другим вариантом будет репликация v с помощью repmat ( не делайте этого ): 
>> v = repmat(v,3,1)
v =
     1     2     3
     1     2     3
     1     2     3
>> B = A + v; 
 Вместо этого используйте bsxfun для этой задачи: 
>> B = bsxfun(@plus, A, v);
B =
     9     3     9
     4     7    10
     5    11     5
Синтаксис
 bsxfun(@fun, A, B) 
 где @fun - одна из поддерживаемых функций, а два массива A и B соответствуют двум условиям ниже. 
 Имя bsxfun помогает понять, как работает эта функция, и это означает, что B inary FUN ction с S ingleton e X pansion. Другими словами, если: 
- два массива имеют одинаковые размеры, кроме одного
-  и несогласованный размер является одноточечным (т.е. имеет размер 1) в любом из двух массивов
то массив с размером Singleton будет расширен, чтобы соответствовать размерности другого массива. После расширения двоичная функция применяется по-разному на двух массивах.
 Например, пусть A - массив M -by- N -by K а B - массив M -by- N . Во-первых, их первые два измерения имеют соответствующие размеры. Во-вторых, A имеет K слоев, в то время как B имеет неявно только 1 , поэтому он является одиночным. Все условия выполнены, и B будет реплицироваться в соответствии с 3-м измерением A 
На других языках это обычно называют вещанием и происходит автоматически в Python (numpy) и Octave.
 Функция @fun должна быть двоичной функцией, означающей, что она должна принимать ровно два входа. 
замечания
 Внутри bsxfun не реплицирует массив и выполняет эффективный цикл. 
Логическая маскировка
MATLAB поддерживает использование логической маскировки для выполнения выбора по матрице без использования для циклов или операторов if.
 Логическая маска определяется как матрица, состоящая только из 1 и 0 . 
Например:
mask = [1 0 0; 0 1 0; 0 0 1];
является логической матрицей, представляющей единичную матрицу.
Мы можем создать логическую маску, используя предикат для запроса матрицы.
A = [1 2 3; 4 5 6; 7 8 9];
B = A > 4;
 Сначала мы создаем матрицу 3х3, A , содержащие цифры от 1 до 9. Затем запрос для значений, которые больше , чем 4 и сохранить результат в виде новой матрицы под названием A B . 
 B - логическая матрица формы: 
B = [0 0 0
     0 1 1
     1 1 1]
 Или 1 когда предикат A > 4 был истинным. И 0 когда это было ложно. 
 Мы можем использовать логические матрицы для доступа к элементам матрицы. Если для выбора элементов используется логическая матрица, в матрице, которую вы выбираете, будут выбраны индексы, в которых 1 появляется в логической матрице. 
 Используя тот же B сверху, мы могли бы сделать следующее: 
C = [0 0 0; 0 0 0; 0 0 0];
C(B) = 5;
 Это выберет все элементы C где B имеет 1 в этом индексе. Затем эти индексы в C устанавливаются в 5 . 
 Наш C теперь выглядит так: 
C = [0 0 0
     0 5 5
     5 5 5]
 Мы можем уменьшить сложные кодовые блоки, содержащие if и for , используя логические маски. 
Возьмите не-векторизованный код:
A = [1 3 5; 7 9 11; 11 9 7];
for j = 1:length(A)
  if A(j) > 5
    A(j) = A(j) - 2;
  end
end
Это можно сократить с помощью логической маскировки до следующего кода:
A = [1 3 5; 7 9 11; 11 9 7];
B = A > 5;
A(B) = A(B) - 2;
Или даже короче:
A = [1 3 5; 7 9 11; 11 9 7];
A(A > 5) = A(A > 5) - 2;
Неявное расширение массива (широковещательная передача) [R2016b]
MATLAB R2016b характеризовался обобщением своего механизма скалярного расширения 1 , 2 , чтобы также поддерживать определенные элементарные операции между массивами разных размеров, если их размерность совместима. Операторы, которые поддерживают неявное расширение, равны 1 :
-  Элементно-арифметические операторы: +,-.^.*.^,./.^.\.
-  Операторы отношения: <,<=,>,>=,==,~=.
-  Логические операторы: &,|,xor.
-  Битовые функции: bitand,bitor,bitxor.
-  Элементарные математические функции: max,min,mod,rem,hypot,atan2,atan2d.
 Вышеупомянутые двоичные операции разрешены между массивами, если они имеют «совместимые размеры». Размеры считаются «совместимыми», когда каждое измерение в одном массиве либо точно равно одной и той же размерности в другом массиве, либо равно 1 . Обратите внимание, что конечные синглтоны (т. Е. Размера 1 ) не учитываются MATLAB, хотя теоретически их бесконечное количество. Другими словами - размеры, которые появляются в одном массиве и не отображаются в другом, неявно подходят для автоматического расширения. 
Например, в версиях MATLAB до R2016b это произойдет:
>> magic(3) + (1:3)
Error using  + 
Matrix dimensions must agree.
Принимая во внимание, что начиная с R2016b предыдущая операция будет успешной:
>> magic(3) + (1:3)
ans =
     9     3     9
     4     7    10
     5    11     5
Примеры совместимых размеров:
| Описание | 1- й размер массива | 2- й размер массива | Размер результата | 
|---|---|---|---|
| Вектор и скаляр | [3x1] | [1x1] | [3x1] | 
| Векторы строк и столбцов | [1x3] | [2x1] | [2x3] | 
| Векторная и 2D матрица | [1x3] | [5x3] | [5x3] | 
| Матрицы ND и KD | [1x3x3] | [5x3x1x4x2] | [5x3x3x4x2] | 
Примеры несовместимых размеров:
| Описание | 1- й размер массива | 2- й размер массива | Возможное обходное решение | 
|---|---|---|---|
| Векторы, где размерность является кратной одной и той же размерности в другом массиве. | [1x2] | [1x8] | transpose | 
| Массивы с размерами, кратными друг другу. | [2x2] | [8x8] | repmat,reshape | 
| ND, которые имеют правильное количество одноэлементных измерений, но они находятся в неправильном порядке (№ 1). | [2x3x4] | [2x4x3] | permute | 
| ND, которые имеют правильное количество одноэлементных измерений, но они находятся в неправильном порядке (# 2). | [2x3x4x5] | [5x2] | permute | 
 ВАЖНЫЙ: 
 Код, основанный на этом соглашении, НЕ обратно совместим с любыми более старыми версиями MATLAB. Поэтому явный вызов bsxfun 1 , 2 (который достигает такого же эффекта) должен использоваться, если код должен запускаться на старых версиях MATLAB. Если такой проблемы не существует, заметки о выпуске MATLAB R2016 побуждают пользователей переключаться с bsxfun : 
По сравнению с использованием
bsxfunнеявное расширение обеспечивает более быструю скорость выполнения, лучшее использование памяти и улучшенную читаемость кода.
Связанные чтения:
- Документация MATLAB на « Совместимые размеры массивов для основных операций ».
- Широковещательная передача NumPy 1 , 2 .
-  Сравнение скорости вычислений с использованием bsxfunпротив неявного расширения массива .
Получить значение функции из двух или более аргументов
Во многих приложениях необходимо вычислить функцию двух или более аргументов.
 Традиционно мы используем for -loops. Например, если нам нужно вычислить f = exp(-x^2-y^2) (не используйте это, если вам нужно быстрое моделирование ): 
% code1
x = -1.2:0.2:1.4;
y = -2:0.25:3;
for nx=1:lenght(x)
   for ny=1:lenght(y)
      f(nx,ny) = exp(-x(nx)^2-y(ny)^2);
   end
end
Но векторная версия более элегантная и быстрая:
% code2
[x,y] = ndgrid(-1.2:0.2:1.4, -2:0.25:3);
f = exp(-x.^2-y.^2);
чем мы можем это визуализировать:
surf(x,y,f)
 Примечание1 - Сетки: Обычно хранилище матриц организовано по очереди . Но в MATLAB это столбцовое хранилище, как в FORTRAN. Таким образом, есть два Двойники функции ndgrid и meshgrid в MATLAB для реализации двух вышеупомянутых моделей. Чтобы визуализировать функцию в случае meshgrid , мы можем использовать: 
surf(y,x,f)
 Примечание2 - Потребление памяти: пусть размер x или y равен 1000. Таким образом, нам нужно хранить 1000*1000+2*1000 ~ 1e6 элементов для не-векторизованного кода1 . Но нам нужно 3*(1000*1000) = 3e6 элементов в случае векторизованного кода2 . В 3D-случае (пусть z имеет тот же размер, что и x или y ), потребление памяти резко возрастает: 4*(1000*1000*1000) (~ 32 ГБ для удвоений) в случае векторизованного кода2 против ~1000*1000*1000 (всего ~ 8 ГБ) в случае кода1 . Таким образом, мы должны выбрать либо память, либо скорость.