parfor loop has wrong sliced variables - matlab

Can anyone explain to me, why the following gives an error for u but nor for h
max_X = 100;
max_Y = 100;
h = ones(max_Y,max_X);
u = zeros(max_Y,max_X);
parfor l=1:max_X*max_Y
i = mod(l-1,max_X) + 1;
j = floor((l-1)/max_Y) + 1;
for k=1:9
m = i + floor((k-1)/3) - 1;
n = j + mod(k,-3) + 1;
h_average(k) = sqrt(h(i,j)*h(m,n));
u_average(k) = (u(i,j)*sqrt(h(i,j)) + u(m,n)*sqrt(h(m,n)))/(sqrt(h(i,j)) + sqrt(h(m,n)));
end
end
I can now substitute (i,j) with (l), but even if I try to calculate the related variable, let's call it p, according to (m,n), and write u(p) instead of u(m,n) it gives me an error message.
It only underlines the u(m,n), resp. u(p) but not the h(m,n).
MATLAB says:
Explanation:
For MATLAB to execute parfor loops efficiently, the amount of data sent to the MATLAB workers must be minimal. One of the ways MATLAB achieves this is by restricting the way variables can be indexed in parfor iterations. The indicated variable is indexed in a way that is incompatible with parfor.
Suggested Action
Fix the indexing. For a description of the indexing restrictions, see “Sliced Variables” in the Parallel Computing Toolbox documentation
Any idea, what's wrong here?

The problems with u and h are that they are both being sent as broadcast variables to the PARFOR loop. This is not an error - it's just a warning indicating that more data than might otherwise be necessary is being sent.
The PARFOR loop cannot run because you're indexing but not slicing u_average and h_average. It's not clear what outputs you want from this loop since you're overwriting u_average and h_average each time, therefore the PARFOR loop is pointless.

Related

How to find argmin/best fit/optimize for an overdetermined quadratic system for multiple variables in Matlab

I have 100 equations with 5 variables. Is there a function in Matlab which I can use to find the optimal solution of these equations?
My problem is to find argmin ||(a-ic)^2 + (b-jd)^2 + e - h(i,j)|| over all i, j from -10 to 10. ie.
%% Note: not Matlab code. Just showing the Math.
for i = -10:10
for j = -10:10
(a-ic)^2 + (b-jd)^2 + e = h(i,j)
known: h(i,j) is a 10*10 matrix,and i,j are indexes
expected: the optimal result of a,b,c,d,e
You can try using lsqnonlin as follows.
%% define a helper function in your .m file
function f = fun(x)
a=x(1); b=x(2); c=x(3); d=x(4); e=x(5); % Using variable names from your question. In other situations, be careful when overwriting e.
f=zeros(21*21,0); % size(f) is taken from your question. You should make this a variable for good practice.
for i = -10:10
for j = -10:10
f(10*(i+10+1)+(j+10+1)) = (a-i*c)^2 + (b-j*d)^2 + e - h(i,j); % 10 is taken from your question.
end
end
end
(Aside, why is your h(i,j) taking negative indices??)
In your main function you can simply write
function out=myproblem(x0)
out=lsqnonlin(#fun,x0);
end
In your cmd, you can call with specific initial try such as
myproblem([0,0,0,0,0])
Helper function over anonymous because in my experience helpers get sped up by JIT while anonymous do not. I also opted to reshape in the loops as an opposed to actually call reshape after because I expect reshape to cost significant extra time. Remember that O(1) in fun is not O(1) in lsqnonlin.
(As always, a solution to a nonlinear problem is not guaranteed.)

How do I properly "slice" a 4D matrix in Matlab in a parfor loop?

I am trying to make a portion of my code run faster in MatLab, and I'd like to use parfor. When I try to, I get the following error about one of my variables D_all.
"The PARFOR loop cannot run because of the way D_all is used".
Here is a sample of my code.
M = 161;
N = 24;
P = 161;
parfor n=1:M*N*P
[j,i,k] = ind2sub([N,M,P],n);
r0 = Rw(n,1:3);
R0 = repmat(r0,M*N*P,1);
delta = sqrt(dXnd(i)^2 + dZnd(k)^2);
d = R_prime - R0;
inS = Rw_prime(find(sqrt(sum(d.^2,2))<0.8*delta),:);
if isempty(inS)
D_all(j,i,k,tj) = D_all(j,i,k,tj-1);
else
y0 = r0(2);
inC = inS(find(inS(:,2)==y0),:);
dw = sqrt(sum(d(find(sqrt(sum(d.^2,2))<0.8*delta & d(:,2)==0),:).^2,2));
V_avg = sum(dw.^(-1).*inC(:,4))/sum(dw.^(-1));
D_all(j,i,k,tj) = V_avg;
end
end
I'm not very familiar with parallel computing, and I've looked at the guides online and don't really understand how to apply them to my situation. I guess I need to "slice" D_all but I don't know how to do that.
EDIT: I think I understand that the major problem is that when using D_all I have tj and tj-1.
EDIT 2: I don't show this above, it probably would have been helpful, but I defined D_all(:,:,:,1) = V_1; where V_1 corresponds to a previous time step. I tried making multiple variables V_2, V_3, etc. for each step and replacing D_all(j,i,k,tj-1) with V_1(j,i,k). This still led to the same error I am seeing with D_all.
"Valid indices for D_all are restricted for PARFOR loops"

"Not enough input arguments" when trying to implement simple FOR loop using GPU

I'm trying to calculate the probability that a point (a nxn matrix) uniformly distributed in R^(n^2) exclusively has eigenvalues with negative real part, but I keep getting the following error:
Not enough input arguments.
Error in probability_n (line 4)
for i = 1:num_pts
Here is my code:
N = 10^2;
num_pts = 10^4;
n = 2;
n = n*ones(N,1,'gpuArray');
k = arrayfun(probability_n,n,num_pts);
and the function called is
function k = probability_n(n,num_pts)
k = 0;
for i = 1:num_pts
R = reshape(randsphere(1,n^2,1),n,n);
if all(real(eig(R))<0)
k = k+1;
end
end
end
function P = randsphere(m,n,r)
P = randn(m,n);
s2 = sum(P.^2,2);
P = P.*repmat(r*(gammainc(s2/2,n/2).^(1/n))./sqrt(s2),1,n);
end
Why is this happening? I suspect it is something very simple to do with a syntax error, since this is my first time trying to use my GPU for MATLAB. The GPU is an Nvidia GeForce GTX 580. Thanks.
In general, it's best to test things in vanilla MATLAB (without GPU or parallel processing) if you experience issues to see if the issue is specific to the GPU or parallel processing or whether it's something else. If you do that, you'll see that your code still doesn't work.
This is because you need to pass a function handle for probability_n to arrayfun, as you have it written, probability_n is implicitly called with no input arguments (you don't need the () to invoke a function). You receive the error you do when MATLAB tries to access num_pts from within probability_n and it hasn't been provided.
k = arrayfun(#probability_n, n, num_pts);
Note that passing the scalar num_pts as the third input only works when the first input to arrayfun is a gpuarray object. Otherwise, you'll want to create an anonymous function which passes num_pts to probability_n

Slicing Variable in Parfor loop

Hi I want to run the code as below using PARFOR.
When I try it says that :
Valid indices for 'A_x' and 'A_y' are restricted in PARFOR loops.
Explanation For MATLAB to execute parfor loops efficiently, the
amount of data sent to the MATLAB workers must be minimal. One of the
ways MATLAB achieves this is by restricting the way variables can be
indexed in parfor iterations. The indicated variable is indexed in a
way that is incompatible with parfor. Suggested Action
Fix the indexing. For a description of the indexing restrictions, see “Sliced Variables” in the >Parallel Computing Toolbox documentation:
N=eveninteger;
H=zeros(N);
V=zeros(N);
A_x=zeros(N);
A_y=zeros(N);
parfor i=1:N;
for j=1:N;
if H(i,j)==-2;
t=0.3;
As_x=t*(j-i)/a;
As_y=t*(j-i)/a;
elseif H(i,j)==-3;
t=0.8;
As_x=t*(j-i)/(a*sqrt3);
As_y=t*(j-i)/(a*sqrt3);
elseif i==j
As_x=i;
As_y=i;
else
t=0;
As_x=0;
As_y=0;
end
for p=1:N/2
for q=N/2+1:N
A_x(p,q)=A_x(p,q)+As_x*(V(i,p)*V(j,q));
A_y(p,q)=A_y(p,q)+As_y*(V(i,p)*V(j,q));
end
end
end
end
I could not find solution. Could you offer me a solution.
Thanks in advance.
Erico
It looks like you're trying to perform a "reduction" on A_x and A_y using +. You might be able to work around this by doing something like the following:
parfor i = 1:N
A_x_tmp = zeros(N);
A_y_tmp = zeros(N);
for p=1:N/2
for q=N/2+1:N
A_x_tmp(p,q) = A_x_tmp(p,q) + ...
A_y_tmp(p,q) = A_y_tmp(p,q) + ...
end
end
A_x = A_x + A_x_tmp;
A_y = A_y + A_y_tmp;
end
In that way, PARFOR will understand the reduction operations on A_x and A_y.

Parfor in Matlab

I'm trying to run this loop as a parfor-loop:
correlations = zeros(1,N);
parfor i = 1:(size(timestamps,1)-1)
j = i+1;
dts = timestamps(j) - timestamps(i);
while (dts < T) && (j <= size(timestamps,1))
if dts == 0 && detectors(i) ~= detectors(j)
correlations(1) = correlations(1) + 2;
elseif detectors(i) ~= detectors(j)
dts = floor(dts/binning)+1;
correlations(dts) = correlations(dts) + 1;
end
j = j + 1;
if j <= size(timestamps,1)
dts = timestamps(j) - timestamps(i);
end
end
end
Matlab gives me the following error:
Error: File: correlate_xcorr.m Line: 18 Column: 17
The variable correlations in a parfor cannot be classified.
See Parallel for Loops in MATLAB, "Overview".
Line 18 is the following:
correlations(1) = correlations(1) + 2;
I can not understand why this shouldn'n be possible. The final value of correlations doesn't depend on the order in which the loop is executed, but only dts and detectors. I found similar examples in the documentation which work fine.
Why can't Matlab execute this code and how can I fix it?
I found the following solution and it seems to work. The program looks a litte different, but it has the same shape. This way Matlab is forced to think x/correlations is a reduction variable.
X = zeros(1,5);
parfor i= 1:1000
a = zeros(1,5);
dts = randi(10)-1;
if dts == 0
a(1) = (a(1) + 2);
elseif dts <= 5
a(dts) = a(dts) +1;
end
X = X + a;
end
MATLAB cannot determine that your loop is order independent because of the way you're accessing correlations(1) from multiple iterations of the PARFOR loop. It looks like this value is in some way 'special', it should work to make a 'reduction' variable, i.e. replace correlations(1) with correlations_1 or something.
The next problem you'll encounter is that you are not correctly 'slicing' the remainder of correlations. For MATLAB to analyse a PARFOR loop, it needs to be able to tell that each loop iteration is writing only to its 'slice' of the output variables. In practice, this means that you must index the outputs using literally the loop index.
More about PARFOR variable classification here: http://www.mathworks.com/help/distcomp/advanced-topics.html#bq_of7_-1
EDIT:
If you want correlations to behave strictly as a reduction variable as I believe you imply in your comments, you need to give PARFOR a clue that's what you mean: in particular, you need to add to the whole variable each time you need to. In other words, something more like:
parfor ...
dummyVec = zeros(1, N);
dummyVec(elementToIncrement) = 1;
correlations = correlations + dummyVec;
end
I agree this is non-obvious. See http://blogs.mathworks.com/cleve/2012/11/26/magic-squares-meet-supercomputing/ for more.