Using classified variables in Parallel for loops in Matlab - matlab

Hi I am trying to run a code for image reconstruction of 2D projections using the iradon transform. My aim to reduce the time significantly for which I am trying to using parallel for loop in my local cluster profile of my laptop.
But I seem to get an error which I am finding it difficult to debug-
Error: The variable data in a parfor cannot be classified.
My code-
clc;
close all;
clear all;
tic
% projection_length = input('Define projection length (px) = ');
projection_length = 4100; % which means our ouput will have 4100 cross sectional images of the capillary tube
parfor q = 1:projection_length
for i = 1:5 % typically 500, since we take 500 projections around the capillary tube 0.72 deg inc
if length(num2str(i)) == 1
data(q,:, i) = imread(['pre00' num2str(i) '.tif'], 'PixelRegion', {[1 1600], [q q]});
elseif length(num2str(i)) == 2
data(q,:, i) = imread(['pre0' num2str(i) '.tif'], 'PixelRegion', {[1 1600], [q q]});
elseif length(num2str(i)) == 3
data(q,:, i) = imread(['pre' num2str(i) '.tif'], 'PixelRegion', {[1 1600], [q q]});
end
disp(['Analyzing projection ' num2str(q) ' of ' num2str(projection_length) ', Angle ' num2str(i) '...']);
end
H = iradon( data(q,:,:), 0.72, 'Hann', 0.8, 1600);
end
toc

Firstly, I would recommend using sprintf to build the filename, like so:
fname = sprintf('pre%03d.tif', i);
data(q, :, i) = imread(fname, ...);
This will correctly zero-pad fname.
The problem with data is that you're indexing it in different ways, and unfortunately parfor cannot understand that correctly. (This should show up as a "red" warning in the MATLAB editor, which can sometimes give you better information about parfor problems). I would be tempted to fix the problem something like this:
parfor q = 1:projection_length
tmpData = zeros(N, numFiles); % insert correct value of N here
for i = 1:numFiles
fname = ...;
tmpData(:, i) = imread(fname, ...);
end
data(q, :, :) = tmpData;
H = iradon(tmpData, ...);
end
I'm not sure what you're trying to do with H - parfor will treat that as a temporary variable, and the value will not be available after the loop.

Related

Convert ode45() to scilab

I'm trying to convert this script from matlab to scilab. I tried the scilab tool for conversion but it crashes with no output so I'm doing it by hand. This is what I got by changing the comments from % to //. #markovprocessfunc refers to another file I was able to convert with the scilab automatic tool.
// Markovprocess
// Main program of the markovprocess simulation
// The system is defined by the generator matrix A
// Ulf Jeppsson, January 2017
global B
// Define the duration of the simulation
disp(' ')
disp('Automation 2017, Markov processes')
disp(' ')
tend = input('Set simulation time = ');
disp(' ')
// Make a new simulation with the same A matrix?
yes = input('Keep the old A matrix? (yes=1, no=0) ');
disp(' ')
if yes>0.9
A
else
disp('Provide the A generator matrix (on the form [ x x .. ; x ...], or give the name of a predefined matrix in the Matlab workspace)')
A = input('A = ')
end
// The generator matrix A is transposed to a matrix B
B = A';
//define the initial condition p(0) (a row vector)
p = input('Define initial condition, p (row) vector (on the form [ x x .. ]) ');
// The row vector p is transposed to a column vector x0
x0 = p';
//Solve the differential equation
[t,x] = ode45(#markovprocessfunc,[0,tend],x0);
// Plot the results
plot(t,x)
grid on;
xlabel('Time')
ylabel('Probabilities')
m=length(A);
if m==2
legend('s1', 's2')
end
if m==3
legend('s1', 's2','s3')
end
if m==4
legend('s1', 's2','s3', 's4')
end
if m==5
legend('s1', 's2','s3', 's4', 's5')
end
if m==6
legend('s1', 's2','s3', 's4', 's5', 's6')
end
if m==7
legend('s1', 's2','s3', 's4', 's5', 's6', 's7')
end
if m==8
legend('s1', 's2','s3', 's4', 's5', 's6', 's7', 's8')
end
title('Markov Process')
m = size(A,1);
aa = A'; //transpose the A matrix
aa(m,:) = 1; //add ones to the last column (can be any column), i.e. the sum all p(i) must equal 1
b = zeros(m,1); //create b-vector with zeros
b(m)=1; //add a 1 to the same row as where you added 1:s to the column of A
c = aa\b; //solve the linear equation system
stationary_solution_vector = c' //transpose the solution vector back to a row vector
e_raised_to_A_times_1000 = expm(A*1000)
eigenvalues_of_A = eig(A)'
I found out that by replacing the line [t,x] = ode45(#markovprocessfunc,[0,tend],x0); with something like
t = [0 1 2 3]
x = [1 2 3 4]
the script works fine (but obviously I get the wrong result). So how do I convert ode45 to scilab? I think that after I get that done everything will work.
About the crash of mfile2sci() code converter, please do not hesitate to post a bug report # https://bugzilla.scilab.org for your user case. Things can't get better without reporting bugs.
Even without converter's crash, the ode45() instruction is not converted. But it could be (let us put this on our todo list ;-). Indeed, an equivalent of
[t,x] = ode45(#markovprocessfunc,[0,tend],x0);
is
n = 100; // or whatever value you wish
t = linspace(0, tend, n);
x = ode("rkf", x0, t(1), t, markovprocessfunc);

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-')

Optimization of column shifting of large matrices (Circshift, etc.)

I am currently looking for the most efficient way to shift and rearrange large matrices. Essentially, I have data with some parabolic shift that needs to be corrected in order to shift the "signal" to a linear event.
I have currently tried the following solutions and tried timing them. Is there any other method that may prove to be more efficient?
DATA = ones(100000,501);
DATA(10000,251) = 100;
for i=1:250
DATA(10000+i^2-1000:10000+i^2+1000,251-i) = 100;
DATA(10000+i^2-1000:10000+i^2+1000,251+i) = 100;
end
k = abs(-250:1:250).^2;
d = size(DATA,1);
figure(99)
imagesc(DATA)
t_INDEX = timeit(#()fun_INDEX(DATA,k))
t_SNIPPET = timeit(#()fun_SNIPPET(DATA,k))
t_CIRCSHIFT = timeit(#()fun_CIRCSHIFT(DATA,k))
t_INDEX_clean = timeit(#()fun_INDEX_clean(DATA,k))
t_SPARSE = timeit(#()fun_SPARSE(DATA,k))
t_BSXFUN = timeit(#()fun_BSXFUN(DATA,k))
function fun_INDEX(DATA,k)
DATA_1 = zeros(size(DATA));
for i=1:size(DATA,2)
DATA_1(:,i) = DATA([k(i)+1:end 1:k(i)],i);
end
figure(1)
imagesc(DATA_1)
end
function fun_SNIPPET(DATA,k)
kmax = max(k);
DATA_2 = zeros(size(DATA,1)-kmax,size(DATA,2));
for i=1:size(DATA,2)
DATA_2(:,i) = DATA(k(i)+1:end-kmax+k(i),i);
end
figure(2)
imagesc(DATA_2)
end
function fun_CIRCSHIFT(DATA,k)
DATA_3 = zeros(size(DATA));
for i=1:size(DATA,2)
DATA_3(:,i) = circshift(DATA(:,i),-k(i),1);
end
figure(3)
imagesc(DATA_3)
end
function fun_INDEX_clean(DATA,k)
[m, n] = size(DATA);
k = size(DATA,1)-k;
DATA_4 = zeros(m, n);
for i = (1 : n)
DATA_4(:, i) = [DATA((m - k(i) + 1 : m), i); DATA((1 : m - k(i) ), i)];
end
figure(4)
imagesc(DATA_4)
end
function fun_SPARSE(DATA,k)
[m,n] = size(DATA);
k = -k;
S = full(sparse(mod(k,m)+1,1:n,1,m,n));
DATA_5 = ifft(fft(DATA).*fft(S),'symmetric');
figure(5)
imagesc(DATA_5)
end
function fun_BSXFUN(DATA,k)
DATA = DATA';
k = -k;
[m,n] = size(DATA);
idx0 = mod(bsxfun(#plus,n-k(:),1:n)-1,n);
DATA_6 = DATA(bsxfun(#plus,(idx0*m),(1:m)'));
figure(6)
imagesc(DATA_6)
end
Is there any way to decrease computation time for this kind of problem?
Thanks in advance for any tips!
One option would be to use MATLAB's GPU functions, if your workstation has a GPU. Depending on if the entire data fits on the GPU at once, it will start to outperform CPU circshift at 1000 X 1000 matrix size.
The implementation only requires you to copy your data to the GPU with a single statement, and then operate circshift on the newly created you array.
A small discussion on its performance can be found here: https://www.mathworks.com/matlabcentral/answers/274619-circshift-slower-on-gpu . Especially, the last post describes a much faster GPU implementation if you actually don't need to circularly shift, but can get away with zero passing on one side, which might be relevant.

"Variable in a parfor cannot be classified" MATLAB

I am trying to convert my code over to run with parfor, since as it is it takes a long time to run on its own. However I keep getting this error. I have search around on the website and have read people with similar problems, but none of those answers seem to fix my problem. This is my code:
r = 5;
Mu = 12.57e-9;
Nu = 12e6;
I = 1.8;
const = pi*Nu*Mu*r*I;
a = 55;
b = 69;
c = 206;
[m,n,p] = size(Lesion_Visible);
A = zeros(m,n,p);
parpool(2)
syms k
parfor J = 1:m
for I = 1:n
for K = 1:p
if Lesion_Visible(J,I,K) ~= 0
Theta = atand((J-b)/(I-a));
Rho = abs((I-a)/cosd(Theta))*0.05;
Z = abs(c-K)*0.05;
E = vpa(const*int(abs(besselj(0,Rho*k)*exp(-Z*k)*besselj(0,r*k)),0,20),5);
A (J,I,K) = E;
end
end
end
end
I'm trying to calculate the electric field in specific position on an array and matlab give me the error "The variable A in a parfor cannot be classified". I need help. Thanks.
As classification of variables in parfor loop is not permitted, you should try to save the output of each loop in a variable & then save the final output into the desired variable, A in your case!
This should do the job-
parfor J = 1:m
B=zeros(n,p); %create a padding matrix of two dimension
for I = 1:n
C=zeros(p); %create a padding matrix of one dimension
for K = 1:p
if Lesion_Visible(J,I,K) ~= 0
Theta = atand((J-b)./(I-a));
Rho = abs((I-a)./cosd(Theta))*0.05;
Z = abs(c-K).*0.05;
E = vpa(const.*int(abs(besselj(0,Rho.*k).*exp(-Z.*k).*besselj(0,r.*k)),0,20),5);
C(K) = E; %save output of innnermost loop to the padded matrix C
end
end
B(I,:)=C; % save the output to dim1 I of matrix B
end
A(J,:,:)=B; save the output to dim1 J of final matrix A
end
Go through the following for better understanding-
http://www.mathworks.com/help/distcomp/classification-of-variables-in-parfor-loops.html
http://in.mathworks.com/help/distcomp/sliced-variable.html

MATLAB How to vectorize these for loops?

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