Error: Unable to classify a variable in the body of the parfor-loop

hello everyone,
I have the following code:
parfor i = 1:2^NJ-1
struct(i,:) = dec2bin(i,NJ);
end
M1 = 0;
for i = 1:NJ
R_M1 = 0;
for j = 1:2^NJ-1
temp = 0;
for p = 1:NJ
temp = temp + str2num(struct(j,p));
end
if temp == i
R_M1 = R_M1 + 1;
final(R_M1,:) = struct(j,NJ:-1:1);
end
M1 = R_M1
end
end
As it is, the code works fine but I want to change the loop after "M1=0" and change the first "For"(for i = 1:NJ) to "Parfor"(parfor i = 1:NJ) but when I do this and run the code I get the following error:
"Error: Unable to classify the variable 'final' in the body of the parfor-loop. For more information, see Parallel for Loops in MATLAB, "Solve Variable Classification Issues in parfor-Loops"."
I think it may be due to the use of "struct(j,NJ:-1:1)" inside the "parfor" loop. Any help would be appreciated.

 Accepted Answer

You cannot do that. You are trying to emit a solution only under conditions, and you want that solution to be the next consecutive after any solution from a lower number iteration. But parfor does not do the iterations in strict increasing order so it cannot know where to write the solution.

You should instead be writing to final(i, :) and setting a variable indexed at i to indicate that final(i, :) is valid. Then after the parfor,

final = final(valid, :); 

to reduce down to the ones that were defined.

5 Comments

Hi Walter, what do you mean when you say "setting a variable indexed at i to indicate that final(i, :) is valid"? Note that "i" is different from "R_M1" and that it is inside an "if".
R_M1 = R_M1 + 1;
final(R_M1,:) = struct(j,NJ:-1:1);
Your variable final appears to be an output variable. It is not used anywhere else inside the for i loop.
The rules for output variables inside parfor loops is that they must be indexed by the parfor variable or a fairly simple expression involving the parfor variable.
Your code involving R_M1 is incrementing R_M1 each time the test succeeds. Your correct code only writes as many rows into final as the number of times that the test succeeds. For example, the 10th iteration might happen to be the 4th time that the test succeeds and you want to write into final(4,:) in that case.
However, when you use parfor, the 10th iteration might be performed first, and certainly could get performed before any of the low-numbered iterations. It could definitely happen that parfor choose to do iterations 9, 10, 11, 12 simultaneously first, leaving iterations 1 to 8 for later. So iteration 10 might happen to be the first one executed that the test was satisfied for. Iteration 10 would have no way of guessing that later iterations 1-8 will satisfy the tests 3 times, so iteration 10 would have no way of guessing that it should output to final(4,:) to leave room for iterations 1-8 writing into final(1:3,:)
The output location for parfor must be computed knowing only the iteration number, without knowing what any other iterations are going to produce.
You have a problem, that each i iteration could produce several output rows. You are going to have to solve that by using cell arrays.
So... you need something like,
parfor i = 1:2^NJ-1
struct(i,:) = dec2bin(i,NJ);
end
final_j = cell(NJ, 1);
parfor i = 1:NJ
j_match = false(1,2^NJ-1);
for j = 1:2^NJ-1
temp = 0;
for p = 1:NJ
temp = temp + str2num(struct(j,p));
end
j_match(j) = temp == i;
end
final_j{i} = fliplr(struct(j_match,:));
end
final = cell2mat(final_j);
Hi Walter, thank you very much, this fix worked for me, I wanted to apply this same logic with another loop I have, which is the following:
for i = 1:NJ
for j = 1:2^NJ-1
temp = 0;
for p = 1:NJ
temp = temp + str2num(struct(j,p));
end
if temp == i
B_ampl(j,:) = struct(j,NJ:-1:1);
end
end
end
When I make the fix I get practically the same as the "final" loop so it gives me the same answer:
B_ampl_j = cell(NJ,1);
parfor i = 1:NJ
ampl_j_match = false(1,2^NJ-1);
for j = 1:2^NJ-1
temp = 0;
for p = 1:NJ
temp = temp + str2num(struct(j,p));
end
ampl_j_match(j) = temp == i;
end
B_ampl_j{i} = fliplr(struct(ampl_j_match,:)); %Representación binaria de Ampl
end
B_ampl = cell2mat(B_ampl_j);
But I am looking for it to give a different order which is the one you see when I have the loop with only "for", this order can be seen by running this for loop. I think it must be because I have not indexed "j" to "B_ampl" properly.
That does not make sense to want that. The entire purpose of your
if temp == i
and your R_M1 logic is to sort the outputs into groups, the first group of which has 1 bit set, the second group has 2 bits set, the third group has 3 bits set, and so on.
Your new top code, the one you say shows the order of output you want, is the same as just doing
fliplr(dec2bin(1:1:2^NJ-1,NJ))
with no loop. There is no point in use parfor for that, or building struct or so on.
you are right, I had done it with the for loop because it was my way of doing it but I will use this simpler way. Thank you for your help!

Sign in to comment.

More Answers (0)

Categories

Community Treasure Hunt

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

Start Hunting!