[Я чувствую, что начинаю звучать как неработающая пластинка ...]
Вы всегда должны сначала реализовывать свой код как цикл, а затем пытаться оптимизировать, используя permute
и reshape
. Но обратите внимание, что permute
необходимо копировать данные, поэтому стремится увеличить объем работы, а не уменьшить ее. Последние версии MATLAB больше не работают медленно с циклами, и, следовательно, копирование данных больше не всегда полезно для ускорения процесса.
Например, цикл в вопросе можно упростить до:
A_contracted = zeros(size(A,2),size(A,4));
for k = 1:size(A,1)
A_contracted = A_contracted + squeeze(A(k,:,k,:));
end
(я также обобщил на произвольные размеры).
По сравнению с ответом Луиса я вижу, что векторизованный метод выиграл для небольших массивов, таких как в OP (17x10x17x12), с 0,09 мс против 0,19 мс. Но с очень маленькими временами вокруг это вероятно не стоит усилий Однако для больших массивов (я пробовал 17x100x17x120) я вижу, что метод цикла выигрывает 1,3 мс против 2,6 мс.
Чем больше данных, тем больше преимущество использования простых старых циклов. С 170x100x170x120 это 0,04 с против 0,45 с.
Тестовый код:
A = rand(17,100,17,120);
assert(all(method2(A)==method1(A),'all'))
timeit(@()method1(A))
timeit(@()method2(A))
function A_contracted = method1(A)
A_contracted = permute(sum( ...
A.*((1:size(A,1)).'==reshape(1:size(A,3), 1, 1, [])), [1 3]), [2 4 1 3]);
end
function A_contracted = method2(A)
A_contracted = zeros(size(A,2),size(A,4));
for k = 1:size(A,1)
A_contracted = A_contracted + squeeze(A(k,:,k,:));
end
end