Ускоряване на вложен for цикъл

Работя върху ускоряването на следната функция, но без резултат:

function beta = beta_c(k,c,gamma)
beta = zeros(size(k));
E = @(x) (1.453*x.^4)./((1 + x.^2).^(17/6));
for ii = 1:size(k,1)
    for jj = 1:size(k,2)
        E_int = integral(E,k(ii,jj),10000);
        beta(ii,jj) = c*gamma/(k(ii,jj)*sqrt(E_int));
    end
end
end

Досега го решавах по следния начин:

function beta = beta_calc(k,c,gamma)
k_1d = reshape(k,[1,numel(k)]);
E_1d =@(k) 1.453.*k.^4./((1 + k.^2).^(17/6));
E_int = zeros(1,numel(k_1d));
parfor ii = 1:numel(k_1d)
E_int(ii) = quad(E_1d,k_1d(ii),10000);
end
beta_1d = c*gamma./(k_1d.*sqrt(E_int));
beta = reshape(beta_1d,[size(k,1),size(k,2)]);
end

Струва ми се, че наистина не подобри представянето. Какво мислиш за това?

Имате ли нещо против да хвърлите светлина?

Благодаря Ви предварително.

РЕДАКТИРАНЕ

Ще представя някои теоретични основи на моя въпрос. Като цяло бета трябва да се изчислява, както следва

въведете описание на изображението тук

Следователно, в намаления случай на едномерен k масив, E_int може да се изчисли като

E = 1.453.*k.^4./((1 + k.^2).^(17/6));
E_int = 1.5 - cumtrapz(k,E);

или алтернативно като

E_int(1) = 1.5;
for jj = 2:numel(k)
E =@(k) 1.453.*k.^4./((1 + k.^2).^(17/6));
E_int(jj) = E_int(jj - 1) - integral(E,k(jj-1),k(jj));
end

Независимо от това, k в момента е матрица k(size1,size2).


person fpe    schedule 20.01.2013    source източник
comment
Най-добрият ви залог би бил да компилирате функцията като mex - ще бъде много по-бързо.   -  person Floris    schedule 20.01.2013
comment
@fpe Извън темата: в текущите версии на MATLAB никога не съм виждал arrayfun да бъде по-бърз от for цикъл.   -  person Eitan T    schedule 20.01.2013
comment
Не съм запознат с интеграла, но не може ли да приеме две матрици?   -  person Pavan Yalamanchili    schedule 20.01.2013
comment
@EitanT: Бих искал между другото да оптимизирам работата на горната функция. Може ли векторизацията да е отговорът?   -  person fpe    schedule 20.01.2013
comment
@Pavan: Предполагам, че интегралът се нуждае от скалари като граници на интеграция.   -  person fpe    schedule 20.01.2013


Отговори (2)


Ето друг подход, успоредете, защото е лесно да използвате spmd или parfor. Вместо integral помислете за quad, вижте тази връзка за примери. ..

person bla    schedule 21.01.2013
comment
Току-що редактирах въпроса си, като въведох parfor в израза на beta_calc. Времето за изпълнение на казус magic(100) е наполовина от предишното. Доста добър резултат, но не знам дали е достатъчно добър - person fpe; 21.01.2013
comment
вашият намек изглежда, засега, най-разумното решение. Благодаря - person fpe; 21.01.2013

Харесвам този въпрос.

Проблемът: функцията integral приема като интеграционни ограничения само скалари. Следователно е трудно да се векторизира изчислението на E_int.

Улика: изглежда има много излишък в интегрирането на една и съща функция отново и отново от k(ii,jj) до безкрайност...

Предложено решение: Какво ще кажете за сортиране на стойностите на k от най-малката към най-голямата и интегриране на E_sort_int(si) = integral( E, sortedK(si), sortedK(si+1) ); с sortedK( numel(k) + 1 ) = 10000;. След това пълната стойност на E_int = cumsum( E_sort_int ); (трябва само да "отмените" сортирането и да го преформатирате обратно до размера на k).

person Shai    schedule 20.01.2013
comment
всъщност E_int като интегрални граници трябва да приема |k| и Inf; между другото, както твърдите, мога да изчисля E_int по алтернативен начин, който ще публикувам като редакция на основния въпрос (забележете, че ще го представя в случай, че k е 1-d масив) - person fpe; 20.01.2013
comment
Започнах да си мисля, че може би е по-лесно да смеся C функция, отчитайки тази, която извиквам сега в Matlab; поне относно integral - person fpe; 21.01.2013