Reputation: 1764
I'm fairly new to proc optmodel and having trouble sorting out some syntax.
Here is my dataset.
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;
There are a few things going on here:
The IDs within a GRP must have the same x2, which is constrained by MIN and MAX. I now wish to further constrain the increase/decrease of x2 based on the value of y. If y<1, I do not want x2 to go below .95*x1. If y>1, I do not want x2 to exceed 1.05*x1. I've looked online and tried a few things to make this happen. Here is my latest attempt, cond_1 and cond_2 are the problems of interest, as everything else works:
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;
Upvotes: 3
Views: 1751
Reputation: 3136
The biggest problem with the model in the question is that the indexing of the var
x2
is incorrect. You could fix that by referring to the group of the ID as such:
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;
but a description of the constraint that reads closer to the business problem is to put a filter in the constraint definition itself:
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];
In either case, the problem becomes infeasible because of the constraint Cond2v2, as you can see using expand
(as @DomPazz pointed out), and in particular the expand / iis
option, which will print the conflicting constraints when it can determine them:
solve with nlp / iis=on;
expand / iis;
Upvotes: 2
Reputation: 12465
I would calculate the global max and min in a data step outside of PROC OPTMODEL and then set the values. Like so:
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;
But you have a problem with group G. Use expand to see it.
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;
You will see that X2[G] is infeasible:
Var x2[G] >= 5.7 <= 5.25
X2[G] starts in [4,6];
For ID=8, X=5 and Y=1.2. By your logic, this sets the max to 5.25 (5*1.2).
Now X2[G] in [4,5.25]
For ID=9, X=6 and Y=0.9. By your logic this sets the min to 5.7 (0.95*6).
X2[G] in [5.7,5.25] <-- BAD!
Upvotes: 3