bsxfun-подобный для матричного продукта

Мне нужно умножить матрицу A на n матриц и получить обратно n матриц. Например, умножьте матрицу 2x2 на 3 матрицы 2x2, сложенные в виде массива 2x2x3 Matlab. bsxfun — это то, что я обычно использую в таких ситуациях, но это применимо только к поэлементным операциям. Я мог бы сделать что-то вроде:

blkdiag(a, a, a) * blkdiag(b(:,:,1), b(:,:,2), b(:,:,3))

но мне нужно решение для произвольного n -?


person Itamar Katz    schedule 13.01.2014    source источник
comment
mathworks.com/matlabcentral/newsreader/view_thread/311944 ознакомьтесь с комментариями для FEX-ссылки   -  person Dan    schedule 13.01.2014
comment
Сейчас не могу проверить, но в примере используется times, возможно здесь можно заменить mtimes.   -  person Dennis Jaheruddin    schedule 13.01.2014


Ответы (3)


Вы можете reshape сложенные матрицы. Предположим, у вас есть матрица k на k a и стопка матриц m k на k sb, и вы хотите получить произведение a*sb(:,:,ii) для ii = 1..m. Тогда все, что вам нужно, это

sza = size(a);
b = reshape( b, sza(2), [] ); % concatenate all matrices aloong the second dim
res = a * b; 
res = reshape( res, sza(1), [], size(sb,3) ); % stack back to 3d
person Shai    schedule 13.01.2014
comment
+1 Хорошо подумал. Но вам нужно сохранить size(sb,3) перед изменением формы b, чтобы использовать его в конце - person Luis Mendo; 13.01.2014
comment
@LuisMendo, если вы обратите внимание, у меня есть две переменные: sb для версии с накоплением и просто b для версии с измененным размером. - person Shai; 13.01.2014
comment
О, я вижу. Я думал, вы используете (и перезаписываете) b. - person Luis Mendo; 13.01.2014
comment
@LuisMendo, но вы правы в том, что при изменении размеров массивов и изменении их размеров лучше следить за тем, что происходит ... - person Shai; 13.01.2014
comment
@Shai В этом случае это должно быть b = reshape( sb, sza(2), [] ); - person user1618022; 28.01.2014
comment
Кстати, а что, если я хочу вычислить sb(:,:,ii)*a? - person user1618022; 28.01.2014

Ваше решение можно адаптировать к произвольному размеру, используя списки, разделенные запятыми, полученные из массивов ячеек:

[k m n] = size(B);
Acell = mat2cell(repmat(A,[1 1 n]),k,m,ones(1,n));
Bcell = mat2cell(B,k,m,ones(1,n));
blkdiag(Acell{:}) * blkdiag(Bcell{:});

Затем вы можете сложить блоки в трехмерный массив, используя этот ответ, и оставить только соответствующие.

Но в этом случае старый добрый цикл, вероятно, работает быстрее:

C = NaN(size(B));
for nn = 1:n
    C(:,:,nn) = A * B(:,:,nn);
end
person Luis Mendo    schedule 13.01.2014

Для больших стеков матриц и/или векторов, над которыми выполняется умножение матриц, скорость может стать проблемой. Чтобы не изобретать велосипед, вы можете просто скомпилировать и использовать следующий быстрый код MEX: -многомерная-поддержка" rel="nofollow noreferrer">MTIMESX - Mathworks. Как правило, MATLAB часто неэффективен при выполнении циклов for над большим количеством операций, которые выглядят так, как будто они должны быть векторизуемыми; Я не могу придумать простого способа обобщить ответ Шаи на этот случай.

person Matthew O'Brien    schedule 11.05.2020
comment
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. - person Ryan M; 11.05.2020
comment
Учитывая, что сама ссылка ведет на страницу mathworks для загрузки кода, разработанного третьей стороной ( mtimesx - GitHub ), мне было бы неуместно претендовать на какую-либо часть их работы как на мой собственный ответ. Если ссылка станет неработающей, я, естественно, попытаюсь заменить ее или удалю свой ответ. - person Matthew O'Brien; 12.05.2020