Вы можете создать одну систему уравнений, содержащую множество независимых «подсистем» уравнений, поместив подматрицы a1
по диагонали матрицы 12000x12000 следующим образом:
a1(1,1) a1(1,2) a1(1,3) 0 0 0 0 0 0
a1(2,1) a1(2,2) a1(2,3) 0 0 0 0 0 0
a1(3,1) a1(3,2) a1(3,3) 0 0 0 0 0 0
0 0 0 a1(1,4) a1(1,5) a1(1,6) 0 0 0
0 0 0 a1(2,4) a1(2,5) a1(2,6) 0 0 0
0 0 0 a1(3,4) a1(3,5) a1(3,6) 0 0 0
0 0 0 0 0 0 a1(1,7) a1(1,8) a1(1,9)
0 0 0 0 0 0 a1(2,7) a1(2,8) a1(2,9)
0 0 0 0 0 0 a1(3,7) a1(3,8) a1(3,9)
а затем разделите его на a2(:)
.
Это можно сделать с помощью kron
и разреженной матрицы, подобной этой (источник):
a1_kron = kron(speye(12000/3),ones(3));
a1_kron(logical(a1_kron)) = a1(:);
a = a1_kron\a2(:);
a = reshape(a, [3 12000/3]);
Преимущество — скорость: это примерно в 3-4 раза быстрее, чем цикл for с предварительным выделением на моем ПК.
Недостаток. При таком подходе следует учитывать один недостаток: при использовании левого деления Matlab ищет наилучший способ решения систем линейных уравнений, поэтому, если вы решаете каждую подсистему независимо, для каждой подсистемы будет выбран лучший путь, но если вы решаете тему как одну систему, Matlab найдет лучший путь для всех подсистем вместе, а не лучший для каждой подсистемы.
Примечание. Как показано в Stefano M ответ, использование одной большой системы уравнений (с использованием kron
и разреженной матрицы) быстрее, чем использование цикла for (с предварительным выделением) только для очень небольшого размера под- системы уравнений (на моем компьютере число уравнений ‹= 7) для больших размеров подсистем уравнений использование цикла for быстрее.
Сравнение различных методов
Я написал и запустил код для сравнения 4 разных методов решения этой проблемы:
- для цикла, без предварительного распределения
- для цикла, с предварительным выделением
kron
cellfun
Контрольная работа:
n = 1200000;
a1 = rand(3,n);
a2 = rand(3,n/3);
disp('Method 1: for loop, no preallocation')
tic
a_method1 = [];
for ii = 1:3:n
a_method1 = [a_method1 a1(:,ii:ii+2)\a2(:, ceil(ii/3))];
end
toc
disp(' ')
disp('Method 2: for loop, with preallocation')
tic
a1_reshape = reshape(a1, 3, 3, []);
a_method2 = zeros(size(a2));
for i = 1:size(a1_reshape,3)
a_method2(:,i) = a1_reshape(:,:,i) \ a2(:,i);
end
toc
disp(' ')
disp('Method 3: kron')
tic
a1_kron = kron(speye(n/3),ones(3));
a1_kron(logical(a1_kron)) = a1(:);
a_method3 = a1_kron\a2(:);
a_method3 = reshape(a_method3, [3 n/3]);
toc
disp(' ')
disp('Method 4: cellfun')
tic
a1_cells = mat2cell(a1, size(a1, 1), repmat(3 ,1,size(a1, 2)/3));
a2_cells = mat2cell(a2, size(a2, 1), ones(1,size(a2, 2)));
a_cells = cellfun(@(x, y) x\y, a1_cells, a2_cells, 'UniformOutput', 0);
a_method4 = cell2mat(a_cells);
toc
disp(' ')
Полученные результаты:
Method 1: for loop, no preallocation
Elapsed time is 747.635280 seconds.
Method 2: for loop, with preallocation
Elapsed time is 1.426560 seconds.
Method 3: kron
Elapsed time is 0.357458 seconds.
Method 4: cellfun
Elapsed time is 3.390576 seconds.
Сравнив результаты четырех методов, можно увидеть, что использование метода 3 — kron
дает немного разные результаты:
disp(['sumabs(a_method1(:) - a_method2(:)): ' num2str(sumabs(a_method1(:)-a_method2(:)))])
disp(['sumabs(a_method1(:) - a_method3(:)): ' num2str(sumabs(a_method1(:)-a_method3(:)))])
disp(['sumabs(a_method1(:) - a_method4(:)): ' num2str(sumabs(a_method1(:)-a_method4(:)))])
Результат:
sumabs(a_method1(:) - a_method2(:)): 0
sumabs(a_method1(:) - a_method3(:)): 8.9793e-05
sumabs(a_method1(:) - a_method4(:)): 0
person
Eliahu Aaron
schedule
30.06.2019