Rob
Am starting a new thread. I want to understand some basics. I have four nodes in my network. A set of locations called Ports that is indexed by P. From P, the products flow to a set of Transits (t) and from there it flows to a set of LSP (c) and from there it goes to the final destination (d). The demand is an array that is indexed over p and d only. This is an input and the solve is to find the cheapest combination of p-t-c-d .
I have 41 ports, 9 LSP, 28 transits and 18 destinations for a total combination of 41*9*28*18 = 185,976 combinations. However, I do not have demand from all p to all d. Also, I do not have all 185,976 combinations of rates as well. There are only 3,000 ish out of 185,976 that has a valid rates, all others are 0. When i prepped the data, i made sure I have all the possible cartesian combination possible . Those that has a valid cost or demand, thats good but if it does not, I said the value is 0. Is this a right approach? Alternatively, since I am doing cost minimization, I artificially inflated my 0 costs entries to a very high number like 100000 so that the model does not choose those in the solution. I am sure this is not the right method which is why i am trying to have a constraint called "UseProperRates" .
My question is how do i tell the model to ignore all 0 rates and demand.
Here is my code:
proc optmodel;
set <str> Ports;
set <str> DC;
set <str> LSP;
set <str> Transit;
read data STDOPT.PN3158_Ports into Ports=[PortSource];
read data STDOPT.PN3158_DC into DC=[RateMatchDest];
read data STDOPT.PN3158_LSP into LSP=[LSP];
read data STDOPT.PN3158_TRANSIT into Transit=[Transit];
num Containers {Ports,DC};
read data STDOPT.PN3158_data into [PortSource RateMatchDest] Containers=FEU;
print containers;
/*END OF GETTING FEU DATA*/
var Is_LSP {LSP} binary;
var IsLSPDC {LSP,DC} binary;
var IsPortsLSPDC {Ports,LSP,DC} binary;
var IsPortsTransitLSPDC {Ports,Transit,LSP,DC} binary;
/* declare Constants*/
num Min_Qty_LSP=0;
NUM BigM;
READ DATA STDOPT.PN3158_BigM INTO BigM=FEU;
/*RATES*/
num InboundLinehaul {Ports,Transit,LSP,DC};
read data STDOPT.PN3158_RATES into [PortSource Transit LSP RateMatchDest] InboundLinehaul=Rate;
/* DECISON VARIABLE */
var ContainersfromPortstoLSPtoDC {Ports,Transit,LSP,DC}>=0;
/* IMPLIED VARIABLE */
impvar Inbound_Linehaul_Costs= sum {p in Ports, t in Transit,c in LSP, d in DC} InboundLinehaul [p,t,c,d] *ContainersfromPortstoLSPtoDC [p,t,c,d];
impvar ContainersatLSP{c in LSP}=sum{p in Ports,t in Transit,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d];
impvar ContainersatTransitLSP{t in Transit, c in LSP}=sum{p in Ports,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d];
/* declare Objective Function*/
Min TotalCost = Inbound_Linehaul_Costs;
/* GENERAL CONSTRAINTS */
con Min_Qty_at_LSP_is_Respected {c in LSP}:
sum{p in Ports,t in Transit,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d]>=Min_Qty_LSP*Is_LSP[c];
con ModelOutput_Same_As_ModelInput {p in Ports, d in DC}:
sum {t in Transit,c in LSP} ContainersfromPortstoLSPtoDC[p,t,c, d] = Containers [p,d];
con CheckLSP {c in LSP}: ContainersatLSP[c] <= BigM*Is_LSP[c];
con UseProperRates{p in Ports, d in DC}:
Sum{t in Transit, c in LSP}IsPortsTransitLSPDC[p,t,c,d]*InboundLinehaul [p,t,c,d] >=1;
**expand / constraint;
solve with milp;
You have declared the PTCD set but not used it. Here is proper syntax for the constraint that currently gives you an error:
con Min_Qty_at_LSP_is_Respected {c in LSP}:
sum{<p,t,(c),d> in PTCD} ContainersfromPortstoLSPtoDC[p,t,c,d]*Assign[p,t,c,d] >= Min_Qty_LSP*Is_LSP[c];
Note that this constraint is nonlinear because it contains a multiplication of variables.
Instead of indexing the variables by the full Cartesian product and then using high penalties to avoid certain <p,t,c,d> tuples, it is much more efficient and numerically preferable to use a sparse set of tuples, as shown in the Sparse Modeling example from the documentation.
THanks Rob.
I will look into this very closely and will try to do changes accordingly.
I will try it out now.
Hi Rob
I have this toy model. I have a new set called PTCD and an assign variable that is binary. I was trying to use these in the constraints but I am not sure if I need to. Also, I added the new constraint "UseProperRates " to limit my model to use those rates that are less than $40. I got an error.
I am kind of lost now . I want to have the "sparse model " structure done so that I can layer in constraints one by one . But my basic general constraints does not seem to work. Can you please help me?
proc optmodel;
set<str> Ports=/'sea' 'air'/;
set<str> DC=/'A1' 'U1'/;
set<str> LSP=/'M' 'O' 'C'/;
set <str> Transit=/'W','E','G'/;
num Containers {Ports,DC}= [2000,3000,1000,4000];
var Is_LSP {LSP} binary;
var IsLSPDC {LSP,DC} binary;
var IsPortsLSPDC {Ports,LSP,DC} binary;
var IsPortsTransitLSPDC {Ports,Transit,LSP,DC} binary;
/* declare Constants*/
num Min_Qty_LSP=2000;
/*RATES*/
num InboundLinehaul {Ports,Transit,LSP,DC}= [40,10,30,5,20,10,
20,6,30,7,3,5,
2,6,2,60,18,4,
32,70,2,30,18,40,
19,10,2,29,3,9,
42,36,79,10,5,14
];
set PTCD = {p in Ports,t in Transit, c in LSP,d in DC : Inboundlinehaul[p,t,c,d] <=40};
var Assign {PTCD} binary;
/* DECISON VARIABLE */
var ContainersfromPortstoLSPtoDC {Ports,Transit,LSP,DC}>=0;
/* IMPLIED VARIABLE */
impvar Inbound_Linehaul_Costs= sum {p in Ports, t in Transit,c in LSP, d in DC} InboundLinehaul [p,t,c,d] *ContainersfromPortstoLSPtoDC [p,t,c,d];
impvar ContainersatLSP{c in LSP}=sum{p in Ports,t in Transit,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d];
impvar ContainersatTransitLSP{t in Transit, c in LSP}=sum{p in Ports,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d];
/* declare Objective Function*/
Min TotalCost = Inbound_Linehaul_Costs;
/* GENERAL CONSTRAINTS */
con Min_Qty_at_LSP_is_Respected {c in LSP} :
sum{p in Ports,t in Transit,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d]*Assign[p,t,c,d]>=Min_Qty_LSP*Is_LSP[c];
con ModelOutput_Same_As_ModelInput {p in Ports, d in DC}:
sum {t in Transit,c in LSP} ContainersfromPortstoLSPtoDC[p,t,c, d] = Containers [p,d];
con CheckLSP {c in LSP}: ContainersatLSP[c] <= 10000*Is_LSP[c];
/*con UseProperRates {p in ports, t in transit, c in LSP, d in DC: InboundLinehaul [p,t,c,d] >=40}:
IsPortsTransitLSPDC[p,t,c,d] = 0;*/
solve with milp;
You have declared the PTCD set but not used it. Here is proper syntax for the constraint that currently gives you an error:
con Min_Qty_at_LSP_is_Respected {c in LSP}:
sum{<p,t,(c),d> in PTCD} ContainersfromPortstoLSPtoDC[p,t,c,d]*Assign[p,t,c,d] >= Min_Qty_LSP*Is_LSP[c];
Note that this constraint is nonlinear because it contains a multiplication of variables.
Thanks Rob.
Yeah i agree that it is now non linear. I tried to do just the solve and not solve with milp. But there are integer variables and so based on what SAS said I used solve with LSO; It does seem to work. Do you see any problems with this approach?
I will add the set (PTCD) to my other constraints based on the syntax and you gave. I will let you know if i have questions.
Thank you for everything. You are the best.
The LSO solver is designed for problems with at most around 100 variables and does not provide any measure of optimality. When you get the code working, please post again, and I will see whether your problem can be linearized so that you can use the MILP solver.
Thanks ROb. I added the set {PTCD} to my other two general constraints. I have not changed anything on the specific constraints that I will layer once the skeleton of the problem is built.
Here is my code for the toy model. When I ran this, it said "the best solution does not satisfy feasibility tolerance" and so the solution status said "failed".
cas;
caslib _all_ ASsign;
proc optmodel;
set<str> Ports=/'sea' 'air'/;
set<str> DC=/'A1' 'U1'/;
set<str> LSP=/'M' 'O' 'C'/;
set <str> Transit=/'W','E','G'/;
num Containers {Ports,DC}= [2000,3000,1000,4000];
print containers;
var Is_LSP {LSP} binary;
var IsLSPDC {LSP,DC} binary;
var IsPortsLSPDC {Ports,LSP,DC} binary;
var IsPortsTransitLSPDC {Ports,Transit,LSP,DC} binary;
/* declare Constants*/
num Min_Qty_LSP=2000;
/*RATES*/
num InboundLinehaul {Ports,Transit,LSP,DC}= [40,10,30,5,20,10,
20,6,30,7,3,5,
2,6,2,60,18,4,
32,70,2,30,18,40,
19,10,2,29,3,9,
42,36,79,10,5,14
];
set PTCD = {p in Ports,t in Transit, c in LSP,d in DC : Inboundlinehaul[p,t,c,d] <=40};
var Assign {PTCD} binary;
/* DECISON VARIABLE */
var ContainersfromPortstoLSPtoDC {Ports,Transit,LSP,DC}>=0;
/* IMPLIED VARIABLE */
impvar Inbound_Linehaul_Costs= sum {p in Ports, t in Transit,c in LSP, d in DC} InboundLinehaul [p,t,c,d] *ContainersfromPortstoLSPtoDC [p,t,c,d];
impvar ContainersatLSP{c in LSP}=sum{p in Ports,t in Transit,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d];
impvar ContainersatTransitLSP{t in Transit, c in LSP}=sum{p in Ports,d in DC} ContainersfromPortstoLSPtoDC [p,t,c,d];
/* declare Objective Function*/
Min TotalCost = Inbound_Linehaul_Costs;
/* GENERAL CONSTRAINTS */
con Min_Qty_at_LSP_is_Respected {c in LSP}:
sum{<p,t,(c),d> in PTCD} ContainersfromPortstoLSPtoDC[p,t,c,d]*Assign[p,t,c,d] >= Min_Qty_LSP*Is_LSP[c];
con ModelOutput_Same_As_ModelInput {p in Ports, d in DC}:
sum {<(p),t,c,(d)> in PTCD} ContainersfromPortstoLSPtoDC[p,t,c, d]*Assign[p,t,c,d] = Containers [p,d];
con CheckLSP {c in LSP}:
Sum{<p,t,(c),d> in PTCD} ContainersatLSP[c]*Assign[p,t,c,d] <= 10000*Is_LSP[c];
/*con UseProperRates {p in ports, t in transit, c in LSP, d in DC: InboundLinehaul [p,t,c,d] >=40}:
IsPortsTransitLSPDC[p,t,c,d] = 0;*/
/*SPECIFIC CONSTRAINTS - You can comment / uncomment based on what you want */
/*Constraint for retricting LSP-DC: given LSP can go to only "x" number of DC */
num MAEU_DCs=1;
**con LSP_DC: sum{d in DC} IsLSPDC['ONEY',d] = MAEU_DCs;
**con LSP_DC_Link{p in Ports, t in Transit,c in LSP, d in DC}:
ContainersfromPortstoLSPtoDC[p,t,c,d] <= 10000 * IsLSPDC[c,d];
/*Constraint for retricting Ports-LSP-DC: given Ports-DC combo can be served by only 1 LSP */
num NumberofLSPsPerPorts_DC=1;
**con OneLSPPerLane {p in Ports,d in DC}: sum{c in LSP} IsPortsLSPDC[p,c,d] = NumberofLSPsPerPorts_DC;
**con Ports_LSP_DC_Link{p in Ports,c in LSP, t in Transit,d in DC}:
ContainersfromPortstoLSPtoDC[p,t,c,d] <= 10000 * IsPortsLSPDC[p,c,d];
/* Have These Many LSPs open*/
num NumberofLSPsopen=2;
**con HaveAtleastTheseManyLSPopen: Sum{c in LSP} Is_LSP [c]=NumberofLSPsopen;
/* Forcing the demand via a given LSP and a DC Combo*/
num O_FU1=0.1*10000;
**con Allocation_ONEY_FU1:sum{p in Ports, t in Transit} ContainersfromPortstoLSPtoDC[p,t,'ONEY','FU1']=ONEY_FU1;
/* Forcing the demand via a given Transit Route */
NUM A_W=0.4*10000;
**con Allocation_W{t in Transit}:sum {p in Ports,c in LSP,d in DC} ContainersfromPortstoLSPtoDC[p,'W',c,d]=Alloc_W;
/* Forcing a Maximum at a given LSP*/
**num Max_Qty_LSP=10;
**con MaxatLSP {c in LSP}: ContainersatLSP[c] <=Max_Qty_LSP*Is_LSP[c];
expand;
solve with lso;
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.