Решите огромную разреженную линейную систему, где A является результатом произведения Крона

Как я могу решить линейную систему (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 элементов на матрицу).

Что можно сделать по этому поводу?

Знаете ли вы какие-либо алгоритмы для решения подобных задач и ищете их реализацию в MATLAB? Или вы спрашиваете, как вообще можно решать в MATLAB задачи, не помещающиеся в памяти?

Dev-iL 28.05.2019 12:48

Как решать задачи, которые не умещаются в памяти. Или как создать «матричный объект», который хранит результат (A x B + C x D) без явного вычисления в первую очередь, который можно использовать с оператором обратной косой черты, если это возможно

Julian H 28.05.2019 12:55
Высокие массивы обеспечивает общее решение таких проблем. Однако, если это уравнение представляет какую-то известную проблему, возможно, существуют некоторые эффективные реализации, которые принимают A, B, C, D и b и возвращают x без решения всей системы. Возможно, вы захотите указать, в каком поле появляется это уравнение....
Dev-iL 28.05.2019 13:15

Уравнения возникают в пространственно-временном методе конечных элементов, где B и D - массовые и жесткие матрицы, а A и C - матрицы для дискретизации во времени. Последние две являются разреженными диагональными матрицами только с одной или двумя вторичными диагоналями. Один из подходов к решению таких уравнений представлен в связь, но я ищу альтернативу

Julian H 28.05.2019 13:21

Согласно Mathworks, у них нет разреженного kron. uk.mathworks.com/matlabcentral/answers/… . В этой же теме есть ссылка на sparse kron, реализованный пользователем, предлагаю использовать его

Ander Biguri 28.05.2019 14:11
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
304
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Видя, как ваши матрицы обычно довольно разрежены, конечный результат тензорного произведения не должен занимать так много памяти. Это один из случаев, когда векторизация просто невозможна из-за огромных требований к памяти промежуточных вычислений, но вполне возможна с использованием циклов (и частичной векторизации).

Обратите внимание, что это решение типа "лучше, чем ничего, но ненамного".

Я буду использовать 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).

Другие вопросы по теме