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.

sas-innovate-white.png

Our biggest data and AI event of the year.

Don’t miss the livestream kicking off May 7. It’s free. It’s easy. And it’s the best seat in the house.

Join us virtually with our complimentary SAS Innovate Digital Pass. Watch live or on-demand in multiple languages, with translations available to help you get the most out of every session.

 

Register now!

Discussion stats
  • 4 replies
  • 1314 views
  • 2 likes
  • 2 in conversation