Hallo, ich hoffe ihr könnt mir weiterhelfen.
Ich beschäftige mich nun seit ein paar Wochen im Rahmen einer Studienarbeit mit MATLAB. Nun habe ich das Problem, dass aufgrund der for-Schleife im Programm der Rechenaufwand zu groß wird. Leider habe ich keine Idee wie ich diese ersetzen kann, ohne Auswirkung auf die Ausgabe.
Die for-Schleife sieht wie folgt aus:
Code:
for i=1:nn
if(Rand(i)==0) % Koeffizienten von u_xx in Matrix schreiben.
c_p=0.5*(c(i+1)+c(i)); c_m=0.5*(c(i-1)+c(i));
A(i,i-1)=-c_m/dx^2;
A(i,i+1)=-c_p/dx^2;
A(i,i)=A(i,i)+(c_m+c_p)/dx^2;
% Koeffizienten von u_yy in Matrix schreiben.
c_p=0.5*(c(i+n)+c(i)); c_m=0.5*(c(i-n)+c(i));
A(i,i-n)=-c_m/dx^2;
A(i,i+n)=-c_p/dx^2;
A(i,i)=A(i,i)+(c_m+c_p)/dx^2;
end end
% Erzeuge einen Vektor, der fuer alle Randknoten den Wert 1 und fuer alle % inneren Knoten den Wert 0 enthaelt. Rand(1:n)=1; Rand((n-1)*n+1:nn)=1;
for i=2:n-1 Rand(i*n)=1;
end
for i=1:nn
if(Rand(i)==0) % Koeffizienten von u_xx in Matrix schreiben.
c_p=0.5*(c(i+1)+c(i)); c_m=0.5*(c(i-1)+c(i));
A(i,i-1)=-c_m/dx^2;
A(i,i+1)=-c_p/dx^2;
A(i,i)=A(i,i)+(c_m+c_p)/dx^2;
% Koeffizienten von u_yy in Matrix schreiben.
c_p=0.5*(c(i+n)+c(i)); c_m=0.5*(c(i-n)+c(i));
A(i,i-n)=-c_m/dx^2;
A(i,i+n)=-c_p/dx^2;
A(i,i)=A(i,i)+(c_m+c_p)/dx^2;
end end
% Setzen der Randwerte. Ueberschreiben der zugehoerigen Matrixzeile mit dem % Einheitsvektor und überschreiben der rechten Seite mit dem Randwert. for i=1:nn
if(Rand(i))==1
f(i)=0;
A(i,:)=0;
A(i,i)=1;
end end
u=mldivide(A,f);
end
Einfache Regel: Vermeide alle wiederholten Berechnungen innerhalb der Schleife.
Welche Größe haben die Inputs etwa? Es ist ein Unterschied, ob es um hunderte oder Milliarden Iterationen geht.
Code:
function[ u ] = s(X,Y,c,dx)
N=size(X);
n=N(1); % IMMER nur ein Befehl pro Zeile!!!
nn = n^2;
A=sparse(nn,nn);
Rand = zeros(nn,1); % Sparse-Vektoren sind wahrscheinlich Zeit-Verschwendung
% Erzeuge einen Vektor, der fuer alle Randknoten den Wert 1 und fuer alle % inneren Knoten den Wert 0 enthaelt. Rand(1:n) = 1;
Rand((n-1)*n+1:nn) = 1;
Rand(2*n:n:n*n-n) = 1;
Rand((1:n-1)*n+1) = 1;
for i=1:nn
ifRand(i)==0 % Koeffizienten von u_xx in Matrix schreiben.
c_p=0.5*(c(i+1)+c(i));
c_m=0.5*(c(i-1)+c(i));
A(i,i-1) = -c_m;
A(i,i+1) = -c_p;
% Koeffizienten von u_yy in Matrix schreiben.
c_p2 = 0.5*(c(i+n)+c(i));
c_m2 = 0.5*(c(i-n)+c(i));
A(i,i-n)=-c_m2;
A(i,i+n)=-c_p2;
A(i,i)=(c_m+c_p+cm2+c_p2); % Das A(ii)+ ist überflüssig, oder? end end
A = A / dx^2;
% Setzen der Randwerte. Ueberschreiben der zugehoerigen Matrixzeile mit dem % Einheitsvektor und überschreiben der rechten Seite mit dem Randwert.
match = (Rand == 1);
f(match) = 0;
for i=1:nn
if match(i)
A(i,:)=0;
A(i,i)=1;
end end
u=mldivide(A,f);
end
Und? Wie groß ist der Unterschied? Welche Zeilen benötigen laut Profiler die meiste Zeit?
Der Zugriff auf die Sparse_Elemente ist zeitraubend. Du könntest die Indices und Werte in Full-Vektoren speichern und die Sparse-Matrix A nach der Schleife erzeugen.
Vielen Dank für die Antwort,
die Berechnungen in der for-Schleife sind alle von der Laufvariable i abhängig, sodass ich keine Werte außerhalb der Schleife berechnen kann. oder seh ich das falsch?
Die for-Schleife benötigt 0.500159 seconds.
Und die eigentliche Berechnung 0.039881 seconds.
Dort stimmt das Verhältnis also überhaupt nicht.
n ist die Länge des x-Vektors.
Inputs sind folgende
Ich habe jetzt Vektoren erstellt, sodass in der Schleife nicht ständig auf die sparse Matrix A zugegriffen werden muss. Wie Sie vorgeschlagen haben, habe ich die full Vektoren in die sparse Matrix geschrieben, jedoch hat das nicht die Rechenzeit verkürzt.
% Rechte Seite
f=X.*sin(X).*sin(Y)-Y.*cos(X).*cos(Y)+2*X.*Y.*cos(Y).*sin(X); % fuer c=xy; u=sin(x)*cos(y)
%f=2*sin(X).*cos(Y);
f=reshape(f,nn,1);
% Erzeuge einen Vektor, der fuer alle Randknoten den Wert 1 und fuer alle % inneren Knoten den Wert 0 enthaelt. Rand(1:n) = 1;
Rand((n-1)*n+1:nn) = 1;
Rand(2*n:n:n*n-n) = 1;
Rand((1:n-1)*n+1) = 1;
tic for i=1:nn
if(Rand(i)==0) % Koeffizienten von u_xx in Matrix schreiben. Randknoten werden zunaechst ausgelassen.
c_p=0.5*(c(i+1)+c(i)); c_m=0.5*(c(i-1)+c(i));
vec_xunten(i)=-c_m/dx^2;
vec_xoben(i)=-c_p/dx^2;
vec_xdiagonale(i)=vec_xdiagonale(i)+(c_m+c_p)/dx^2
% Koeffizienten von u_yy in Matrix schreiben. Randknoten werden zunaechst ausgelassen.
c_p=0.5*(c(i+n)+c(i)); c_m=0.5*(c(i-n)+c(i));
vec_yunten(i)=-c_m/dx^2;
vec_yoben(i)=-c_p/dx^2;
vec_ydiagonale(i)=vec_xdiagonale(i)+(c_m+c_p)/dx^2;
end end
for i=1:nn
if(Rand(i)==0)
A(i,i-1)=vec_xunten(i);
A(i,i+1)=vec_xoben(i);
A(i,i)=vec_xdiagonale(i);
A(i,i-n)=vec_yunten(i);
A(i,i+n)=vec_yoben(i);
A(i,i)=vec_ydiagonale(i);
end end toc
% Setzen der Randwerte. Ueberschreiben der zugehoerigen Matrixzeile mit dem % Einheitsvektor und überschreiben der rechten Seite mit dem Randwert. for i=1:nn
if(Rand(i)==1)
f(i)=0;
A(i,:)=0;
A(i,i)=1;
end end
Der Power-Operator ist ziemlich teuer. Da in jeder Iteration mehrfach "/dx^2" berechnet wird, ist es sinnvoller, das aus der Schleife heraus zu ziehen.
Zitat:
Die for-Schleife benötigt 0.500159 seconds.
Und die eigentliche Berechnung 0.039881 seconds.
Welche der FOR-Schleifen und welche Zeile ist "die eigentliche Berechnung"?
Wie große sind die Input-Array typischerweise? 100 Elemente?
Der Hinweis, nur einen Befehl pro Zeile zu verwenden, kann sehr wichtig sein. Andernfalls kann nämlich Matlabs JIT-Beschleunigung die Schleifen nicht effizient bearbeiten.
Gruß, Jan
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.