Proc Optmodel SAS Conditional Restriction
I'm new to proc optmodel and can't seem to work out any 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 several things here:
IDs inside GRP must have the same x2, which is limited to MIN and MAX. Now I want to further constrain the increase / decrease of x2 based on the y value. If y <1, I don't want x2 to go below .95 * x1. If y> 1, I don't want x2 to exceed 1.05 * x1. I looked online and tried several things to make this happen. Here is my last try, cond_1 and cond_2 are issues 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;
source to share
The biggest problem with the model in question is that the indexing var
x2
is wrong. You can fix this by referring to the ID group 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 the description of the constraint, which reads the business problem closer, is to put the filter in the constraint definition:
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 any case, the problem becomes impossible due to the Cond2v2 constraint, as you can see using expand
(as @DomPazz pointed out) and in particular a parameter expand / iis
that will print conflicting constraints when it can define them:
solve with nlp / iis=on;
expand / iis;
source to share
I would calculate the global max and min in the data step outside the PROC OPTMODEL and then set the values. For example:
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 it 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 invalid:
Var x2[G] >= 5.7 <= 5.25
X2 [G] starts at [4,6];
With ID = 8, X = 5 and Y = 1.2. By your logic, this sets the max to 5.25 (5 * 1.2).
Now X2 [G] from [4.5.25]
With ID = 9, X = 6 and Y = 0.9. By your logic, this sets the min value to 5.7 (0.95 * 6).
X2 [G] in [5.7.5.25] <- BAD!
source to share