Using the 'eval" function in parfor

Greetings,
I am writing a piece of code that composes and evaluates logical expressions for my research. It picks one of the 26 minimally functionally complete operator sets, chooses the number of variables and then composes expressions based on those criteria.
I have worked on this problem for some time now and I have reluctantly used Matlab's 'eval' command to evaluate these logical expressions. Although I do have it working for the "in series" case, I have considerable difficulty expanding it to the "parallel" case.
I have provided my script and the necessary functions below. I have also commented the script so that (hopefully) you may follow along. As you will see, my difficulties arise in the following line:
ExpResult(1+jj,k) = eval(Syntax{k});
I have read quite a bit about the eval function and its limitations as well as the considerable disadvantages of using it while developing dynamic variables. I still feel that all things considered this particular methodology for this particular problem was still necessary. However, I could be incorrect in that assessment. At this point, my objective is to get a working version of this script and then modify. If you could assist in that effort, I would be very thankful.
The script is as follows:
% This script stochastically evaluates propositional formulas of arity-2
% It also evaluates based on a certain set of atoms.
% In addition, this script employs T and F as constants which is
% different than the previous versions.
clc; % Clear output screen
AtomNum = 5; % Number of variables used
AtomMax = 5; % Maximum number of variables (for later)
LL = 100; % Number of evaluations before save
syms G; % For rest of code
N = 100; % Number of iterations to run
R(1:N) = 0; % Initialize Random number dimensions
% Create generalized atoms instead of p, q, r, etc...
for j = 1:AtomMax
for k=1:N
Atom{j,k} = strcat('p(', num2str(j),',',num2str(k),')');
end
end
% Create CDFs
RV1(1,1:N) = rand(1,N); % Create an array of random variables to use
RV1(2,1:N) = RV1(1,1:N) + rand(1,N);
RV1(1,1:N) = RV1(1,1:N)./RV1(2,1:N);
RV1(2,1:N) = RV1(2,1:N)./RV1(2,1:N);
RV2(1,1:N) = rand(1,N); % Create an array of random variables to use
RV2(2,1:N) = RV2(1,1:N) + rand(1,N);
RV2(3,1:N) = RV2(2,1:N) + rand(1,N);
RV2(1,1:N) = RV2(1,1:N) ./RV2(3,1:N);
RV2(2,1:N) = RV2(2,1:N) ./RV2(3,1:N);
RV2(3,1:N) = RV2(3,1:N) ./RV2(3,1:N);
RV3(1,1:N) = zeros(1,N);
for j=2:AtomMax+1
RV3(j,1:N) = RV3(j-1,1:N) + rand(1,N);
end
for j=1:AtomMax+1
RV3(j,1:N) = RV3(j,1:N)./RV3(AtomMax+1,1:N);
end
% Initialize string variables
for j=1:N
Constant{j} = '';
Q{j} = '';
BString{j} = '';
str1{j} = '';
end
p(1:AtomMax,1:N) = zeros(AtomMax,N);
ExpResult(1:2^AtomMax,1:N) = 0;
% Distribute computations over many processors.
% 1) Create well-formed propositional formulas
% 2) evaluate formulas
% 3) store results
parfor k = 1:N
Syntax{k} = 'Z'; % Seed for all propositional formulas is a nondescript atom
VarCnt(k) = 1; % Number of variables within a formula are counted
W(k) = randi([0, 2^52]); % To ensure longer formulas are more included
W(k) = log(W(k))/log(2);
OperNum(k) = 1+ floor(W(k));
L(k) = randi([1,26]); % Randomly select which language to use
% There are 26 minimally functionally complete languages. Choose
% which one to use. Must be coded in this way.
switch L(k)
case 1 % {NAND}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
Syntax{k} = regexprep(Syntax{k},'Z','NAND(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
case 2 % {NOR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
Syntax{k} = regexprep(Syntax{k},'Z','NOR(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
case 3 % {NOT, AND}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand; % <- shows up as [0,0,0,...0] in workspace
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','not(Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','and(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
end
case 4 % {NOT, OR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','not(Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','or(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
end
case 5 % {NLA, LA} Eigenanti
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','NLA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','LA(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 6 % {NRA, RA} Eigen Anti
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','NRA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','RA(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 7 % {NLA, RA} Eigen Reverse Bit Flip
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','NLA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','RA(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 8 % {NRA, LA} Eigen Reverse Bit Flip
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','NRA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','LA(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 9 % {LA, XOR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','LA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','xor(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 10 % {RA, XOR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','RA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','xor(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 11 % {NLA, NXOR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','NLA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NXOR(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 12 % {NRA, NXOR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','NRA(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NXOR(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 13 % {NOT,RA}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','not(Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','RA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
end
case 14 % {NOT,LA}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','not(Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','LA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
end
case 15 % {NOT,NRA}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','not(Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NRA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
end
case 16 % {NOT,NLA}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','not(Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NLA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
end
case 17 % {NLA, T}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
Syntax{k} = regexprep(Syntax{k},'Z','NLA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
case 18 % {NRA, T}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
Syntax{k} = regexprep(Syntax{k},'Z','NRA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
case 19 % {LA, F}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
Syntax{k} = regexprep(Syntax{k},'Z','LA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
case 20 % {RA, F}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
Syntax{k} = regexprep(Syntax{k},'Z','RA(Z,Z)', R(k));
VarCnt(k) = VarCnt(k) + 1;
end
case 21 % {AND, NXOR, F}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','and(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NXOR(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 22 % {OR, XOR, T}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','or(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','xor(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 23 % {AND, XOR, NXOR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV2(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','and(Z,Z)', R(k));
elseif r <= RV2(2,k)
Syntax{k} = regexprep(Syntax{k},'Z','xor(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NXOR(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 24 % {OR, XOR, NXOR}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV2(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','or(Z,Z)', R(k));
elseif r <= RV2(2,k)
Syntax{k} = regexprep(Syntax{k},'Z','xor(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NXOR(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 25 % {AND, XOR, T}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','and(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','xor(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
case 26 % {OR, NXOR, F}
for jj = 1:OperNum(k)
R(k) = randi([1, VarCnt(k)]);
r = rand;
if r <= RV1(1,k)
Syntax{k} = regexprep(Syntax{k},'Z','or(Z,Z)', R(k));
else
Syntax{k} = regexprep(Syntax{k},'Z','NXOR(Z,Z)', R(k));
end
VarCnt(k) = VarCnt(k) + 1;
end
end
% For those languages which have TRUE or FALSE constants, we have an
% additional step to consider
if (L(k) >= 17 && L(k) <= 22) || L(k) == 25 || L(k) == 26
if L(k) == 17 || L(k) == 18 || L(k) == 22 || L(k) == 25
% Add atom for TRUE
Constant{k} = '1';
else
% Add atom for FALSE
Constant{k} = '0';
end
% Select which atom index to assign to each nondescript atom
for jj = 1:VarCnt(k)
for m = 1:AtomNum
r = rand;
if r >= RV3(m,k) && r < RV3(m+1,k)
Syntax{k} = regexprep(Syntax{k},'Z',Atom{m,k}, randi([1, VarCnt(k)-jj+1]));
end
end
end
Syntax{k} = regexprep(Syntax{k},'Z',Constant{k});
else
% Select which atom index to assign to each nondescript atom
for jj = 1:VarCnt(k)
for m = 1:AtomNum
r = rand;
if r >= RV3(m,k) && r < RV3(m+1,k)
Syntax{k} = regexprep(Syntax{k},'Z',Atom{m,k},randi([1, VarCnt(k)-jj+1]));
end
end
end
Syntax{k} = regexprep(Syntax{k},'Z',Atom{AtomNum,k});
end
% Just like in a truth table with multiple variables so too must we
% set up our variables to do the same thing.
for jj = 0:2^AtomNum-1
BString{k} = dec2bin(jj);
for n = 1:length(dec2bin(2^(AtomNum)-1))-length(dec2bin(jj))
BString{k} = strcat('0',BString{k});
end
p(:,k) = str2num(BString{k} (:));
% Up until this point everything works as it should. Each 'Syntax'
% is ready to be evaluated. The problem is actually evaluating it.
% Substitute 'p(*,k)' values w/actual values
ExpResult(1+jj,k) = eval(Syntax{k}); % <- This line is the issue
% Q = strcat(Q,num2str(ExpResult(1+j,1)));
end
% The rest of the routine is here. I left it out since it is not
% necessaey
end
Also, the necessary functions are below. They are the remaining Boolean functions of arity 2 which are not standard Matlab functions:
function [V] = NOR(p,q)
V = not(or(p,q));
end
function [V] = NAND(p,q)
V = not(and(p,q));
end
function [V] = LA(p,q)
V = or(not(xor(p,q)),not(p));
end
function [V] = NLA(p,q)
V = and(xor(p,q),p);
end
function [V] = NRA(p,q)
V = and(xor(p,q),not(p));
end
function [V] = RA(p,q)
V = or(not(xor(p,q)),p);
end
function [V] = NXOR(p,q)
V = not(xor(p,q));
end

12 Comments

Could you tell us exactly what isn't working? Your code appears very readable, but it's difficult for us to understand what might need to be tested or if there are environment-specific problems without knowing the details of the error you're seeing.
Absolutely! The problem is at the very end of the script, namely the line:
ExpResult(1+jj,k) = eval(Syntax{k});
I am getting the error message:
Error: The variable ExpResult in a parfor cannot be classified.
However, this line has two issues. That is the first one. The second one involves the actual eval function. If I substitute
ExpResult(1+jj,k) = eval(Syntax{k});
with, say
D = eval(Syntax{k});
then I get the error:
Transparency violation error.
Referencing this in online forums and MathWorks documentation as at this website indicates that the eval function is having difficulty discerning my variables. However, my variables (specifically the Atom variable) is assigned to be processed in parallel and is assigned a value throughout the parfor loop.
Hopefully, this helps in providing a strategy. I will supply any further details if/when necessary.
Thank you very much for taking a look at this.
Can you try one thing before I dig in? Try making a sub-function which does the following
function [D] = commitEval(Syntax)
D = eval(Syntax);
end
Then replace your eval code with the above?
D = commitVeal(Syntax{k});
and see if it works? This might fix the transparency issue; the classification issue is likely because of the double index. Try doing that in two steps.
jgg,
Thank you for your suggestion. Unfortunately, it does not seem to work. I receive the following error:
Error using commitEval (line 2)
Undefined function 'p' for input arguments of type 'double'.
Error in StochasticSyntaxEval_Arity2_WithConstants_Gen_6PlusPRL (line 65)
parfor k = 1:N
I commented out this lines 375 to 392 and worked my way through the variables. I think Matlab is having difficulty with this piece and is guessing that the error is with the 'p' variable.
I also tried the following line to see if it would make a difference, however it did not. I received the same error message:
D{k} = commitEval(Syntax{k});
Looking forward to any further suggestions you may have.
Many thanks again!
After looking at it some more today, it seems as if I need to "slice" my 'ExpResult' variable for the parfor loop.
ExpResult(1+jj,k) = eval(Syntax{k});
That seems to be the real first problem. The second problem deals then with the 'eval' function in that Matlab cautions that the 'eval' function may not access the correct workspace, or:
Explanation
MATLAB runs parfor loops on multiple MATLAB workers that have multiple workspaces. The indicated function might not access the correct workspace; therefore, its usage is invalid.
Suggested Action
Rewrite the application to avoid using this function. For information about what is and is not valid within a parfor loop, see Transparency in the Parallel Computing Toolbox&trade; documentation.
Stephen23
Stephen23 on 25 Jul 2016
Edited: Stephen23 on 25 Jul 2016
Using eval inside a parfor seems very bad choice anyway: usually people use parfor to speed up processing, so why choose to use slow and buggy eval which will drastically slow it down ?? This rather defeats the purpose of using the parfor.
As the documentation states: "Code that calls eval is often less efficient and more difficult to read and debug than code that uses other functions or language constructs."
Thank you for your comment. However, I did address this concern above.
I think you're correct about the slicing; try not using two indices, and instead doing it one variable at a time. That usually fixes it.
I'm confused why the internal function is throwing can error. Can you try entering debug and seeing what syntax{k} looks like and what the eval function is doing, precisely.
We might need to pass in the other variables to the commitEval function that are needed; that seems like it would fix the error you see. I'm just not clear which variables are potentially needed.
For example, like this:
function [D] = commitEval(Syntax, p, q, r, s, t) %etc
D = eval(Syntax);
end
The undefined variable error SEEMS like a good sign; the subfunction is properly parsing the syntax{k} text into a function, but the function takes inputs which are not available inside the subfunction so it crashes. If we provide those inputs, it might be fixed.
I have rewritten the ExpResult piece around lines 57-60 and line 392 to read as follows:
ExpResult = cell(1,N);
for i=1:N
ExpResult{1,N}(1:2^AtomMax,1)=0;
end
and
ExpResult{k,1}(1+jj,1) = eval(Syntax{k});
This eliminates the first issue I had. The remaining issue is the problem with transparency violation. The issue seems to still be in the eval function. Now that I have figured out the first piece I am going to try to see if I can debug and see if I can figure out how to tease out the second issue. Any assistance is greatly appreciated.
Referencing this discussion are my dynamic variables not visible to Matlab?
Made quite some progress I think. Finally found a case where the eval function will not create an error. However not sure how to generalize the code. Made the following modifications:
1) Set the following variables at the top:
AtomNum = 3; % Number of variables used
AtomMax = 3; % Maximum number of variables (for later)
2) Redefine ExpResult
ExpResult = cell(1,N);
for i=1:N
ExpResult{1,N}(1:2^AtomMax,1)=0;
end
3) Strip out the follwing line:
p(:,k) = str2num(BString{k} (:));
4) Set the following static variables (for the Atom = 3 case only):
q1 = str2num(BString{k} (1));
q2 = str2num(BString{k} (2));
q3 = str2num(BString{k} (3));
5) Set the ExpResult line to:
ExpResult{k,1}(1+jj,1) = commitEval(Syntax{k},k,q1,q2,q3);
6) Edit the commitEval function as:
function [D] = commitEval(Syntax,k,q1,q2,q3)
p(1,k) = q1;
p(2,k) = q2;
p(3,k) = q3;
D = eval(Syntax);
end
Now the script will run and I think as it should. However it will only run in this specific '3' case. I have tried to generalize using arrays, etc but it won't take. I am not sure why.
Any ideas? Almost there...
jgg
jgg on 27 Jul 2016
Edited: jgg on 27 Jul 2016
If the error is the same (``undefined variable'') then I'm 99% sure you can fix it by simply passing ALL of the possible inputs to the function being created by eval into the commitEval function.
This may be a bit cumbersome to code as above, so try passing them as a struct instead.
Basically, if I understand what is going is as follows:
1) Your eval command creates a function and a function call together. It's like eval(strcat('sin(','x',')')) for example. This part appears to be working properly.
2) The issue seems to be that the function call created is sin(x) and within the commitEval() function the variable x is unknown.
3) The solution is then to pass all possible x's into your commitEval function. This is troublesome since there are a lot of possible inputs, but I don't think it's impossible.
You also might be able to get creative and pass only the ones you need, but that seems like the solution.
See if that works! If you get an error, let me know what it is precisely.
Your solution to the classification problem is correct, though. Good work.
jgg,
Script is running and finally works. Thank you for your help!

Sign in to comment.

Answers (0)

Tags

Asked:

on 23 Jul 2016

Commented:

on 27 Jul 2016

Community Treasure Hunt

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

Start Hunting!