Avoiding operations on the same component in nested for loops
3 views (last 30 days)
Show older comments
Fredrik Carlsson
on 29 Jan 2015
Answered: Fredrik Carlsson
on 15 Feb 2015
I'm trying to optimize an implementation of Newtons gravity law using a Runge-Kutta of the fourth order for an assignment in a course I'm taking, so far it works as it should but is rather slow when it is to plot/make video the orbits of the objects. Aside from using a different numerical integrator, as I am aware of the problems of Runge-Kutta, but the assignment was specific about implementing the method, I have tried to take away as many loops as I can during the calculations of the derivatives.
So far I have two nested for loops in a function that will calculate the derivatives as shown below. The W argument is a matrix containg the objects location and velocity in x y z direction on a row as,
object1 (x,y,z,vx,vy,vz);
object2 (x,y,z,vx,vy,vz); ...
i.e. each row is a planet or star in this case.
The Gm parameter is an array containing the masses of the objects multiplied by G.
The t should be a scalar but is not used.
As shown in the code the dvdt operation is only to be done when i~=j since it would otherwise mean division with 0. I'm wondering if there is a way to get rid of the second loop, I have tried it by using vector operations as MatLAB is constructed to do, but I cannot find a way to make sure that if statement is included either explicitly or implicitly.
function dwdt = g2(W,Gm,t)
dxdt = zeros(size(W(:,1:3)));
dvdt = zeros(size(W(:,1:3)));
for i=1:size(W,1) %Iterate over number of objects
dxdt(i,:) = W(i,4:6);
for j=1:size(W,1) %Iterate over number of objects
if j~=i
r3 = norm(W(i,1:3)-W(j,1:3)).^3;
dvdt(i,:) = dvdt(i,:) - Gm(j).*(W(i,1:3)-W(j,1:3))./r3;
end
end
end
dwdt = [dxdt dvdt];
end
4 Comments
Matt J
on 30 Jan 2015
Edited: Matt J
on 30 Jan 2015
just a good habit to get into: avoid using i and j as counters or variables, because sometimes Matlab thinks they're the imaginary unit.
A better habit is to stop using i and j for the imaginary unit and start using 1i and 1j
>> for i=1:3, 10*i+1i, end
ans =
10.0000 + 1.0000i
ans =
20.0000 + 1.0000i
ans =
30.0000 + 1.0000i
Accepted Answer
More Answers (1)
Jan
on 30 Jan 2015
This wastes time:
dxdt = zeros(size(W(:,1:3)));
The temporary array "W(:, 1:3)" is created, but not used. Better:
dxdt = zeros(size(W, 1), 3);
norm is not really fast. Look in the FileExchange for "DNorm2". But your vectors are tiny and a simple sqrt(sum(x.*x)) might be more efficient.
Do not calculate "W(i,1:3)-W(j,1:3)" twice. Do this once only and store it in a variable.
See Also
Categories
Find more on Loops and Conditional Statements in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!