2016-10-10 15 views
2

Matlabの最適化ツールボックスのガイドを読んでいます。 1-15ページでは、インデックス作成用の変数を作成するためのコードが提供されています。ここにコードです:matlabでインデックスを作成する変数を作成する

%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 
+2

疑問に思っている人のために、これは*公式のドキュメントにあります(https://www.mathworks.com/help/optim/ug/example-linear-programming.html#bsmt5lz)。 – excaza

+0

はい、そうです。たぶん私は明らかに自分自身を表現していないかもしれません。別の言い方をすれば、 "eval"はセル配列内の要素に値を代入することです。それは正しい?もしそうなら、同じことをする他の方法はありますか? –

+1

@ Rolf_Zhangあなたがここにぶら下がってあなたを残して申し訳ありません:私たちのいくつかはあなたの質問を議論し、公式のドキュメントに存在するこの恐ろしい怪物によって引き起こされたショックに気を散らしました:) –

答えて

6

おかげで、私たちのいくつかは、あなたの質問を議論し、我々は、実際のショックで、まだですこの恐ろしい怪物は公式の文書にあります:)その例が行っているのはであり、それは安全ではないだけでなく非常に非効率的であることを示す猥褻なアンチパターンです。あなたの疑惑は正しいです、誰もほとんどevalを使用するべきではありません。可能であれば、evalと動的変数名なしでジョブを実行する必要があります。それが不可能なときは、彼らが直面しているコードをリファクタリングして、安全で素早く慣用的な方法で解決できるようにしなければなりません。

ここでの問題は、構造そのものがevalの使用を要求していることです。これは悪いです。ひどい。私がドキュメントでこれを見たとき、私は自分の目をほとんど信じなかったのでとても悪いです。なぜevalがペストのように避けられるべきであるかについては、this answer and references thereinを参照してください。一般的に言えば、evalは攻撃者の潜在的なエントリポイントとなる任意の文字列を実行しますが、正にほとんどのユースケースは外部からアクセスできません。しかし、MATLABのジャストインタイムコンパイルでは、動的コード内のものを最適化することはできません。最後に、動的変数名を使用して作業を開始すると、evalウサギの穴がエスケープするのが難しい場所から離れることになります。

evalの代替手段は何ですか、特にダイナミックフィールド名の場合は何ですか?セル、またはもっと重要なのは構造体です。私は後者を好む。人々が動的変数名の代わりに構造体を使用する際の主な障害は、あまりに広く知られているstructの特徴がであることです。次の二つが同一である:

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

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

isequal(mystruct1,mystruct2) 
% yes 

のでeval問題への一般的なソリューションは、ダイナミックなフィールド名と構造体を使用しています。

あなたの場合、これは明らかに困難につながります。表記法は、わずらわしく、分かりやすくなります。しかし、原則的に、あなたはevalへの呼び出しを捨て、代わりに単一のインデックス構造体isのフィールドを設定できます

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

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

コストは、あなたが後で少し少ない簡潔でなければならないということです

あなたはそうしたくないと思っています。この方法でevalを使用することを示唆するツールボックスは、他の驚きをもたらすかもしれませんが、おそらくこのルートをとるでしょう。精神衛生の酒と恐ろしい反パターンを避けることは、意欲的なものでなければなりません。

 

これもアウトevalウサギの穴からの道があることを意味しますdat = load('tmp.mat');でそれをロードし、その後、.matファイルとしてワークスペースを保存するには:結果は、あなたができる構造体datになりますあなたが必要とする方法で容易にアクセスできます。

+0

手順に従うとき、Aeq(6、is.HE1)が行列の次元を超えています。なぜ??? –

+0

@Rolf_Zhang元のコードで 'Aeq(6、HE1)'が見つかりません。あなたはオリジナルでこれらのインデックスのすべての出現を変更してもよろしいですか?それがあなたのために誤りを投げなかったら、新しいものはどちらもではありません。 –

+0

Aeq(6、[is.HE1、is.HE2、is.BF1、is.BF2、is.MPS])= [1,1,1、-1、-1]の短いものです。私は、あなたが言ったのと同じように、私のコードのすべての患者要素を修正しました。しかし、何かが間違っています。エラーを表示します:割り当てA(:) = Bでは、AとBの要素の数は同じでなければなりません。私は構造体の配列に関連してドキュメントをチェックし、私はいくつかの興味のものを発見します。上のコマンドラインでは、[is.HE1、...]は行列Aeqの6つの別々の索引付けを表していません。代わりに、ただ1つの数字です。したがって、上記の代入の左は6番目の行と348911番目の列を表します。しかし、これは私が欲しいものではありません。 –

関連する問題