Как я могу решить линейную систему (A ⊗ B + C ⊗ D) x = b
в MATLAB без вычисления фактической матрицы, которая умножает x
(⊗ обозначает произведение Кронекера). Несмотря на то, что A
, B
, C
и D
являются sparse
матрицами, наивный подход,
x = (kron(A,B) + kron(C,D))\b
не помещается в память и вызывает сбой MATLAB для больших матриц (~ 1000 x 1000 элементов на матрицу).
Что можно сделать по этому поводу?
Как решать задачи, которые не умещаются в памяти. Или как создать «матричный объект», который хранит результат (A x B + C x D) без явного вычисления в первую очередь, который можно использовать с оператором обратной косой черты, если это возможно
A, B, C, D
и b
и возвращают x
без решения всей системы. Возможно, вы захотите указать, в каком поле появляется это уравнение....
Уравнения возникают в пространственно-временном методе конечных элементов, где B и D - массовые и жесткие матрицы, а A и C - матрицы для дискретизации во времени. Последние две являются разреженными диагональными матрицами только с одной или двумя вторичными диагоналями. Один из подходов к решению таких уравнений представлен в связь, но я ищу альтернативу
Согласно Mathworks, у них нет разреженного kron
. uk.mathworks.com/matlabcentral/answers/… . В этой же теме есть ссылка на sparse kron, реализованный пользователем, предлагаю использовать его
Видя, как ваши матрицы обычно довольно разрежены, конечный результат тензорного произведения не должен занимать так много памяти. Это один из случаев, когда векторизация просто невозможна из-за огромных требований к памяти промежуточных вычислений, но вполне возможна с использованием циклов (и частичной векторизации).
Обратите внимание, что это решение типа "лучше, чем ничего, но ненамного".
Я буду использовать ndSparse
подача, так как это упрощает работу с разреженными матрицами.
% Create some matrices
[A,B] = deal(sparse(1000,1000));
A(randperm(1000^2, 10000)) = randn(1E4, 1);
B(randperm(1000^2, 10000)) = randn(1E4, 1);
A = ndSparse(A); B = ndSparse(B);
% Kronecker tensor product, copied from kron.m
[ma,na] = size(A);
[mb,nb] = size(B);
A = reshape(A,[1 ma 1 na]);
B = reshape(B,[mb 1 nb 1]);
% K = reshape(A.*B,[ma*mb na*nb]); % This fails, too much memory.
K = ndSparse(sparse(mb*ma*nb*na,1),[mb, ma, nb, na]); % This works
Отсюда можно действовать в зависимости от доступной памяти:
% If there's plenty of memory (2D x 1D -> 3D):
for ind1 = 1:mb
K(ind1,:,:,:) = bsxfun(@times, A, B(ind1, :, :, :));
end
% If there's less memory (1D x 1D -> 2D):
for ind1 = 1:mb
for ind2 = 1:ma
K(ind1,ind2,:,:) = bsxfun(@times, A(:, ind2, :, :), B(ind1, :, :, :));
end
end
% If there's even less memory (1D x 0D -> 1D):
for ind1 = 1:mb
for ind2 = 1:ma
for ind3 = 1:nb
K(ind1,ind2,ind3,:) = bsxfun(@times, A(:, ind2, :, :), B(ind1, :, ind3, :));
end
end
end
% If there's absolutely no memory (0D x 0D -> 0D):
for ind1 = 1:mb
for ind2 = 1:ma
for ind3 = 1:nb
for ind4 = 1:na
K(ind1,ind2,ind3,ind4) = A(:, ind2, :, ind4) .* B(ind1, :, ind3, :);
end
end
end
end
K = sparse(reshape(K,[ma*mb na*nb])); % Final touch
Так что это просто теоретическая демонстрация того, как в конце концов выполняет вычисления, но, к сожалению, это очень неэффективно, так как приходится снова и снова вызывать методы класса, а также это не гарантирует, что будет достаточно памяти для вычисления \
оператор.
Один из возможных способов улучшить это — вызвать matlab.internal.sparse.kronSparse
поблочно и сохранить промежуточные результаты в правильной позиции выходного массива, но это требует тщательного обдумывания.
Кстати, я пытался использовать отправку FEX, о которой упомянул Андер (KronProd
), но это не дает никакой пользы, когда вам нужно вычислить kron(A,B) + kron(C,D)
(хотя это потрясающе для ситуаций kron(A,B)\b
).
Знаете ли вы какие-либо алгоритмы для решения подобных задач и ищете их реализацию в MATLAB? Или вы спрашиваете, как вообще можно решать в MATLAB задачи, не помещающиеся в памяти?