MATLAB How to vectorize these for loops? - matlab

I've searched a lot but didn't find any solution to my problem, could you please help me vectorizing (or just a way to make it way faster) these loops ?
% n is the size of C
h = 1/(n-1)
dt = 1e-6;
a = 1e-2;
F=zeros(n,n);
F2=zeros(n,n);
C2=zeros(n,n);
t = 0.0;
for iter=1:12000
F2=F.^3-F;
for i=1:n
for j=1:n
F2(i,j)=F2(i,j)-(C(ij(i-1),j)+C(ij(i+1),j)+C(i,ij(j-1))+C(i,ij(j+1))-4*C(i,j)).*(a.^2)./(h.^2);
end
end
F=F2;
for i=1:n
for j=1:n
C2(i,j)=C(i,j)+(F(ij(i-1),j)+F(ij(i+1),j)+F(i,ij(j-1))+F(i,ij(j+1))-4*F(i,j)).*dt./(h^2);
end
end
C=C2;
t = t + dt;
end
function i=ij(i) %Just to have a matrix as loop (the n+1 th cases are the 1 th and 0 the 0th are nth)
if i==0
i=n;
return
elseif i==n+1
i=1;
end
return
end
thanks a lot
EDIT: Found an answer, it was totally ridiculous and I was searching way too far
%n is still the size of C
h = 1/((n-1))
dt = 1e-6;
a = 1e-2;
F=zeros(n,n);
var1=(a^2)/(h^2); %to make a bit less calculus
var2=dt/(h^2); % the same
t = 0.0;
for iter=1:12000
F=C.^3-C-var1*(C([n 1:n-1],1:n) + C([2:n 1], 1:n) + C(1:n, [n 1:n-1]) + C(1:n, [2:n 1]) - 4*C);
C = C + var2*(F([n 1:n-1], 1:n) + F([2:n 1], 1:n) + F(1:n, [n 1:n-1]) + F(1:n,[2:n 1]) - 4*F);
t = t + dt;
end

Found an answer, it was totally ridiculous and I was searching way too far
%n is still the size of C
h = 1/((n-1))
dt = 1e-6;
a = 1e-2;
F=zeros(n,n);
var1=(a^2)/(h^2); %to make a bit less calculus
var2=dt/(h^2); % the same
prev = [n 1:n-1];
next = [2:n 1];
t = 0.0;
for iter=1:12000
F = C.*C.*C - C - var1*(C(:,next)+C(:,prev)+C(next,:)+C(prev,:)-4*C);
C = C + var2*(F(:,next)+F(:,prev)+F(next,:)+F(prev,:)-4*F);
t = t + dt;
end

The behavior of the inner loop looks like a 2-dimensional circular convolution. That's the same as multiplication in the FFT domain. Subtraction is invariant across a linear operation such as FFT.
You'll want to use the fft2 and ifft2 functions.
Once you do that, I think you'll find that the repeated convolution can be eliminated by raising the convolution kernel (element-wise) to the power iter. If that optimization is correct, I'm predicting a speedup of 5 orders of magnitude.

You can replace for example C(ij(i-1),j) by using circshift(C,[1,0]) or circshift(C,[1,0]) (i can't figure out witch one of two is correct)
http://www.mathworks.com/help/matlab/ref/circshift.htm

Related

2nd Order ODE Approx using Finite Difference

I am trying to approximate and plot the solution to u"(x) = exp(x) in the interval 0-3, with boundary conditions x(0)=1,x(3)=3. I am able to plot the approximate solution vs the exact, but the plot looks a bit off:
% Interval
a=0;
b=3;
n=10;
% Boundary vals
alpha=1;
beta=3;
%grid size
h=(b-a)/(n+1);
%Matrix generation
m = -2;
u = 1;
l = 1;
% Obtained from (y(i-1) -2y(i) + y(i+1)) = h^2 exp(x(i)
M = (1/h^2).*(diag(m*ones(1,n)) + diag(u*ones(1,n-1),1) + diag(l*ones(1,n-1),-1));
B=[];
xjj=[];
for j=1:n
xjj=[xjj,j*h];
if j==1
B=[B,f(j*h)-(alpha/h^2)];
continue
end
if j==n
B=[B,f(j*h)-(beta/h^2)];
continue
else
B=[B,f(j*h)];
end
end
X=M\B';
x=linspace(0,3,101);
plot(xjj',X,'r*')
hold on
plot(x,exp(x),'b-')
I appreciate all the advice and explanation. This is the scheme I am following: http://web.mit.edu/10.001/Web/Course_Notes/Differential_Equations_Notes/node9.html
You could shorten the big loop to simply
x=linspace(a,b,n+2);
B = f(x(2:end-1));
B(1)-=alpha/h^2;
B(n)-=beta/h^2;
The exact solution is u(x)=C*x+D+exp(x), the boundary conditions give D=0 and 3*C+exp(3)=3 <=> C=1-exp(3)/3.
Plotting this exact solution against the numerical solution gives a quite good fit for this large step size:
f=#(x)exp(x)
a=0; b=3;
n=10;
% Boundary vals
alpha=1; beta=3;
%grid
x=linspace(a,b,n+2);
h=x(2)-x(1);
% M*u=B obtained from (u(i-1) -2u(i) + u(i+1)) = h^2 exp(x(i))
M = (1/h^2).*(diag(-2*ones(1,n)) + diag(1*ones(1,n-1),1) + diag(1*ones(1,n-1),-1));
B = f(x(2:end-1));
B(1)-=alpha/h^2; B(n)-=beta/h^2;
U=M\B';
U = [ alpha; U; beta ];
clf;
plot(x',U,'r*')
hold on
x=linspace(0,3,101);
C = 1-exp(3)/3
plot(x,exp(x)+C*x,'b-')

Error in FDM for a coupled PDEs

Here is the code which is trying to solve a coupled PDEs using finite difference method,
clear;
Lmax = 1.0; % Maximum length
Wmax = 1.0; % Maximum wedth
Tmax = 2.; % Maximum time
% Parameters needed to solve the equation
K = 30; % Number of time steps
n = 3; % Number of space steps
m =30; % Number of space steps
M = 2;
N = 1;
Pr = 1;
Re = 1;
Gr = 5;
maxn=20; % The wave-front: intermediate point from which u=0
maxm = 20;
maxk = 20;
dt = Tmax/K;
dx = Lmax/n;
dy = Wmax/m;
%M = a*B1^2*l/(p*U)
b =1/(1+M*dt);
c =dt/(1+M*dt);
d = dt/((1+M*dt)*dy);
%Gr = gB*(T-T1)*l/U^2;
% Initial value of the function u (amplitude of the wave)
for i = 1:n
if i < maxn
u(i,1)=1.;
else
u(i,1)=0.;
end
x(i) =(i-1)*dx;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for j = 1:m
if j < maxm
v(j,1)=1.;
else
v(j,1)=0.;
end
y(j) =(j-1)*dy;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for k = 1:K
if k < maxk
T(k,1)=1.;
else
T(k,1)=0.;
end
z(k) =(k-1)*dt;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Value at the boundary
%for k=0:K
%end
% Implementation of the explicit method
for k=0:K % Time loop
for i=1:n % Space loop
for j=1:m
u(i,j,k+1) = b*u(i,j,k)+c*Gr*T(i,j,k+1)+d*[((u(i,j+1,k)-u(i,j,k))/dy)^(N-1)*((u(i,j+1,k)-u(i,j,k))/dy)]-d*[((u(i,j,k)-u(i,j-1,k))/dy)^(N-1)*((u(i,j,k)-u(i,j-1,k))/dy)]-d*[u(i,j,k)*((u(i,j,k)-u(i-1,j,k))/dx)+v(i,j,k)*((u(i,j+1,k)-u(i,j,k))/dy)];
v(i,j,k+1) = dy*[(u(i-1,j,k+1)-u(i,j,k+1))/dx]+v(i,j-1,k+1);
T(i,j,k+1) = T(i,j,k)+(dt/(Pr*Re))*{(T(i,j+1,k)-2*T(i,j,k)+T(i,j-1,k))/dy^2-Pr*Re{u(i,j,k)*((T(i,j,k)-T(i-1,j,k))/dx)+v(i,j,k)*((T(i,j+1,k)-T(i,j,k))/dy)}};
end
end
end
% Graphical representation of the wave at different selected times
plot(x,u(:,1),'-',x,u(:,10),'-',x,u(:,50),'-',x,u(:,100),'-')
title('graphs')
xlabel('X')
ylabel('Y')
But I am getting this error
Subscript indices must either be real positive integers or logicals.
I am trying to implement this
with boundary conditions
Can someone please help me out!
Thanks
To be quite honest, it looks like you started with something that's way over your head, just typed everything down in one go without thinking much, and now you are surprised that it doesn't work...
In the future, please break down problems like these into waaaay smaller chunks that you can individually plot, check, test, etc. Better yet, try simpler problems first (wave equation, heat equation, ...), gradually working your way up to this.
I say this so harshly, because there were quite a number of fairly basic things wrong with your code:
you've used braces ({}) and brackets ([]) exactly as they are written in the equation. In MATLAB, braces are a constructor for a special container object called a cell array, and brackets are used to construct arrays and matrices. To group things like in the equation, you always have to use parentheses (()).
You had quite a number of parentheses wrong, which became apparent when I re-grouped and broke up those huge unintelligible lines into multiple lines that humans can actually read with understanding
you forgot to take the absolute values in the 3rd and 4th terms of u
you looped over k = 0:K and j = 1:m and then happily index everything with k and j-1. MATLAB is 1-based, meaning, the first element of anything is element 1, and indexing with 0 is an error
you've initialized 3 vectors u, v and T, but then index those in the loop as if they are 3D arrays
Now, I've managed to come up with the following code, which runs OK and at least more or less agrees with the equations shown. But I think it still doesn't make much sense because I get only zeros out (except for the initial values).
But, with this feedback, you should be able to correct any problems left.
Lmax = 1.0; % Maximum length
Wmax = 1.0; % Maximum wedth
Tmax = 2.; % Maximum time
% Parameters needed to solve the equation
K = 30; % Number of time steps
n = 3; % Number of space steps
m = 30; % Number of space steps
M = 2;
N = 1;
Pr = 1;
Re = 1;
Gr = 5;
maxn = 20; % The wave-front: intermediate point from which u=0
maxm = 20;
maxk = 20;
dt = Tmax/K;
dx = Lmax/n;
dy = Wmax/m;
%M = a*B1^2*l/(p*U)
b = 1/(1+M*dt);
c = dt/(1+M*dt);
d = dt/((1+M*dt)*dy);
%Gr = gB*(T-T1)*l/U^2;
% Initial value of the function u (amplitude of the wave)
u = zeros(n,m,K+1);
x = zeros(n,1);
for i = 1:n
if i < maxn
u(i,1)=1.;
else
u(i,1)=0.;
end
x(i) =(i-1)*dx;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
v = zeros(n,m,K+1);
y = zeros(m,1);
for j = 1:m
if j < maxm
v(1,j,1)=1.;
else
v(1,j,1)=0.;
end
y(j) =(j-1)*dy;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
T = zeros(n,m,K+1);
z = zeros(K,1);
for k = 1:K
if k < maxk
T(1,1,k)=1.;
else
T(1,1,k)=0.;
end
z(k) =(k-1)*dt;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Value at the boundary
%for k=0:K
%end
% Implementation of the explicit method
for k = 2:K % Time loop
for i = 2:n % Space loop
for j = 2:m-1
u(i,j,k+1) = b*u(i,j,k) + ...
c*Gr*T(i,j,k+1) + ...
d*(abs(u(i,j+1,k) - u(i,j ,k))/dy)^(N-1)*((u(i,j+1,k) - u(i,j ,k))/dy) - ...
d*(abs(u(i,j ,k) - u(i,j-1,k))/dy)^(N-1)*((u(i,j ,k) - u(i,j-1,k))/dy) - ...
d*(u(i,j,k)*((u(i,j ,k) - u(i-1,j,k))/dx) +...
v(i,j,k)*((u(i,j+1,k) - u(i ,j,k))/dy));
v(i,j,k+1) = dy*(u(i-1,j,k+1)-u(i,j,k+1))/dx + ...
v(i,j-1,k+1);
T(i,j,k+1) = T(i,j,k) + dt/(Pr*Re) * (...
(T(i,j+1,k) - 2*T(i,j,k) + T(i,j-1,k))/dy^2 - Pr*Re*(...
u(i,j,k)*((T(i,j,k) - T(i-1,j,k))/dx) + v(i,j,k)*((T(i,j+1,k) - T(i,j,k))/dy))...
);
end
end
end
% Graphical representation of the wave at different selected times
figure, hold on
plot(x, u(:, 1), '-',...
x, u(:, 10), '-',...
x, u(:, 50), '-',...
x, u(:,100), '-')
title('graphs')
xlabel('X')
ylabel('Y')

Shorten this in Matlab

Let x = [1,...,t] be a vector with t components and A and P arrays. I asked myself whether there is any chance to shorten this, as it looks very cumbersome:
for n = 1:t
for m = 1:n
H(n,m) = A(n,m) + x(n) * P(n,m)
end
end
My suggestion: bsxfun(#times,x,P) + A;
e.g.
A = rand(3);
P = rand(3);
x = rand(3,1);
for n = 1:3
for m = 1:3
H(n,m) = A(n,m) + x(n) * P(n,m);
end
end
H2 = bsxfun(#times,x,P) + A;
%//Check that they're the same
all(H(:) == H2(:))
returns
ans = 1
EDIT:
Amro is right! To make the second loop is dependent on the first use tril:
H2 = tril(bsxfun(#times,x,P) + A);
Are the matrices square btw because that also creates other problems
tril(A + P.*repmat(x',1,t))
EDIT. This is for when x is row vector.
If x is a column vector, then use tril(A + P.*repmat(x,t,1))
If your example code is correct, then H(i,j) = 0 for any j > i, e.g. X(1,2).
For t = 3 for example, you would have.
H =
'A(1,1) + x(1) * P(1,1)' [] []
'A(2,1) + x(2) * P(2,1)' 'A(2,2) + x(2) * P(2,2)' []
'A(3,1) + x(3) * P(3,1)' 'A(3,2) + x(3) * P(3,2)' 'A(3,3) + x(3) * P(3,3)'
Like I pointed out in the comments, unless it was a typo mistake, the second for-loop counter depends on that of the first for-loop...
In case it was intentional, I came up with the following solution:
% some random data
t = 10;
x = (1:t)';
A = rand(t,t);
P = rand(t,t);
% double for-loop
H = zeros(t,t);
for n = 1:t
for m = 1:n
H(n,m) = A(n,m) + x(n) * P(n,m);
end
end
% vectorized using linear-indexing
[a,b] = ndgrid(1:t,1:t);
idx = sub2ind([t t], nonzeros(tril(a)), nonzeros(tril(b)));
xidx = nonzeros(tril(a));
HH = zeros(t);
HH(tril(true(t))) = A(idx) + x(xidx).*P(idx);
% check the results are the same
assert(isequal(H,HH))
I like #Dan's solution better. The only advantage here is that I do not compute unnecessary values (since the upper half of the matrix is zeros), while the other solution computes the full matrix and then cut back the extra stuff.
A good start would be
H = A + x*P
This may not be a working solution, you'll have to check conformability of arrays and vectors, and make sure that you're using the correct multiplication, but this should be enough to point you in the right direction. If you're new to Matlab be aware that vectors can be either 1xn or nx1, ie row and column vectors are different species unlike in so many programming languages. If x isn't what you want on the rhs, you may want its transpose, x' in Matlab.
Matlab is, from one point of view, an array language, explicit loops are often unnecessary and frequently not even a good way to go.
Since the range for second loop is 1:n, you can take the lower triangle parts of matrices A and P for calculation
H = bsxfun(#times,x(:),tril(P)) + tril(A);

Finding matrix inverse by Gaussian Elimination With Partial Pivoting

Hello guys I am writing program to compute determinant(this part i already did) and Inverse matrix with GEPP. Here problem arises since i have completely no idea how to inverse Matrix using GEPP, i know how to inverse using Gauss Elimination ([A|I]=>[I|B]). I have searched through internet but still no clue, could you please explain me?
Here is my matlab code (maybe someone will find it useful), as of now it solves AX=b and computes determinant:
function [det1,X ] = gauss_czesciowy( A, b )
%GEPP
perm=0;
n = length(b);
if n~=m
error('vector has wrong size');
end
for j = 1:n
p=j;
% choice of main element
for i = j:n
if abs(A(i,j)) >= abs(A(p,j))
p = i;
end
end
if A(p,j) == 0
error('Matrix A is singular');
end
%rows permutation
t = A(p,:);
A(p,:) = A(j,:);
A(j,:) = t;
t = b(p);
b(p) = b(j);
b(j) = t;
if~(p==i)
perm=perm+1;
end
% reduction
for i = j+1:n
t = (A(i,j)/A(j,j));
A(i,:) = A(i,:)-A(j,:)*t;
b(i) = b(i)-b(j)*t;
end
end
%determinant
mn=1;
for i=1:n
mn=mn*A(i,i);
end
det1=mn*(-1)^perm;
% solution
X = zeros(1,n);
X(n) = b(n)/A(n,n);
if (det1~=0)
for i = 1:n
s = sum( A(i, (i+1):n) .* X((i+1):n) );
X(i) = (b(i) - s) / A(i,i);
end
end
end
Here is the algorithm for Guassian elimination with partial pivoting. Basically you do Gaussian elimination as usual, but at each step you exchange rows to pick the largest-valued pivot available.
To get the inverse, you have to keep track of how you are switching rows and create a permutation matrix P. The permutation matrix is just the identity matrix of the same size as your A-matrix, but with the same row switches performed. Then you have:
[A] --> GEPP --> [B] and [P]
[A]^(-1) = [B]*[P]
I would try this on a couple of matrices just to be sure.
EDIT: Rather than empirically testing this, let's reason it out. Basically what you are doing when you switch rows in A is you are multiplying it by your permutation matrix P. You could just do this before you started GE and end up with the same result, which would be:
[P*A|I] --> GE --> [I|B] or
(P*A)^(-1) = B
Due to the properties of the inverse operation, this can be rewritten:
A^(-1) * P^(-1) = B
And you can multiply both sides by P on the right to get:
A^(-1) * P^(-1)*P = B*P
A^(-1) * I = B*P
A^(-1) = B*P

Lagrange interpolation method

I use convolution and for loops (too much for loops) for calculating the interpolation using
Lagrange's method , here's the main code :
function[p] = lagrange_interpolation(X,Y)
L = zeros(n);
p = zeros(1,n);
% computing L matrice, so that each row i holds the polynom L_i
% Now we compute li(x) for i=0....n ,and we build the polynomial
for k=1:n
multiplier = 1;
outputConv = ones(1,1);
for index = 1:n
if(index ~= k && X(index) ~= X(k))
outputConv = conv(outputConv,[1,-X(index)]);
multiplier = multiplier * ((X(k) - X(index))^-1);
end
end
polynimialSize = length(outputConv);
for index = 1:polynimialSize
L(k,n - index + 1) = outputConv(polynimialSize - index + 1);
end
L(k,:) = multiplier .* L(k,:);
end
% continues
end
Those are too much for loops for computing the l_i(x) (this is done before the last calculation of P_n(x) = Sigma of y_i * l_i(x)) .
Any suggestions into making it more matlab formal ?
Thanks
Yeah, several suggestions (implemented in version 1 below): if loop can be combined with for above it (just make index skip k via something like jr(jr~=j) below); polynomialSize is always equal length(outputConv) which is always equal n (because you have n datapoints, (n-1)th polynomial with n coefficients), so the last for loop and next line can be also replaced with simple L(k,:) = multiplier * outputConv;
So I replicated the example on http://en.wikipedia.org/wiki/Lagrange_polynomial (and adopted their j-m notation, but for me j goes 1:n and m is 1:n and m~=j), hence my initialization looks like
clear; clc;
X=[-9 -4 -1 7]; %example taken from http://en.wikipedia.org/wiki/Lagrange_polynomial
Y=[ 5 2 -2 9];
n=length(X); %Lagrange basis polinomials are (n-1)th order, have n coefficients
lj = zeros(1,n); %storage for numerator of Lagrange basis polyns - each w/ n coeff
Lj = zeros(n); %matrix of Lagrange basis polyns coeffs (lj(x))
L = zeros(1,n); %the Lagrange polynomial coefficients (L(x))
then v 1.0 looks like
jr=1:n; %j-range: 1<=j<=n
for j=jr %my j is your k
multiplier = 1;
outputConv = 1; %numerator of lj(x)
mr=jr(jr~=j); %m-range: 1<=m<=n, m~=j
for m = mr %my m is your index
outputConv = conv(outputConv,[1 -X(m)]);
multiplier = multiplier * ((X(j) - X(m))^-1);
end
Lj(j,:) = multiplier * outputConv; %jth Lagrange basis polinomial lj(x)
end
L = Y*Lj; %coefficients of Lagrange polinomial L(x)
which can be further simplified if you realize that numerator of l_j(x) is just a polynomial with specific roots - for that there is a nice command in matlab - poly. Similarly the denominator is just that polyn evaluated at X(j) - for that there is polyval. Hence, v 1.9:
jr=1:n; %j-range: 1<=j<=n
for j=jr
mr=jr(jr~=j); %m-range: 1<=m<=n, m~=j
lj=poly(X(mr)); %numerator of lj(x)
mult=1/polyval(lj,X(j)); %denominator of lj(x)
Lj(j,:) = mult * lj; %jth Lagrange basis polinomial lj(x)
end
L = Y*Lj; %coefficients of Lagrange polinomial L(x)
Why version 1.9 and not 2.0? well, there is probably a way to get rid of this last for loop, and write it all in 1 line, but I can't think of it right now - it's a todo for v 2.0 :)
And, for dessert, if you want to get the same picture as wikipedia:
figure(1);clf
x=-10:.1:10;
hold on
plot(x,polyval(Y(1)*Lj(1,:),x),'r','linewidth',2)
plot(x,polyval(Y(2)*Lj(2,:),x),'b','linewidth',2)
plot(x,polyval(Y(3)*Lj(3,:),x),'g','linewidth',2)
plot(x,polyval(Y(4)*Lj(4,:),x),'y','linewidth',2)
plot(x,polyval(L,x),'k','linewidth',2)
plot(X,Y,'ro','linewidth',2,'markersize',10)
hold off
xlim([-10 10])
ylim([-10 10])
set(gca,'XTick',-10:10)
set(gca,'YTick',-10:10)
grid on
produces
enjoy and feel free to reuse/improve
Try:
X=0:1/20:1; Y=cos(X) and create L and apply polyval(L,1).
polyval(L,1)=0.917483227909543
cos(1)=0.540302305868140
Why there is huge difference?