Бавна производителност на Matlab при използване на затваряния

Кодирам решение за уравнение на Поасон върху 2d правоъгълник, използвайки крайни елементи. За да опростя кода, съхранявам манипулатори на базовите функции в масив и след това преминавам през тези базови функции, за да създам моята матрица и дясната страна. Проблемът с това е, че дори за много груби мрежи е непосилно бавен. За мрежа 9x9 (използвайки Dirichlet BC, има 49 възела за решаване) отнема около 20 секунди. Използвайки профила, забелязах, че около половината от времето се изразходва за достъп (не изпълнение) на моите основни функции.

Профайлърът казва matrix_assembly>@(x,y)bilinearBasisFunction(x,y,xc(k-1),xc(k),xc(k+1),yc(j-1),yc(j),yc(j+1)) (156800 calls, 11.558 sec), самото време (без изпълнение на кода на билинейната основа) е над 9 секунди. Някакви идеи защо това може да е толкова бавно?

Ето част от кода, мога да публикувам още, ако е необходимо:

%% setting up the basis functions, storing them in cell array
basisFunctions = cell(nu, 1); %nu is #unknowns 
i = 1;
for j = 2:length(yc) - 1
for k = 2:length(xc) - 1
    basisFunctions{i} = @(x,y) bilinearBasisFunction(x,y, xc(k-1), xc(k),...
        xc(k+1), yc(j-1), yc(j), yc(j+1)); %my code for bilinear basis functions
    i = i+1;
end
end

%% Assemble matrices and RHS
M = zeros(nu,nu);
S = zeros(nu,nu);
F = zeros(nu, 1);

for iE = 1:ne
for iBF = 1:nu
    [z1, dx1, dy1] = basisFunctions{iBF}(qx(iE), qy(iE));

    F(iBF) = F(iBF) + z1*forcing_handle(qx(iE),qy(iE))/ae(iE);

    for jBF = 1:nu
        [z2, dx2, dy2] = basisFunctions{jBF}(qx(iE), qy(iE));

        %M(iBF,jBF) = M(iBF,jBF) + z1*z2/ae(iE);
        S(iBF,jBF) = S(iBF, jBF) + (dx1*dx2 + dy1*dy2)/ae(iE);
    end        
end
end

person Lukas Bystricky    schedule 20.11.2013    source източник
comment
Като начало вие извиквате този ред 156 800 пъти (създавайки толкова много анонимни функции) в двоен for цикъл и променяте стойностите на параметрите с помощта на индексиране всеки път! И сигурни ли сте, че nu е равно на (length(xc)-2)*(length(yc)-2), за да избегнете преразпределение в масива basisFunctions на клетка?   -  person horchler    schedule 20.11.2013
comment
Има ли причина да има 156800 функции вместо една функция с параметрите (jBF,qx(iE), qy(iE))?   -  person Daniel    schedule 20.11.2013
comment
@DanielR : има само 49 функции, всяка с малко по-различни параметри. Има и други начини да направите това, разбира се, но начинът, по който го направих тук, има предимството, че е много четим и не виждам защо трябва да е толкова по-бавен.   -  person Lukas Bystricky    schedule 20.11.2013
comment
Тогава какво се прави 156 800 пъти? matrix_assembly името на подфункция в рамките на bilinearBasisFunction ли е?   -  person horchler    schedule 20.11.2013
comment
@horchler: да, наричам го много, но това е неизбежно, трябва много да оценявам моите базови функции. Също така извиквам bilinearBasisFunction 156800 пъти, но това отнема само 2 секунди според профилиращия.   -  person Lukas Bystricky    schedule 20.11.2013
comment
@horchler: моето разбиране е, че имам достъп до масива 156800 пъти и това е тясното място. Може обаче да тълкувам погрешно профилиращия.   -  person Lukas Bystricky    schedule 20.11.2013
comment
За да кажем нещо, ще трябва да видим matrix_assembly и може би bilinearBasisFunction тогава. Дори всяко повикване да отнеме няколко десети от милисекунди, ще се съберат 156 800 извиквания на функции.   -  person horchler    schedule 20.11.2013
comment
@horchler: Трябваше да изясня това, но matrix_assembly е кодът, който публикувах. Наистина няма много повече за това, освен решаването на системата. ne е броят на елементите (64 за мрежа 9x9), така че това е по-голямата част от 156800 извиквания (64*49*49).   -  person Lukas Bystricky    schedule 20.11.2013
comment
Освен ако това не е за домашна работа или за ваше собствено назидание, можете да проверите дали имате Частично диференциално уравнение кутия с инструменти (имам я с моята институционална версия на R2013a) и вижте тази статия.   -  person horchler    schedule 20.11.2013
comment
@horchler : Благодаря, но правя това с образователна цел.   -  person Lukas Bystricky    schedule 20.11.2013


Отговори (1)


Опитайте да промените basisFunctions от клетъчен масив на обикновен масив.

Можете също да опитате да вградите директното повикване към bilinearBasisFunctionв рамките на вашия jBF цикъл, вместо да използвате basisFunctions. Създаването и по-късното използване на анонимни функции в Matlab винаги е по-бавно от директното използване на целевата функция. Кодът може да е малко по-подробен по този начин, но ще бъде по-бърз.

person Yair Altman    schedule 21.11.2013