I am trying to solve an integer nonlinear problem like this:
| location g | location s | location t |
Office Visit | 80 | 70 | 90 |
Video Visit | 25 | 31 | 27 |
I am trying to see how to allocate these providers in these locations, to meet the demand most.
Here are my codes, and I have 15 variables, represent the number of days for each provider to stay in one location for the next 10 days. For example, p1g means the number of days that provider p1 at location g.
proc optmodel;
var p1g<=6 >=0 , p2g<=6>=0, p3g<=6>=0, p4g<=6>=0, p5g<=6>=0 integer;
var p1s<=6>=0, p2s<=6>=0, p3s<=6>=0 ,p4s<=6>=0, p5s<=6>=0 integer;
var p1t<=6>=0, p2t<=6>=0, p3t<=6>=0, p4t<=6>=0, p5t<=6>=0 integer;
/* declare objective */
impvar OfficeVisit=min(7*(p1g+p2g+p3g+p4g+p5g),80)
+min(7*(p1s+p2s+p3s+p4s+p5s),70)
+min(7*(p1t+p2t+p3t+p4t+p5t),90);
impvar VideoVisit=min(3*(p1g+p2g+p3g+p4g+p5g),25)
+min(3*(p1s+p2s+p3s+p4s+p5s),31)
+min(3*(p1t+p2t+p3t+p4t+p5t),27);
/*declare constraints*/
con p1g +p1s +p1t<=6;
con p2g +p2s +p2t<=6;
con p3g +p3s +p3t<=6;
con p4g +p4s +p4t<=6;
con p5g +p5s +p5t<=6;
max bts = OfficeVisit + VideoVisit;
solve ;
print p1g p2g p3g p4g p5g p1s p2s p3s p4s p5s p1t p2t p3t p4t p5t;
quit;
If you have SAS Viya, you can use the LINEARIZE option to automatically linearize the problem:
solve linearize;
Problem Summary | |
---|---|
Objective Sense | Maximization |
Objective Function | bts |
Objective Type | Nonlinear |
Number of Variables | 15 |
Bounded Above | 0 |
Bounded Below | 0 |
Bounded Below and Above | 15 |
Free | 0 |
Fixed | 0 |
Binary | 0 |
Integer | 3 |
Number of Constraints | 5 |
Linear LE (<=) | 5 |
Linear EQ (=) | 0 |
Linear GE (>=) | 0 |
Linear Range | 0 |
Constraint Coefficients | 15 |
Solution Summary | |
---|---|
Solver | MILP |
Algorithm | Branch and Cut |
Objective Function | bts |
Solution Status | Optimal |
Objective Value | 292 |
Relative Gap | 0 |
Absolute Gap | 0 |
Primal Infeasibility | 0 |
Bound Infeasibility | 0 |
Integer Infeasibility | 0 |
Best Bound | 292 |
Nodes | 1 |
Solutions Found | 3 |
Iterations | 10 |
Presolve Time | 0.03 |
Solution Time | 0.04 |
p1g | p2g | p3g | p4g | p5g | p1s | p2s | p3s | p4s | p5s | p1t | p2t | p3t | p4t | p5t |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1.25 | 1.25 | 1.25 | 1.25 | 6 | 2.5 | 2.5 | 2.5 | 2.5 | 0 | 2.25 | 2.25 | 2.25 | 2.25 | 0 |
But notice that some variables are fractional. That is because the INTEGER keyword applies only to three of the variables in your VAR statements. What you intended was instead:
var p1g<=6>=0 integer, p2g<=6>=0 integer, p3g<=6>=0 integer, p4g<=6>=0 integer, p5g<=6>=0 integer;
var p1s<=6>=0 integer, p2s<=6>=0 integer, p3s<=6>=0 integer, p4s<=6>=0 integer, p5s<=6>=0 integer;
var p1t<=6>=0 integer, p2t<=6>=0 integer, p3t<=6>=0 integer, p4t<=6>=0 integer, p5t<=6>=0 integer;
And this yields integer values for all variables:
p1g | p2g | p3g | p4g | p5g | p1s | p2s | p3s | p4s | p5s | p1t | p2t | p3t | p4t | p5t |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
6 | 2 | 0 | 0 | 3 | 0 | 4 | 0 | 6 | 0 | 0 | 0 | 6 | 0 | 3 |
A more compact and less error-prone approach is to use index sets:
proc optmodel;
set PROVIDERS = 1..5;
set LOCATIONS = /g s t/;
var NumDays {PROVIDERS, LOCATIONS} >= 0 <= 6 integer;
/* declare objective */
num officeDemand {LOCATIONS} = [80, 70, 90];
impvar OfficeVisit = sum {l in LOCATIONS} min(7*sum {p in PROVIDERS} NumDays[p,l], officeDemand[l]);
num videoDemand {LOCATIONS} = [25, 31, 27];
impvar VideoVisit = sum {l in LOCATIONS} min(3*sum {p in PROVIDERS} NumDays[p,l], videoDemand[l]);
/*declare constraints*/
con ProviderLimit {p in PROVIDERS}: sum {l in LOCATIONS} NumDays[p,l] <= 6;
max bts = OfficeVisit + VideoVisit;
solve linearize;
print NumDays;
quit;
NumDays | |||
---|---|---|---|
g | s | t | |
1 | 6 | 0 | 0 |
2 | 2 | 4 | 0 |
3 | 0 | 0 | 6 |
4 | 0 | 6 | 0 |
5 | 3 | 0 | 3 |
If you have SAS Viya, you can use the LINEARIZE option to automatically linearize the problem:
solve linearize;
Problem Summary | |
---|---|
Objective Sense | Maximization |
Objective Function | bts |
Objective Type | Nonlinear |
Number of Variables | 15 |
Bounded Above | 0 |
Bounded Below | 0 |
Bounded Below and Above | 15 |
Free | 0 |
Fixed | 0 |
Binary | 0 |
Integer | 3 |
Number of Constraints | 5 |
Linear LE (<=) | 5 |
Linear EQ (=) | 0 |
Linear GE (>=) | 0 |
Linear Range | 0 |
Constraint Coefficients | 15 |
Solution Summary | |
---|---|
Solver | MILP |
Algorithm | Branch and Cut |
Objective Function | bts |
Solution Status | Optimal |
Objective Value | 292 |
Relative Gap | 0 |
Absolute Gap | 0 |
Primal Infeasibility | 0 |
Bound Infeasibility | 0 |
Integer Infeasibility | 0 |
Best Bound | 292 |
Nodes | 1 |
Solutions Found | 3 |
Iterations | 10 |
Presolve Time | 0.03 |
Solution Time | 0.04 |
p1g | p2g | p3g | p4g | p5g | p1s | p2s | p3s | p4s | p5s | p1t | p2t | p3t | p4t | p5t |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1.25 | 1.25 | 1.25 | 1.25 | 6 | 2.5 | 2.5 | 2.5 | 2.5 | 0 | 2.25 | 2.25 | 2.25 | 2.25 | 0 |
But notice that some variables are fractional. That is because the INTEGER keyword applies only to three of the variables in your VAR statements. What you intended was instead:
var p1g<=6>=0 integer, p2g<=6>=0 integer, p3g<=6>=0 integer, p4g<=6>=0 integer, p5g<=6>=0 integer;
var p1s<=6>=0 integer, p2s<=6>=0 integer, p3s<=6>=0 integer, p4s<=6>=0 integer, p5s<=6>=0 integer;
var p1t<=6>=0 integer, p2t<=6>=0 integer, p3t<=6>=0 integer, p4t<=6>=0 integer, p5t<=6>=0 integer;
And this yields integer values for all variables:
p1g | p2g | p3g | p4g | p5g | p1s | p2s | p3s | p4s | p5s | p1t | p2t | p3t | p4t | p5t |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
6 | 2 | 0 | 0 | 3 | 0 | 4 | 0 | 6 | 0 | 0 | 0 | 6 | 0 | 3 |
A more compact and less error-prone approach is to use index sets:
proc optmodel;
set PROVIDERS = 1..5;
set LOCATIONS = /g s t/;
var NumDays {PROVIDERS, LOCATIONS} >= 0 <= 6 integer;
/* declare objective */
num officeDemand {LOCATIONS} = [80, 70, 90];
impvar OfficeVisit = sum {l in LOCATIONS} min(7*sum {p in PROVIDERS} NumDays[p,l], officeDemand[l]);
num videoDemand {LOCATIONS} = [25, 31, 27];
impvar VideoVisit = sum {l in LOCATIONS} min(3*sum {p in PROVIDERS} NumDays[p,l], videoDemand[l]);
/*declare constraints*/
con ProviderLimit {p in PROVIDERS}: sum {l in LOCATIONS} NumDays[p,l] <= 6;
max bts = OfficeVisit + VideoVisit;
solve linearize;
print NumDays;
quit;
NumDays | |||
---|---|---|---|
g | s | t | |
1 | 6 | 0 | 0 |
2 | 2 | 4 | 0 |
3 | 0 | 0 | 6 |
4 | 0 | 6 | 0 |
5 | 3 | 0 | 3 |
@RobPratt thank you so much. I don't have Viya but "solve with LSO" works after I add 'INTEGER' keyword to all variables.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.