Назначение подматрицы - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть вопрос, касающийся времени вычисления назначения подматрицы. Раньше у меня был такой код:

B_tot(1:6,pos:pos+2) = [ddx 0 0;0 ddy 0;0 0 ddz;ddy ddx 0;0 ddz ddy;ddz 0 ddx];

Согласно профилировщику Matlab, эта строка занимает 3,91 с (она выполняется более 800 000 раз). У меня было чувство, что это занимает много времени, поэтому я заменил его на:

B_tot(1,pos) = ddx;
B_tot(2,pos+1) = ddy;
B_tot(3,pos+2) = ddz;
B_tot(4,pos) = ddy;
B_tot(4,pos+1) = ddx;
B_tot(5,pos+1) = ddz;
B_tot(5,pos+2) = ddy;
B_tot(6,pos) = ddz;
B_tot(6,pos+2) = ddx;

Время вычислений комбинируется всего за 0,22 с, поэтому намного быстрее.

Теперь у меня вопрос: почему назначение подматрицы намного медленнее, и я могу написать такое назначение хорошо выглядящим способом, который все еще не занимает много времени?

Edit: Я сделал воспроизводимый код для сравнения:

tic
for i = 1:10000
    B_tot = zeros(6,24);
    for j = 1:8
        ddx = 1;
        ddy = 2;
        ddz = 3;
        pos = j*3-2;
        B_tot(1:6,pos:pos+2) = [ddx 0 0;0 ddy 0;0 0 ddz;ddy ddx 0;0 ddz ddy;ddz 0 ddx];
    end
end
toc
tic
for i = 1:10000
    B_tot = zeros(6,24);
    for j = 1:8
        ddx = 1;
        ddy = 2;
        ddz = 3;
        pos = j*3-2;
        B_tot(1,pos) = ddx;
        B_tot(2,pos+1) = ddy;
        B_tot(3,pos+2) = ddz;
        B_tot(4,pos) = ddy;
        B_tot(4,pos+1) = ddx;
        B_tot(5,pos+1) = ddz;
        B_tot(5,pos+2) = ddy;
        B_tot(6,pos) = ddz;
        B_tot(6,pos+2) = ddx;
    end
end
toc
tic
for i = 1:10000
    B_tot = zeros(6,24);
    for j = 1:8
        ddx = 1;
        ddy = 2;
        ddz = 3;
        pos = j*3-2;
        B_tot(sub2ind(size(B_tot),[1 2 3 4 4 5 5 6 6],pos+[0,1,2,0,1,1,2,0,2]))=[ddx,ddy,ddz,ddy,ddx,ddz,ddy,ddz,ddx];
    end
end
toc

Выход:

Elapsed time is 0.287602 seconds.
Elapsed time is 0.012062 seconds.
Elapsed time is 0.510040 seconds.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

Используя Octave 4.0, я вижу следующие моменты запуска вашего скрипта:

Elapsed time is 2.30614 seconds.
Elapsed time is 3.02992 seconds.
Elapsed time is 1.84936 seconds.

Версия Wolfie - самая быстрая, а индексирование по одному элементу - самое медленное!

JIT от Octave (если он есть) не так хорош, как MATLAB, отсюда и относительно медленные времена.

Я думаю, вы видите, что JIT MATLAB лучше оптимизирован для одноэлементной индексации. Обратите внимание, что

B_tot(1:6,pos:pos+2) = [ddx 0 0;0 ddy 0;0 0 ddz;ddy ddx 0;0 ddz ddy;ddz 0 ddx];

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

Обратите внимание, что вы увидите очень разные тайминги в разных версиях MATLAB. Я уверен, что старые версии MATLAB будут показывать время, похожее на то, что я получаю сейчас с Octave. Но также вполне возможно, что будущая версия MATLAB будет показывать другой порядок для этих таймингов, поскольку они дополнительно улучшат свой JIT и оптимизируют больше синтаксических случаев.

0 голосов
/ 27 апреля 2018

Базовая реализация назначения подматрицы состоит из циклов. Циклы всегда медленнее, чем линейное программирование. Если вы спускаетесь на уровень ассамблера, циклы выглядят примерно так.

Pos  Operation
  1  load variable1, variable2
  2  cmp = compare variable1, variable2
  3  if cmp : goto pos 4, else : goto pos 17
  4  load something
  5  operate on something
...
 16  goto pos 1
 17  load something_else

В то время как линейная программа имеет как минимум на четыре операции меньше.

... Я знаю, что это не настоящий Ассемблер, но я не знаю синтаксис.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...