2017-01-13 8 views
0

変数v(1) - v(k)のセットが与えられた場合、関数ff(v1,v2,...vk)と定義されます。SASは変数の関数を最大化する

ターゲットは、fが与えられたv(1)+v(2)+....+v(k)=nを最大にするv(i)のセットを持つことです。すべての要素は、負でない整数に制限されています。

注:SAS/IMLまたはSAS/ORはありません。

kが知られている場合、たとえば2とすれば、このようにsthできます。

data out; 
    set in; 
    maxf = 0; 
    n1 = 0; 
    n2 = 0; 
    do i = 0 to n; 
     do j = 0 to n; 
      if i + j ne n then continue; 
      _max = f(i,j); 
      if _max > maxf then do; 
       maxf = max(maxf,_max); 
       n1 = i; 
       n2 = j; 
      end; 
     end; 
    end; 
    drop i j; 
run; 

ただし、この解決策にはいくつかの問題があります。

  1. ループの使用は非常に効率が悪いようです。

  2. kが不明なときにネストされたループがどのように必要なのかわかりません。

それは正確kが特定のプレフィックスとnとデータinの列の#により決定される「Kビンに割り当てNボール」の問題は、マクロ変数によって決定されます。

機能fは、たとえばf(i,j) = 2*i+3*jです。

これはデータステップで実行できますか?

+0

がf常にあなたの変数の線形関数ですか?もしそうなら、SASを使用して、問題をホイールを再開発するのではなく、[lpsolve](https://sourceforge.net/projects/lpsolve/)のような別のアプリケーションにエクスポートすることをお勧めします。 – user667489

+0

@ user667489残念ながら、それはこの問題が解決できるかどうか疑問に思う理由の一部です。 – Lovnlust

+0

[SCIP](http://scip.zib.de/)はこれに対処できるかもしれません。 – user667489

答えて

1

コメントで述べたように、一般的な非線形整数プログラムは解くのが難しいです。以下のメソッドは、連続するパラメータを解決します。あなたは出力を取り、関数を最大にする最も近い整数値を見つけなければなりません。しかし、ループは今よりはるかに小さくなり、実行が速くなります。

まずは関数を作りましょう。この関数は余分なパラメータを持ち、そのパラメータでは線形です。このようなものの中に関数をラップします。

proc fcmp outlib=work.fns.fns; 
function f(x1,x2,a); 
    out = -10*(x1-5)*(x1-5) + -2*(x2-2)*(x2-2) + 2*(x1-5) + 3*(x2-2); 
    return(out+a); 
endsub; 
run;quit; 

options cmplib=work.fns; 

私たちは、SASは、実際のパラメータ以外に渡すことができる値を持つことができるようにaパラメータを追加する必要があります。 SASは、x1x2に基づいて、Aの可能性を解決していると考えます。

Aの値を持つデータセットを生成します。

data temp; 
a = 1; 
run; 

Aの可能性を最大化するためにPROC NLMIXEDを使用しています。

ods output ParameterEstimates=Parameters; 
ods select ParameterEstimates; 

proc nlmixed data=temp; 
parms x1=1 x2=1; 
bounds x1>0, x2>0; 

y = f(x1,x2,a); 

model a ~ general(y); 
run; 

ods select default; 

私はx1=5.1x2=2.75の出力を取得します。次に、「周囲」を検索して、最大値が出てくる場所を確認することができます。ここで

は値の周りに検索するためのデータステップでの私の試みです:

%macro call_fn(fn,n,parr); 
%local i; 
&fn(&parr[1] 
%do i=2 %to &n; 
    , &parr[&i] 
%end; 
,0) 
%mend; 

%let n=2; 
%let c=%sysevalf(2**&n); 

data max; 
set Parameters end=last; 
array parms[&n] _temporary_; 
array start[&n] _temporary_; 
array pmax[&n]; 
max = -9.99e256; 

parms[_n_] = estimate; 

if last then do; 
    do i=1 to &n; 
     start[i] = floor(parms[i]); 
    end; 

    do i=1 to &c; 
     x = put(i,$binary2.); 
     do j=1 to &n; 
      parms[j] = input(substr(x,j,1),best.) + start[j]; 
     end; 


     /*You need a macro to write this dynamically*/ 
     val = %call_fn(f,&n,parms); 

     *put i= max= val=; 
     if val > max then do; 
      do j=1 to &n; 
       pmax[j] = parms[j]; 
      end; 
      max = val; 
     end; 
    end; 
    output; 
end; 
+0

興味深い解決策。最尤部分については、詳細については教科書をチェックする必要がありますが、その背後にあるロジックを覚えていないことがあります。しかし、一度は連続した解決策があると思います。それでも私は2つの質問があります。 1.最初の部分では、proc nlmixedはxとnの和を保証しません。あなたは2番目の部分のためにそれを残しますか? 2. substr部分の働きを理解していない。 – Lovnlust

+0

sum(x)= nの制約が見当たらなかった。私はそれを実装する方法を見なければならないでしょう。 substr()の部分は、整数(2^n)の整数を取ります。私は数をバイナリ文字列、すなわち2 = 10に変換してCまでカウントします。次に、substr()関数でその文字列のj番目の値を取得し、それを開始値に追加します。これにより、0と1のすべての組み合わせを開始値に追加するための簡単な方法が得られます。 – DomPazz

+0

そして、尤度の部分については心配しないでください。関数を最大化するだけです。 – DomPazz