MATLAB: эффективная генерация блочных матриц с использованием блочного вектора - PullRequest
0 голосов
/ 31 октября 2018

Предположим,

x = [x1; x2; ...; х]

, где каждый xi является вектором столбца длиной l(i). Мы можем установить L = sum(l), общая длина x. Я хотел бы сгенерировать 2 матрицы на основе х:

enter image description here

Давайте назовем их A и B. Например, когда x только как 2 блока x1 и x2, тогда:

A = [x1 * x1 'нули (l (1), l (2)); нули (l (2), l (1)), x2 * x2 '];

B = [x1 нули (1 (1), 1); нули (1 (2), 1), х2];

В обозначении проблемы A всегда равно L на L, а B равно L на n. Я могу генерировать A и B с учетом x, используя циклы, но это утомительно. Есть ли умный (без цикла) способ генерации A и B. Я использую MATLAB 2018b, но при необходимости вы можете использовать более раннюю версию MATLAB.

Ответы [ 3 ]

0 голосов
/ 01 ноября 2018

Вот альтернативный подход:

s = repelem(1:numel(l), l).';
t = accumarray(s, x, [], @(x){x*x'});
A = blkdiag(t{:});
t = accumarray(s, x, [], @(x){x});
B = blkdiag(t{:});
0 голосов
/ 01 ноября 2018

Я думаю, что это коротко и быстро:

B = x .* (repelem((1:numel(l)).',l)==(1:numel(l)));
A = B * B.';

Если у вас большие данные, лучше использовать разреженную матрицу:

B = sparse(1:numel(x), repelem(1:numel(l), l), x);
A = B * B.';
0 голосов
/ 01 ноября 2018

Следующее должно работать. В этом случае я выполняю неэффективное преобразование в массивы ячеек, поэтому возможна более эффективная реализация.

cuml = [0; cumsum(l(:))];
get_x = @(idx) x((1:l(idx))+cuml(idx));
x_cell = arrayfun(get_x, 1:numel(l), 'UniformOutput', false);
B = blkdiag(x_cell{:});
A = B*B';

Редактировать

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

A = zeros(sum(l));
B = zeros(sum(l), numel(l));
prev = 0;
for idx = 1:numel(l)
    xidx = (1:l(idx))+prev;
    A(xidx, xidx) = x(xidx,1) * x(xidx,1)';
    B(xidx, idx) = x(idx,1);
    prev = prev + l(idx);
end
...