Вы можете создать одну систему уравнений, содержащую множество независимых «подсистем» уравнений, поместив подматрицы 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
и разреженную матрицу, подобную этой ( source ):
a1_kron = kron(speye(12000/3),ones(3));
a1_kron(logical(a1_kron)) = a1(:);
a = a1_kron\a2(:);
a = reshape(a, [3 12000/3]);
Advantage - Speed : это примерно в 3-4 раза быстрее, чем цикл for с предварительным распределением на моем ПК.
Недостаток : при таком подходе необходимо учитывать один недостаток: при использовании левого деления Matlab ищет лучший способ решения систем линейных уравнений, поэтому, если вы решаете каждую подсистему независимо, наилучший путь будет выбран для каждой подсистемы, но если вы решите тему как одну системуMatlab найдет лучший способ для всех подсистем вместе - не самый лучший для каждой подсистемы.
Примечание : Как показано в Stefano M 's ответ , используя одну большую системуem уравнений (с использованием kron
и разреженной матрицы) быстрее, чем использование цикла for (с предварительным распределением) только для очень небольшого размера подсистем уравнений (на моем ПК для числа уравнений <= 7) для больших размеровподсистем уравнений, используя цикл for быстрее. </p>
Сравнение различных методов
Я написал и запустил код для сравнения 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