I would like to run a Simulink model in a parfor loop on many cores with different data. However, I could not get the sim results when I use parfor whereas I can obtain them while using only for loop.
It simply get [t,u] from workspace1, consider a transfer function n{1}/d{1} and then calculates the EqFracInt to workspace2.
The problematic part of my code is
...
parfor ieq=1:1
assignin('base','t',t);
assignin('base','u',u);
assignin('base','n',n);
assignin('base','d',d);
assignin('base','T_end',T_end);
[simout] = sim('RespSpecFrac', [0 T_end], simset('ReturnWorkspaceOutputs','on'));
PGRs = simout.get('EqFracInt');
end
I could not get the PGRs values. Could you please explain the error to me and how to solve it?
The cause you can't get PGRs values is that is a temporary variable. Since in a parfor loop each iteration is independent, any variable assigned directly inside the loop without indexing is used only in that specific iteration and destroyed.
In order to get the desired values, you need to transform PGRs in either a sliced variable (by indexing it) or in a reduction variable (by, for example, concatenating it). Try to modify the last line of your loop following one of these examples:
PGRs(ieq, :) = simout.get('EqFracInt'); % sliced variable
or
PGRs = [PGRs; simout.get('EqFracInt')]; % reduction variable
The specific implementation will depend on the shape of the expected outputs EqFracInt, of course. You can see more about types of variables inside a parfor loop in the documentation.
Related
I am trying to use a for loop inside of a parfor loop in Matlab.
The for loop is equivalent to the ballode example in here.
Inside the for loop a function ballBouncing is called which is a system of 6 differential equations.
So, what I am trying to do is to use 500 different sets of parameter values for the ODE system and run it, but for each parameter set, a sudden impulse is added, which is handled through the code in 'for' loop.
However, I don't understand how to implement this using a parfor and a for loop as below.
I could run this code by using two for loops but when the outer loop is made to be a parfor it gives the errors,
the PARFOR loop cannot run due to the way variable results is used,
the PARFOR loop cannot run due to the way variable y0 is used and
Valid indices for results are restricted in PARFOR loops
results=NaN(500,100);
x=rand(500,10);
parfor j=1:500
bouncingTimes=[10,50];%at time 10 a sudden impulse is added
refine=2;
tout=0;
yout=y0;%initial conditions of ODE system
paras=x(j,:);%parameter values for the ODE
for i=1:2
tfinal=bouncingTimes(i);
[t,y]=ode45(#(t,y)ballBouncing(t,y,paras),tstart:1:tfinal,y0,options);
nt=length(t);
tout=[tout;t(2:nt)];
yout=[yout;y(2:nt,:)];
y0(1:5)=y(nt,1:5);%updating initial conditions with the impulse
y0(6)=y(nt,6)+paras(j,10);
options = odeset(options,'InitialStep',t(nt)-t(nt-refine),...
'MaxStep',t(nt)-t(1));
tstart =t(nt);
end
numRows=length(yout(:,1));
results(1:numRows,j)=yout(:,1);
end
results;
Can someone help me to implement this using a parfor outer loop.
Fixing the assignment into results is relatively straightforward - what you need to do is ensure you always assign a whole column. Here's how I would do that:
% We will always need the full size of results in dimension 1
numRows = size(results, 1);
parfor j = ...
yout = ...; % variable size
yout(end:numRows, :) = NaN; % Expand if necessary
results(:, j) = yout(1:numRows, 1); % Shrink 'yout' if necessary
end
However, y0 is harder to deal with - the iterations of your parfor loop are not order-independent because of the way you're passing information from one iteration to the next. parfor can only handle loops where the iterations are order-independent.
Just beginning with parallel stuff...
I have a code that boils down to filling the columns of a matrix A (which is preallocated with NaNs) with an array of variable length:
A = nan(100);
for ii=1:100
hmy = randi([1,100]); %lenght of the array
A(1:hmy,ii) = rand(hmy,1); %array
end
Simply transforming the for in a parfor does not even run
parfor ii=1:100
hmy = randi([1,100]); %how many not NaN values to put in
A(1:hmy,ii) = rand(hmy,1);
end
because the parfor does not like the indexing:
MATLAB runs loops in parfor functions by dividing the loop iterations
into groups, and then sending them to MATLAB workers where they run in
parallel. For MATLAB to do this in a repeatable, reliable manner, it
must be able to classify all the variables used in the loop. The code
uses the indicated variable in a way that is incompatible with
classification.
I thought that this was due to the indexing on the first dimension and tried a workaround that did not work (same error message as before):
parfor ii=1:100
hmy = randi([1,100]);
tmp = [rand(hmy,1); NaN(size(A,1)-hmy,1)];
A(:,ii) = tmp;
end
How can I index A in order to store the array?
You cant partially change the row or column data in A. You have to do either a full row or full column inside parfor. Here is the updated code.
A = nan(100);
parfor ii=1:100
hmy = randi([1,100]); %lenght of the array
temp = nan(1,100);
temp(1:hmy) = rand(hmy,1); %array
A(:,ii) = temp; %updating full row of iith column
end
First of all, the output variable (A in this case) will be a sliced variable in case of parfor. Which means this variable will be sliced in different part for parallel calculation. The form of indexing in the sliced variable should be same for all incident. Here, you are creating a random number(hmy) and using (1:hmy) as a index which is changing every now and then. That's why your output variable can't be sliced and you have the error.
If you try with a fixed hmy, then it will be alright.
We're developing an application which is processing medical images of an eye retina.
Very often the straight iterating through the pixel indices is used. And even when the size of images is fixed to 1024*768 pixels it may be a CPU-consuming operation e.g. to assign certain values to binarized pixels we need.
lowlayers2 = zeros(img_y_size, img_x_size);
for i=1:numel(lowlayers)
y = rem(lowlayers(i),img_y_size);
x = fix(lowlayers(i)/img_y_size)+1;
lowlayers2(y,x) = 1;
end;
When trying to use parfor in a simple loop above the debugger types that all variables in the loop must be presented as sliced ones. I guess it's in order to divide iterations more primitively inside the loop.
How can I modify the loop or variable to be able to use parfor? May every variable be presented as a sliced variable (mean more multidim matrix with 2 or 3 dimentions)?
a sliced variable is a variable that has a reference out of parfor loop and each of its element only accessed by a single worker (in parfor paralle workers)
sometime matlab doesnt recognize a variable in parfor loop as "sliced variable"
so you could use a temporary variable and collect results after the parfor loop,
lowlayers2 = zeros(img_y_size, img_x_size);
parfor i=1:numel(lowlayers)
y = rem(lowlayers(i),img_y_size);
x = fix(lowlayers(i)/img_y_size)+1;
t(i)= sub2ind(size(lowlayers2),y,x);
end
lowlayers2(t)=1;
NOTE 1: It is better to vectorise code in the older versions because loops didn't use to be as good as they are now in R2017 referring to (this).
I want to paralyze my forloop in Matlab.I use parfor function for that, but I get error because the way I used variable inside of the loop. would someone help me to fix that. I'm new in matlab.
Here is part of my try.
Here is part of problematic part:
CV_err=zeros(length(gamma), (Num_Tasks + 1));
parfor k=1:length(gamma)
#block of code
#
CV_err(k,1:Num_Tasks)= sum(In_Fold_Error)./size(In_Fold_Error,1);
CV_err(k,Lambda_location)= Lambda;
CV_err(k,(Num_Tasks +2))= sum(CV_err(k,1:Num_Tasks))/Num_Tasks;
end
Error: parfor loop can not run due to way CV_err is used.
CV_err is indexed in different ways, potentially causing dependencies
Seems that valid indices are restricted in parfor .
While your variable is sliced, you only access the k-th row in the k-th iteration, the code analyser does not understand it. Give a little help to matlab, first put all data into a vector and then write all at once to the sliced variable.
CV_err=zeros(length(gamma), (Num_Tasks + 2));
parfor k=1:length(gamma)
%block of code
%
temp=zeros(1,(Num_Tasks + 2));
temp(1,1:Num_Tasks)= sum(In_Fold_Error)./size(In_Fold_Error,1);
temp(1,Lambda_location)= Lambda;
temp(1,(Num_Tasks +2))= sum(temp(1,1:Num_Tasks))/Num_Tasks;
CV_err(k,:)=temp;
end
The limitation is explained in the documentation:
Form of Indexing. Within the list of indices for a sliced variable, one of these indices is of the form i, i+k, i-k, k+i, or k-i, where i is the loop variable and k is a constant or a simple (nonindexed) broadcast variable; and every other index is a scalar constant, a simple broadcast variable, a nested for-loop index, colon, or end.
Source
To fix pre-allocation, don't pre-allocate. You're just telling to MATLAB how it should split the work among workers; parfor doesn't like that.
The answer is: don't make loops change common variables, write your results separately, grow cell arrays instead of matrices, i.e.
clear CV_err;
parfor k=1:length(gamma)
%// here your other code
this_CV_err = zeros(Num_Tasks+2,1);
this_CV_err(1:Num_Tasks) = sum(In_Fold_Error)./size(In_Fold_Error,1);
this_CV_err(Lambda_location) = Lambda;
this_CV_err(Num_Tasks+2) = mean(this_CV_err(1:Num_Tasks));
CV_err{k} = this_CV_err;
end;
Why can't I use the parfor in this piece of code?
parfor i=1:r
for j=1:N/r
xr(j + (N/r) * (i-1)) = x(i + r * (j-1));
end
end
This is the error:
Error: The variable xr in a parfor cannot be classified.
See Parallel for Loops in MATLAB, "Overview".
The issue here is that of improper indexing of the sliced array. parfor loops are run asynchronously, meaning the order in which each iteration is executed is random. From the documentation:
MATLAB workers evaluate iterations in no particular order, and independently of each other. Because each iteration is independent, there is no guarantee that the iterations are synchronized in any way, nor is there any need for this.
You can easily verify the above statement by typing the following in the command line:
parfor i=1:100
i
end
You'll see that the ordering is arbitrary. Hence if you split a parallel job between different workers, one worker has no way of telling if a different iteration has finished or not. Hence, your variable indexing cannot depend on past/future values of the iterator.
Let me demonstrate this with a simple example. Consider the Fibonacci series 1,1,2,3,5,8,.... You can generate the first 10 terms of the series easily (in a naïve for loop) as:
f=zeros(1,10);
f(1:2)=1;
for i=3:10
f(i)=f(i-1)+f(i-2);
end
Now let's do the same with a parfor loop.
f=zeros(1,10);
f(1:2)=1;
parfor i=3:10
f(i)=f(i-1)+f(i-2);
end
??? Error: The variable f in a parfor cannot be classified.
See Parallel for Loops in MATLAB, "Overview"
But why does this give an error?
I've shown that iterations are executed in an arbitrary order. So let's say that a worker gets the loop index i=7 and the expression f(i)=f(i-1)+f(i-2);. It is now supposed to execute the expression and return the results to the master node. Now has iteration i=6 finished? Is the value stored in f(6) reliable? What about f(5)? Do you see what I'm getting at? Supposing f(5) and f(6) are not done, then you'll incorrectly calculate that the 7th term in the Fibonnaci series is 0!
Since MATLAB has no way of telling if your calculation can be guaranteed to run correctly and reproduce the same result each time, such ambiguous assignments are explicitly disallowed.