我正在阅读Matlab用户的优化工具箱指南.在第1-15页中,提供了一些用于创建索引变量的代码.这是代码:
%Combine variables into one vector
variables = {'I1','I2','HE1','HE2','LE1','LE2','C','BF1',...
'BF2','HPS','MPS','LPS','P1','P2','PP','EP'};
N = length(variables);
% create variables for indexing
for v = 1:N
eval([variables{v},' = ',num2str(v),';']); %?
end
Run Code Online (Sandbox Code Playgroud)
我知道"变量"类是单元格数组.但我无法理解"eval"的功能.要阅读以下代码,它似乎为变量中的元素创建索引,以便元素可以用作操作矩阵或向量的索引号.例如:
lb = zeros(size(variables));
lb([P1,P2,MPS,LPS]) = [2500,3000,271536,100623];
Run Code Online (Sandbox Code Playgroud)
我已经阅读了帮助文档,但仍然无法获得它.所以,任何人都可以更清楚地向我解释.
顺便说一句,用户指南建议避免这种"评估"功能.那么,还有其他方法可以实现上述功能吗?
谢谢大家
完整的计划
% Combine variables into one vector
variables = {'I1','I2','HE1','HE2','LE1','LE2','C','BF1',...
'BF2','HPS','MPS','LPS','P1','P2','PP','EP'};
N = length(variables);
% create variables for indexing
for v = 1:N
eval([variables{v},' = ',num2str(v),';']); %?
end
% Write bound constraints
lb = zeros(size(variables));
lb([P1,P2,MPS,LPS]) = ...
[2500,3000,271536,100623];
ub = Inf(size(variables));
ub([P1,P2,I1,I2,C,LE2]) = ...
[6250,9000,192000,244000,62000,142000];
% Write linear inequality constraints
A = zeros(3,N);
A(1,I1) = 1; A(1,HE1) = -1; b(1) = 132000;
A(2,EP) = -1; A(2,PP) = -1; b(2) = -12000;
A(3,[P1,P2,PP]) = [-1,-1,-1]; b(3) = -24550;
% Write linear equality constraints
Aeq = zeros(8,N); beq = zeros(8,1);
Aeq(1,[LE2,HE2,I2]) = [1,1,-1];
Aeq(2,[LE1,LE2,BF2,LPS]) = [1,1,1,-1];
Aeq(3,[I1,I2,BF1,HPS]) = [1,1,1,-1];
Aeq(4,[C,MPS,LPS,HPS]) = [1,1,1,-1];
Aeq(5,[LE1,HE1,C,I1]) = [1,1,1,-1];
Aeq(6,[HE1,HE2,BF1,BF2,MPS]) = [1,1,1,-1,-1];
Aeq(7,[HE1,LE1,C,P1,I1]) = [1267.8,1251.4,192,3413,-1359.8];
Aeq(8,[HE2,LE2,P2,I2]) = [1267.8,1251.4,3413,-1359.8];
% Write the objectvie
f = zeros(size(variables));
f([HPS PP EP]) = [0.002614 0.0239 0.009825];
% Solve the problem
%print out the results in floating-point fromat in a field 12 characters
%wide, including 2 digits after the decimal point for first data
[x,fval] = linprog(f,A,b,Aeq,beq,lb,ub);
for d = 1:N
fprintf('%12.2f \t %s \n',x(d),variables{d});
end
fval
Run Code Online (Sandbox Code Playgroud)
我们中的一些人讨论了你的问题,我们仍然对这个可怕的怪物在官方文档中的事实感到震惊:)这个例子正在做的是一个淫秽的反模式,这不仅不安全而且效率极低.你的怀疑是正确的,人们几乎不应该使用eval.如果可能,应该在没有eval动态变量名的情况下完成工作.如果不可能,那么应该重构他们所面对的任何代码,以便能够以一种美好,安全,快速和惯用的方式解决它.
这里的问题是建筑本身要求使用eval.这是不好的.很坏.当我在文档中看到这个时,我几乎不相信自己的眼睛.看到这个答案和其中的参考资料,为什么eval应该像瘟疫一样避免.一般来说,eval执行任意字符串会为攻击者提供潜在的入口点,但老实说,大多数用例都无法被外人访问.但是,MATLAB中的即时编译无法优化动态代码中的任何内容.最后,开始使用动态变量名称将导致你从一个eval难以逃脱的兔子洞.
那么,通常的替代方案是什么eval,特别是在动态字段名称方面?细胞,或更重要的是结构.我更喜欢后者.使人们使用结构而不是动态变量名称的主要障碍是,有一种不太广为人知的结构特征,称为字段名称的动态访问.以下两个是相同的:
% static version
mystruct1 = [];
mystruct1.field1 = 3;
% dynamic version
fname = 'field1';
mystruct2 = [];
mystruct2.(fname) = 3;
isequal(mystruct1,mystruct2)
% yes
Run Code Online (Sandbox Code Playgroud)
因此,通常的eval问题解决方案是使用具有动态字段名称的结构.1
在你的情况下,这无疑会导致困难.符号会变得更加麻烦,可以理解.但原则上你可以放弃调用eval,而是设置单个索引结构的字段is:
is = [];
for v = 1:N
% nope eval nope nope nope nope
is.(variables{v}) = v;
end
Run Code Online (Sandbox Code Playgroud)
成本是你以后必须简化一点:
Aeq(6,[is.HE1,is.HE2,is.BF1,is.BF2,is.MPS]) = [1,1,1,-1,-1];
Run Code Online (Sandbox Code Playgroud)
我知道你不愿意这样做,并且建议使用eval这种方式的工具箱可能会为你带来其他惊喜,但我可能会选择这条路线.为了一个人的精神卫生和避免可怕的反模式应该是非常激励.
1这也暗示了从eval兔子洞出来的方法:将你的工作区保存为.mat文件,然后加载dat = load('tmp.mat');:结果将是一个dat你可以按照你需要的方式轻松访问的结构.