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 2025: Register Today!

 

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


Register now!

Multiple Linear Regression in SAS

Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.

Find more tutorials on the SAS Users YouTube channel.

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