Problem with cell array indexing when using parfor

Dear all,
I'm try to do certain calculation that automatically generates a certain (large) matrix for each iteration and calculates the Eigenvalue for it. To speed up the lengthy calculation, I am using parfor. Unfortunately, the code gives me "The variable IM in a parfor cannot be classified" error. It seems like looking at M-lint tells me that IM, B1, B2, and B3 are bad variables. These are all cell arrays that were created so that different cell can be assigned independently by each iteration, preventing interaction between other iterations.
I do not understand the problem here. Could someone help me? Thank you.
The code is shown below. IM, IIM, B1, B2, and B3 are already defined elsewhere as empty cell arrays. variables l and n depends on the input of the user but is defined prior to the code.
parfor cycle = 1:n
IM{cycle, 1} = IIM
B1{cycle, 1} = setdiff(1:(2*l+1)^3, ((2*l+1)^3+1)/2).'
if Impurity == 1
o(cycle) = randi([0, 1], 1);
if o(cycle) == 0
B2{cycle, 1} = 0;
else
p(cycle) = randi(length(B1{cycle, 1}),1);
IM{cycle, 1}(:, B1{cycle, 1}(p(cycle), 1)) = 0;
IM{cycle, 1}(B1{cycle, 1}(p(cycle), 1), :) = IM{B1{p(cycle),1}, :}*1;
IM{cycle, 1}(B1{cycle, 1}(p(cycle), 1), B1{cycle, 1}(p(cycle), 1)) = -str2double(answer3(2,1));
B2{cycle, 1} = B1{cycle, 1}(p(cycle), 1);
end
end
B3{cycle, 1} = zeros(m,1);
q(cycle) = 1;
while length(B1{cycle, 1}) > o(cycle) + str2double(answer2(1,1)) - 1
r(cycle) = randi(length(B1{cycle, 1}),1);
if B1{r(cycle), 1} ~= B2{cycle, 1}
B3{cycle, 1}(q(cycle),1) = B1{cycle, 1}(r(cycle), 1);
B1{r(cycle), 1} = [];
IM{:, B3{q(cycle), 1}} = 0;
IM{B3{q(cycle), 1}, :} = 0;
q(cycle) = q(cycle) + 1;
end
end
B1{cycle, 1}(B1{cycle, 1}==B2{cycle, 1}) = [];
for q = 1:length(B1{cycle, 1})
IM{B1{cycle, 1}(q(cycle), 1), B1{cycle, 1}(q(cycle), 1)} = 0;
IM{B1{cycle, 1}(q(cycle), 1), B1{cycle, 1}(q(cycle), 1)} = -(str2double(answer3(1,1)) + str2double(answer3(2,1)) + sum(IM{cycle, 1}(:, B1{q(cycle),1}))) + str2double(answer3(6,1))*sum(IM{cycle, 1}(:, B1{q(cycle),1}));
end
IM{cycle, 1}(((2*l+1)^3+1)/2, ((2*l+1)^3+1)/2) = 0;
IM{cycle, 1}(((2*l+1)^3+1)/2, ((2*l+1)^3+1)/2) = -(str2double(answer3(1,1)) + str2double(answer3(2,1)) + sum(IM{cycle, 1}(:, ((2*l+1)^3+1)/2)) + str2double(answer3(6,1))*sum(IM{cycle, 1}(:, ((2*l+1)^3+1)/2)))
I = eye((2*l+1)^3);
C = zeros((2*l+1)^3, 1);
C(((2*l+1)^3+1)/2) = 1;
[P{cycle,1},D{cycle,1}] = eig(IM{cycle,1})
V{cycle,1} = (P{cycle,1}*expm((D{cycle,1})*t)*(P{cycle,1})^-1)*C
S1(cycle) = sum(V{cycle,1}(B1{q(cycle),1},1)) + V{cycle,1}(((2*l+1)^3+1)/2,1);
end

 Accepted Answer

On first glance, here are some issues. Rewrite the code to prevent accessing cells in dependent or ambiguous manners.
Example 1) Use the same indexing style for all variables linked to the parfor index. For instance:
IM = cell(1, 100);
parfor j = 1:numel(IM)
IM{j} = zeros(1, 10);%You're access IM via IM{j}. Must be same in code.
for k = 1:10
IM{j}(k) = k; %OKAY, same indexing style as IM{j}
IM{1, j}(k) = k; %NOT OKAY. Different indexing IM{1, j} even
%though it's correct without parfor.
end
end
Example 2) Don't modify a sliced variable with different index as the parfor counter, since MATLAB cannot confirm if these are truly independent.
B1 = cell(1, 100);
parfor j = 1:numel(B1)
r(j) = randi(numel(B1), 1);
B1{r(j)} = j; %NOT OKAY. Index to sliced variable B1 differs from
%parfor loop counter variable j. Conflict arises when
%multiple jobs tries to write to same cell in B1.
end

5 Comments

Thank you for your help.
I think I can find some ways to solve the issue for the first example, but I don't know what to do about the second. For example, if I remove the r(j) and replace it with just r, then I believe this is going to conflict with other workers while performing parfor.
Yes you're right. Changing r(j), which is going to be a sliced variable, to just r will still cause write-access conflict issues to B1, which seems like a sliced variable too. Does B1 have to be accessed randomly via randi? See comments below.
parfor cycle = 1:n
IM{cycle, 1} = IIM
B1{cycle, 1} = setdiff(1:(2*l+1)^3, ((2*l+1)^3+1)/2).'
...
while length(B1{cycle, 1}) > o(cycle) + str2double(answer2(1,1)) - 1
r(cycle) = randi(length(B1{cycle, 1}),1);
if B1{r(cycle), 1} ~= B2{cycle, 1} <=== HERE!!!
%NOTE: B1 was referred to B1{cycle, 1} and also B1{r(cycle), 1).
%If B1 is a sliced variable, then you can't do the 2nd term.
%Is there a reason you have to access B1{r(cycle), 1) and not
%B1{cycle, 1}? Or did you mean B1{cycle, 1}(r(cycle), 1)?
...
end
end
...
end
Hayao
Hayao on 23 May 2018
Edited: Hayao on 23 May 2018
Yes, it has be accessed randomly via randi.
Basically, in each cycle, I have some full (2*l+1)^3 by (2*l+1)^3 (l is an input value) matrix IM (which is initially IIM), and the script adds one inhomogeneous point, and then erases certain number of rows-columns into zeros randomly.
B1 is there as a initial matrix to specify what rows-columns in IM is available to alter, that is, all rows-columns except that one in the center of IM. B2 specifies what row-column in IM is going to have certain inhomogeneous point, and B3 specifies what rows-columns in IM is going to be changed into zeros. The elements of B2 and B3 is selected randomly from B1, and that specific element of B1 is to be erased in the case of B3 so that same element won't be chosen again.
So yes, it has to be accessed randomly.
Your comment in the code is right. I meant B1{cycle, 1}(r(cycle), 1).
Interesting situation here... Did it work? If not, does this even work for a regular for loop?
There seems to be a lot of work needed to remove the typos and ensure each cycle is truly independent of each other.
To help, anytime you see the cycle parfor loop counter variable, check to see if the variable that uses cycle as an index is a sliced variable or a broadcast variable as intended. I see a lot of use of cycle...
I did find another potential error:
q(cycle) = 1;
...
for q = 1:length(B1{cycle, 1}) %HERE! q was a sliced variable, but now it's a counter variable. q(cycle) won't make sense.
IM{B1{cycle, 1}(q(cycle), 1), B1{cycle, 1}(q(cycle), 1)} = 0;
IM{B1{cycle, 1}(q(cycle), 1), B1{cycle, 1}(q(cycle), 1)} = -(str2double(answer3(1,1)) + str2double(answer3(2,1)) + sum(IM{cycle, 1}(:, B1{q(cycle),1}))) + str2double(answer3(6,1))*sum(IM{cycle, 1}(:, B1{q(cycle),1}));
end
Also, try to avoid having B1 (a sliced variable) storing another sliced variable inside. I feel like this is a fairly complex code structure...
B1{cycle, 1}(r(cycle), 1)
B1 = sliced variable itself
B1{cycle, 1} = sliced variable stored within a cell of B1?
r = sliced variable?
So are you trying to modify a sliced variable inside a sliced variable randomly,
and store this random variable in another sliced variable?
I'm having difficulty classifying which variables are sliced or broadcast or slices of sliced variables, which is probably the error Matlab is trying to tell you "Cannot classify variable IM".
Anyways, hope this helps!
Thank you,
Actually, you are right. I should've tried normal "for" loop before testing parfor. I initially did not have (cycle) variables because I first made normal for-loop script. Seeing that the script works, but way too slow for cases with large matrix, I decided to use parfor.
Of course parfor didn't work at first because of write-access conflict issues. That is when I attempted changing the code using cell arrays with (cycle) to prevent the issue and then the "classify variable" error came up.
Thank you for your consistent help and being patient with me. I'll try rewriting the script in a little more organized manner with what you said in mind. I'll be back with a new question if problem persists with the reorganized new code.

Sign in to comment.

More Answers (0)

Categories

Asked:

on 21 May 2018

Commented:

on 23 May 2018

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!