matlab - 在 matlab 中创建索引变量

标签 matlab indexing

我正在阅读优化工具箱的 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

我知道“变量”的类是元胞数组。但我无法清楚地理解“eval”的功能。阅读下面的代码,它似乎为变量中的元素创建了索引,以便元素可以用作操作矩阵或向量的索引号。例如:

lb = zeros(size(variables));
lb([P1,P2,MPS,LPS]) = [2500,3000,271536,100623];

我已经阅读了帮助文档,但仍然无法获取。所以,任何人都可以为我解释得更清楚。

顺便说一句,用户指南建议避免使用此“eval”函数。那么,有没有其他方法可以实现上述功能呢?

谢谢大家

完整的程序

% 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

最佳答案

我们中的一些人讨论了您的问题,但我们仍然对官方文档中存在这个可怕的怪物这一事实感到震惊:)该示例的作用是一种淫秽的反模式,这不仅不安全,而且效率极低。您的怀疑是正确的,人们几乎不应该使用eval。如果可能的话,应该在没有eval和动态变量名称的情况下完成这项工作。当不可能时,人们应该重构他们所面临的任何代码,以便能够以一种良好、安全、快速和惯用的方式解决它。

这里的问题是构造本身要求使用eval。这不好。很坏。太糟糕了,当我在文档中看到这一点时,我简直不敢相信自己的眼睛。请参阅this answer and references therein为什么eval应该像瘟疫一样被避免。一般来说,eval 执行任意字符串,这为攻击者提供了潜在的入口点,但老实说,大多数用例对外人来说是无法访问的。但是,MATLAB 中的即时编译无法优化动态代码内的任何内容。最后,开始使用动态变量名称将导致您陷入难以逃脱的 eval 兔子洞。

那么,eval 的常用替代方案是什么,尤其是在动态字段名称方面?细胞,或更重要的是,结构。我更喜欢后者。让人们使用结构体而不是动态变量名的主要障碍是,结构体有一个不太广为人知的功能,即dynamic access of field names。 。以下两个是相同的:

% static version
mystruct1 = [];
mystruct1.field1 = 3;

% dynamic version
fname = 'field1';
mystruct2 = [];
mystruct2.(fname) = 3;

isequal(mystruct1,mystruct2)
% yes

因此,eval 问题的通常解决方案是使用具有动态字段名称的结构。1

就您而言,这无疑会导致困难。可以理解的是,符号会变得更加麻烦。但原则上,您可以放弃对 eval 的调用,而是设置单个索引结构 is 的字段:

is = [];
for v = 1:N
   % nope eval nope nope nope nope
   is.(variables{v}) = v;
end

代价是你以后必须变得不那么简洁:

Aeq(6,[is.HE1,is.HE2,is.BF1,is.BF2,is.MPS]) = [1,1,1,-1,-1];

我知道您不愿意这样做,并且建议以这种方式使用 eval 的工具箱可能会给您带来其他惊喜,但我可能会采取这种方式。保持心理健康并避免可怕的反模式应该具有高度的激励作用。

 

1这也意味着有一种摆脱 eval 兔子洞的方法:将工作区保存为 .mat 文件,然后加载使用 dat = load('tmp.mat');:结果将是一个 struct dat,您可以按照您需要的方式轻松访问它。

关于matlab - 在 matlab 中创建索引变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39959835/

相关文章:

matlab - 在 MATLAB 中创建一个 1's and 0' s 矩阵,其中 1 的数量有限制

function - 为什么我不能在 MATLAB 匿名函数中定义变量?

database - 索引如何加快搜索速度?

sql-server - SQL Server 自动索引调整功能是否会删除唯一索引?

mysql - 具有数百万行的数据库的有效索引

matlab - Matlab 中的范围界定是如何工作的?

matlab - 使用 Matlab 进行肿瘤分割的模糊 C 均值

arrays - 我想要将一组色 block 叠加到图像上并想要控制它们的颜色范围?

c++ - 如果大小等于特定数字,如何找到字符串 vector 的单个索引的大小并打印索引?

mongodb - mongodb中索引是如何管理的