Proc Optmodel条件约束SAS

3

我是一个新手,不太懂如何使用proc optmodel,有些语法还很困惑。

这是我的数据集。

data opt_test;
        input ID GRP $ x1 MIN MAX y z;
cards;
2 F 10 9 11 1.5 100
3 F 10 9 11 1.2 50
4 F 11 9 11 .9 20
8 G 5 4 6 1.2 300
9 G 6 4 6 .9 200
1 H 21 18 22 1.2 300
7 H 20 18 22 .8 1000
;
run;

这里有几个要点:

GRP内的ID必须具有相同的x2,这受到MIN和MAX的限制。我现在希望根据y的值进一步限制x2的增加/减少。如果y<1,则不希望x2低于.95*x1。如果y>1,则不希望x2超过1.05*x1。我在网上查找并尝试了一些方法来实现这一点。以下是我的最新尝试,cond_1和cond_2是感兴趣的问题,因为其他所有内容都有效:

proc optmodel;

set<num> ID;

string GRP{ID};
set GRPS = setof{i in ID} GRP[i];
set IDperGRP{gi in GRPS} = {i in ID: GRP[i] = gi};

number x1{ID}; 
number MIN{ID};
number MAX{ID}; 

var x2{gi in GRPS} >= max{i in IDperGRP[gi]} MIN[i] 
                   <= min{i in IDperGRP[gi]} MAX[i] 
;
impvar x2byID{i in ID} = x2[GRP[i]];
number y{ID}; 
number z{ID}; 

read data opt_test into
        ID=[ID]
        GRP
        x1 
        MIN 
        MAX 
        y 
        z 
        ;

max maximize = sum{gi in GRPS} sum{i in IDperGRP[gi]} 
            (x2[gi]) * (1-(x2[gi]-x1[i])*y[i]/x1[i]) * z[i];

con cond_1 {i in ID}: x2[i] >= 
        if y[i]<1 then .95*x1[i] else 0;
con cond_2 {i in ID}: x2[i] <= 
        if y[i]>=1 then 1.05*x1[i] else 99999999;

solve;

create data results from [ID]={ID} x2=x2byID GRP x1 MIN MAX y z;

print x2 maximize;
quit;

是的,在约束中不能使用条件语句。y是否严格大于等于0? - DomPazz
是的,y始终大于0。这是我在尝试形成语法时参考的网站之一:http://support.sas.com/documentation/cdl/en/ormpug/59679/HTML/default/viewer.htm#optmodel_sect58.htm - pyll
1
一个问题是x2被定义为GRPS集合(一个字符串),而不是ID集合(一个数字)。因此,“{i in ID} x2[i]”将无法解决。 - DomPazz
另外,假设X2在群组上定义,而y在id上定义,您如何处理每个组的条件两侧都有y的事实?您是否只是寻找对X2最严格的约束条件? - DomPazz
我不想让任何给定的ID超过基于其特定y值的限制,从而限制整个组。 - pyll
您可以在约束条件中使用条件语句。如果条件语句涉及到一个 var,则结果表达式将是非线性的。在这种情况下,条件只涉及到 num,因此约束是线性的。请查看我的答案以获取更多详细信息。 - Leo
2个回答

3

我会在 PROC OPTMODEL 之外的数据步骤中计算全局最大值和最小值,然后设置这些值。具体操作如下:

data opt_test;
set opt_test;
if y < 1 then
    min2 = .95*x1;
else
    min2 = 0;

if y>=1 then
    max2 = 1.05*x1;
else
    max2 = 9999999999;

Min_old = min;
max_old = max;

MIN = max(min,min2);
MAX = min(max,max2);
run;

但是您在群组G方面遇到了问题。使用“展开”来查看它。

proc optmodel;

set<num> ID;

string GRP{ID};
set GRPS = setof{i in ID} GRP[i];
set IDperGRP{gi in GRPS} = {i in ID: GRP[i] = gi};

number x1{ID}; 
number MIN{ID};
number MAX{ID}; 

var x2{gi in GRPS} >= max{i in IDperGRP[gi]} MIN[i] 
                   <= min{i in IDperGRP[gi]} MAX[i] 
;
impvar x2byID{i in ID} = x2[GRP[i]];
number y{ID}; 
number z{ID}; 

read data opt_test into
        ID=[ID]
        GRP
        x1 
        MIN 
        MAX 
        y 
        z 
        ;

max maximize = sum{gi in GRPS} sum{i in IDperGRP[gi]} 
            (x2[gi]) * (1-(x2[gi]-x1[i])*y[i]/x1[i]) * z[i];

/*con cond_1 {i in ID}: x2[i] >= 
        if y[i]<1 then .95*x1[i] else 0;
con cond_2 {i in ID}: x2[i] <= 
        if y[i]>=1 then 1.05*x1[i] else 99999999;*/

expand;
solve;

create data results from [ID]={ID} x2=x2byID GRP x1 MIN MAX y z;

print x2 maximize;
quit;

您会发现X2[G]是不可行的:
Var x2[G] >= 5.7 <= 5.25

X2[G]从[4,6]开始;

对于ID=8,X=5且Y=1.2。按照你的逻辑,这将把最大值设置为5.25(5*1.2)。

现在X2[G]在[4,5.25]范围内。

对于ID=9,X=6且Y=0.9。按照你的逻辑,这将把最小值设置为5.7(0.95*6)。

X2[G]在[5.7,5.25]范围内 <-- 不好!


是的。我同意。在优化过程之外声明这些值更有意义。感谢分享扩展语句。这将有助于调试。 - pyll
这是一个很好的解决方案,但Leo的回答正确地解决了所述的问题。谢谢你的帮助。 - pyll

2

这个问题模型的最大问题在于索引varx2是不正确的。你可以通过将ID组作为参考来解决这个问题:

con cond_1 {i in ID}: x2[GRP[i]] >= 
        if y[i] < 1 then .95*x1[i] else 0;
con cond_2 {i in ID}: x2[GRP[i]] <= 
        if y[i]>=1 then 1.05*x1[i] else 99999999;

但更接近业务问题的约束描述是在约束定义本身中放置一个过滤器:

con Cond_1v2 {i in ID: y[i] < 1} : x2[GRP[i]] >=  .95 * x1[i]; 
con Cond_2v2 {i in ID: Y[i] >= 1}: x2[GRP[i]] <= 1.05 * x1[i];

无论哪种情况,由于约束条件Cond2v2的存在,问题变得不可行。可以使用expand(如@DomPazz所指出的)来查看,特别是使用expand / iis选项,它会在能够确定时打印出冲突的约束条件:
solve with nlp / iis=on;
expand / iis;

啊好的。所以逻辑是正确的,但索引错误。这是我在optmodel过程中遇到的最大问题。你有什么推荐的资源吗?SAS文档并不是非常有用,因为示例太少且太简单。谢谢。 - pyll
这是我的首选推荐:http://support.sas.com/documentation/cdl/en/ormpex/67518/HTML/default/viewer.htm#titlepage.htm。它与一本备受好评的教材相辅相成,其中包含直接用OPTMODEL编写的示例。 - Leo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接