Вот довольно простая и общая реализация, которая использует один цикл for для выполнения линейного индексирования и избегает работы с трехмерными переменными или изменения формы:
%# General solution:
%# ----------------
B = cell(N);
for index = 1:N^2
A = [Ax(index) Ay(index) Az(index)];
B{index} = A(:)*A;
end
B = cell2mat(B);
РЕДАКТИРОВАТЬ # 1:
В ответ на дополнительный вопрос о том, как уменьшить количество вычислений, выполняемых для симметричной матрицы B
, вы можете использовать следующую модифицированную версию вышеуказанного кода:
%# Symmetric solution #1:
%# ---------------------
B = cell(N);
for index = find(tril(ones(N))).' %'# Loop over the lower triangular part of B
A = [Ax(index) Ay(index) Az(index)];
B{index} = A(:)*A;
symIndex = N*rem(index-1,N)+ceil(index/N); %# Find the linear index for the
%# symmetric element
if symIndex ~= index %# If we're not on the main diagonal
B{symIndex} = B{index}; %# then copy the symmetric element
end
end
B = cell2mat(B);
Однако, в таком случае вы можете получить более высокую производительность (или, по крайней мере, более простой код), отказавшись от линейного индексирования и используя два цикла for с индексированным индексированием, например, так:
%# Symmetric solution #2:
%# ---------------------
B = cell(N);
for c = 1:N %# Loop over the columns
for r = c:N %# Loop over a subset of the rows
A = [Ax(r,c) Ay(r,c) Az(r,c)];
B{r,c} = A(:)*A;
if r ~= c %# If we're not on the main diagonal
B{c,r} = B{r,c}; %# then copy the symmetric element
end
end
end
B = cell2mat(B);
РЕДАКТИРОВАНИЕ № 2:
Второе симметричное решение может быть еще более ускорено путем перемещения диагонального вычисления за пределы внутреннего цикла (устраняя необходимость в условном выражении) и перезаписи A
с результатом A(:)*A
, чтобы мы могли обновить симметричную ячейку введите B{c,r}
, используя A
вместо B{r,c}
(т.е. обновление одной ячейки содержимым другой, по-видимому, несет некоторые дополнительные издержки):
%# Symmetric solution #3:
%# ---------------------
B = cell(N);
for c = 1:N %# Loop over the columns
A = [Ax(c,c) Ay(c,c) Az(c,c)];
B{c,c} = A(:)*A;
for r = c+1:N %# Loop over a subset of the rows
A = [Ax(r,c) Ay(r,c) Az(r,c)];
A = A(:)*A;
B{r,c} = A;
B{c,r} = A;
end
end
B = cell2mat(B);
А вот некоторые временные результаты для 3 симметричных решений, использующих следующие примерные симметричные матрицы Ax
, Ay
и Az
:
N = 400;
Ax = tril(rand(N)); %# Lower triangular matrix
Ax = Ax+triu(Ax.',1); %'# Add transpose to fill upper triangle
Ay = tril(rand(N)); %# Lower triangular matrix
Ay = Ay+triu(Ay.',1); %'# Add transpose to fill upper triangle
Az = tril(rand(N)); %# Lower triangular matrix
Az = Az+triu(Az.',1); %'# Add transpose to fill upper triangle
%# Timing results:
%# --------------
%# Solution #1 = 0.779415 seconds
%# Solution #2 = 0.704830 seconds
%# Solution #3 = 0.325920 seconds
Большое ускорение для решения 3 обусловлено главным образом обновлением содержимого ячейки B
локальной переменной A
вместо обновления одной ячейки содержимым другой. Другими словами, копирование содержимого ячейки с помощью таких операций, как B{c,r} = B{r,c};
, несет больше затрат, чем я ожидал.