Mathematical Optimization, Discrete-Event Simulation, and OR

Operations Research topics: SAS/OR,
SAS Optimization, and SAS Simulation Studio
BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.

I have below data:

id $ cost profit_1 profit_2 score;
A -1 10 11 500
B -0.6 10 5 700
C -0.75 10 10.5 700
D -0.75 10.5 10 600
E -0.65 12 11 300
F -0.65 12 13 350;
Following code does the work when considering profits only:

proc optmodel;
set <str> ITEMS;
num cost {ITEMS};
set CASES = 1..2;
num profit {ITEMS, CASES};
read data have into ITEMS=[id] cost {j in CASES} <profit[id,j]=col('profit_'||j)>;
var X {ITEMS, CASES} binary;
max TotalProfit = sum {i in ITEMS, j in CASES} profit[i,j] * X[i,j];
con ChooseOne {i in ITEMS}: sum {j in CASES} X[i,j] <= 1;
con Budget: sum {i in ITEMS, j in CASES} cost[i] * X[i,j] <= 1.5;
solve;
print X;
quit;

but I want to add another constraint on score.
Something like SCORE must be greater than 500, i tried inserting following -
num score {ITEMS}

then in read data statement- SCORE[id] = col('SCORE')

And finally the constraint- con MinScore SCORE{i in ITEMS}: SCORE[id]>=500

but this is leading to infeasible solution because of cases where SCORE >=500.

Can anyone help in how to do this and what am I doing wrong?

 

1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ

Here are four ways, in increasing order of efficiency.

 

1. Impose explicit constraint:

/* if X[i,j] = 1 then score[i] >= 500 */
con MinScore {i in ITEMS, j in CASES}: score[i] >= 500 * X[i,j];

2. Fix variables to 0:

/* if score[i] < 500 then X[i,j] = 0 */
for {i in ITEMS: score[i] < 500} for {j in CASES} fix X[i,j] = 0;

3. Modify index set after reading data:

read data have into ITEMS=[id] cost score {j in CASES} <profit[id,j]=col('profit_'||j)>;
ITEMS = {i in ITEMS: score[i] >= 500};

4. Use WHERE= in READ DATA:

read data have(where=(score >= 500)) into ITEMS=[id] cost score {j in CASES} <profit[id,j]=col('profit_'||j)>;

See also this doc example.

View solution in original post

4 REPLIES 4
RobPratt
SAS Super FREQ

Here are four ways, in increasing order of efficiency.

 

1. Impose explicit constraint:

/* if X[i,j] = 1 then score[i] >= 500 */
con MinScore {i in ITEMS, j in CASES}: score[i] >= 500 * X[i,j];

2. Fix variables to 0:

/* if score[i] < 500 then X[i,j] = 0 */
for {i in ITEMS: score[i] < 500} for {j in CASES} fix X[i,j] = 0;

3. Modify index set after reading data:

read data have into ITEMS=[id] cost score {j in CASES} <profit[id,j]=col('profit_'||j)>;
ITEMS = {i in ITEMS: score[i] >= 500};

4. Use WHERE= in READ DATA:

read data have(where=(score >= 500)) into ITEMS=[id] cost score {j in CASES} <profit[id,j]=col('profit_'||j)>;

See also this doc example.

thepushkarsingh
Quartz | Level 8
Thanks a lot for your response. I was able to do 3 and 4, but it was subsetting my observations in output, so wasn't inclined. Finally I found 2 but was quite sure that this can be done in CON statement. Thanks again for 1. Very grateful for what I am learning from you.
RobPratt
SAS Super FREQ

Glad to help.  By the way, because of the ChooseOne constraint, you can tighten the MinScore constraint as follows:

con MinScore {i in ITEMS}: score[i] >= 500 * sum {j in CASES} X[i,j];

In either case, the MILP presolver will force X[i,j] to 0 if score[i] < 500.