Optimisation de code MATLAB

Fermé
Cherry - Modifié par Cherry le 31/07/2012 à 13:38
 Cherry - 1 août 2012 à 14:47
Bonjour,

Je travaille sur MATLAB en ce moment et j'ai un problème de temps d'exécution. La cause : 5 boucles imbriquées 11x128x128x128x128 = 3 milliards d'itérations. Je sais que c'est mal mais cela fait plusieurs jours / semaines que je réfléchis à comment optimiser mon code, en passant par l'écriture matricielle, en vain. Ci-dessous un copier-coller de mon code pour voir si vous avez des idées d'optimisation.

J'ai également pensé à convertir ce bout de code en C, C++ ou Fortran, via les MEX-files de MATLAB. J'ai demandé à Mathworks une version d'évaluation de leur toolbox "MATLAB Coder" (http://www.mathworks.fr/products/matlab-coder/index.html), qui m'a l'air intéressant. Je me trompe ?

Merci de me tenir au courant de vos idées. Et merci de votre aide !

-------------

for klat_s = 1 : 11

disp( [ ' ANALYSE DE LA LATITUDE : ' , num2str( lat_s(klat_s) ) ] ) ;

fabcd = zeros( nt , nx ) ;
fst = zeros( nt , nx ) ;
fwr = zeros( nt , nx ) ; fwl = zeros( nt ,nx ) ;
fer = zeros( nt , nx ) ; fel = zeros( nt ,nx ) ;
fwerl = zeros( nt , nx ) ;

% Balayage en temps
for jt = 1 : 128

tic
disp(['jt = ', num2str(jt)])

% Balayage en espace
for ix = 1 : 128

disp([' ix = ', num2str(ix)])

dfabcd = 0 ;
dfss = 0 ;
dfww = 0 ; dfwr = 0 ; dfwl = 0 ;
dfee = 0 ; dfer = 0 ; dfel = 0 ;

% Balayage des pulsations
for jl = 1 : 128


if( pe(jl) <= 10 )
iw_r = 1 ; iw_l = 0 ;
ie_r = 1 ; ie_l = 0 ;
elseif( pe(jl) <= 20 )
iw_r = 0 ; iw_l = 1 ;
ie_r = 1 ; ie_l = 0 ;
else
iw_r = 0 ; iw_l = 1 ;
ie_r = 0 ; ie_l = 1 ;
end

% Balayage des vecteurs d'onde
for ik = 1 : 128


dfabcd = dfabcd + cos(k(ik)*x(ix)) * (a_u( jl , ik )*cos(l(jl)*t(jt)) + b_u( jl , ik )*sin(l(jl)*t(jt))) ...
+ sin(k(ik)*x(ix)) * (c_v( jl , ik )*cos(l(jl)*t(jt)) + d_v( jl , ik)*sin(l(jl)*t(jt))) ;

dfss = dfss + ( sc_f( jl , ik ) * cos(k(ik)*x(ix)) ...
+ ss_f( jl , ik ) * sin(k(ik)*x(ix))) ...
* cos( l(jl)*t(jt) + sph_f( jl , ik ) ) ;

dfw = wc_f( jl , ik ) * cos( k(ik)*x(ix) + l(jl)*t(jt) ) ...
+ ws_f( jl , ik ) * sin( k(ik)*x(ix) + l(jl)*t(jt) ) ;
dfww = dfww + dfw ;
dfwr = dfwr + iw_r * dfw ;
dfwl = dfwl + iw_l * dfw ;

dfe = ec_f( jl , ik ) * cos( k(ik)*x(ix) - l(jl)*t(jt) ) ...
+ es_f( jl , ik ) * sin( k(ik)*x(ix) - l(jl)*t(jt) ) ;
dfee = dfee + dfe ;
dfer = dfer + ie_r * dfe ;
dfel = dfel + ie_l * dfe ;

end
end


fabcd( jt , ix ) = dfabcd ;
fst( jt , ix ) = dfss ;
fwr( jt , ix ) = dfwr ;
fwl( jt , ix ) = dfwl ;
fer( jt , ix ) = dfer ;
fel( jt , ix ) = dfel ;
fwerl( jt , ix ) = dfwr + dfwl + dfer + dfel ;

end
t_toc=toc;
disp(['Temps d''execution : ', num2str(toc)]); % donne 223 secondes en moyenne
end
end








A voir également:

1 réponse

Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
31 juil. 2012 à 14:04
Salut.
des fois, il n'est pas possible d'écrire des boucles en notation matricielle. Mais il y a d'autres manière d'optimiser un code, comme en C.
De ce que tu as fait, il faut minimiser les appels aux fonction sinus et cosinus qui sont couteuse, puis dans un second temps diminuer les opérations inutiles. Par exemple, tu calcules plusieurs fois l(jl)*t(jt), alors que tu pourrais carrément sortir ce produit de la boucle en ik.

Tu ne pourrais pas remplacer ta boucle en ik par :
dfabcd = sum(
cos(k*x(ix)) .* (a_u( jl , : )*cos(l(jl)*t(jt)) + b_u( jl , : )*sin(l(jl)*t(jt))) ...
+ sin(k*x(ix)) .* (c_v( jl , : )*cos(l(jl)*t(jt)) + d_v( jl , :)*sin(l(jl)*t(jt)))
);

on peux même peut être agir sur des matrices et virer la boucle en ik en faisant : k*x' (ou k'*x selon les dimensions respective (1,n) ou (n,1)) et en propageant les b_u et compagnie dans la bonne direction (pas sur que tu gagnes du temps au final). dfabcd serait alors un vecteur.
0
Salut,

Merci pour ta réponse.

Alors, effectivement, j'avais remarqué pour la récurrence des l(jl)*t(jt) et des cos et sin. D'ailleurs, au début, j'avais créé des variables intermédiaires en dehors de la boucle sur ik :
lt = l( jl ) * t( jt ) ;
clt = cos( lt ) ; slt = sin( lt ) ;
entre autres.

Mais j'avais des temps d'exécution beaucoup plus longs (4 heures de plus), bizarrement. Donc je me suis dit que c'était à cause de la création de nouvelles variables. Donc finalement, j'ai tout remis en cos, sin, et accès aux tableaux.

En ce qui concerne les sommes pour remplacer la boucle sur ik, effectivement !!! Je remplace ça alors ! Est-on d'accord que l'on a donc, au lieu de la boucle :
dfabcd = sum(cos(k*x(ix)) .* (a_u( jl , : ).*cos(l(jl)*t(jt)) + b_u( jl , : ).*sin(l(jl)*t(jt))) + sin(k*x(ix)) .* (c_v( jl , : ).*cos(l(jl)*t(jt)) + d_v( jl , : ).*sin(l(jl)*t(jt)))) ;
dfss = sum( sc_f( jl , : ) .* cos(k*x(ix)) + ss_f( jl , : ) .* sin(k*x(ix))) .* cos( l(jl)*t(jt) + sph_f( jl , : ) ) ;
dfww = sum(wc_f( jl , : ) .* cos( k*x(ix) + l(jl)*t(jt) ) + ws_f( jl , : ) .* sin( k*x(ix) + l(jl)*t(jt) )) ;
dfwr = iw_r * dfww ;
dfwl = iw_l * dfww ;
dfee = sum( ec_f( jl , : ) .* cos( k*x(ix) - l(jl)*t(jt) ) + es_f( jl , : ) .* sin( k*x(ix) - l(jl)*t(jt) )) ;
dfer = ie_r * dfee ;
dfel = ie_l * dfee ;
?

Et je n'ai pas compris l'histoire de la propagation des b_u et compagnie dans la bonne direction... ????

Merci bien en tout cas :)
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
31 juil. 2012 à 14:58
ça me semble bien.
je n'avais pas fait attention, en fait ta boucle suivante est sur jl.
Si tu supprimes jl des équations, tu te retrouves à multiplier des vecteurs par des matrices, ce qui ne pass pas avec ".*". Il faut donc que tu donnes aux vecteurs la forme de matrices, et comme ils ne varient pas suivant les jl, il faut que tu recopies 128 fois ton vecteur (je dirai verticalement) afin de conserver tes produits.
tu peux aussi simplifier ie_r et cie en utilisant le booléen et les indices jl :
ie_r=pe<=20;
ie_l= !ie_r ; %% not ie_r
iw_r=pe<=10;
etc.
ce qui te permet de récupérer des vecteurs et de multiplier directement tes solutions.
Tu me diras les gains de temps obtenus.
0
Bonjour,

Je me suis débrouillée pour éliminer la boucle sur ik, et j'ai utilisé les booléens au lieu de faire des if. Et certes, je gagne beaucoup de temps. Le t_toc dans la boucle jt donne maintenant 5 secondes au lieu de 223 !!! Donc je peux enfin faire tourner mon programme sans gros souci.

Ça prend toujours un certain globalement, surtout que je dois exécuter plusieurs fois ce programme. Je suppose qu'il est possible de réduire encore plus l'écriture, en éliminant la boucle sur jl, comme tu l'as suggéré et en travaillant sur les matrices. Mais là, vu que ça marche déjà pas mal, j'ai un peu la flemme de réfléchir, je passe à autre chose !

Merci beaucoup Char Snipeur, tu m'as été d'une très grande aide !
0