BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Santha
Pyrite | Level 9

Hi Rob

Here is my full fledged model. It has  52 weeks data. I have cross checked the input files and is clean and good. 

I added proportion to my code to make sure that for a given ISN that goes via CYS, the proportion split add up to 1. Similarly for CFS, for a week load of stuff going to CFS, the proportion of volume goes via CFS for that week adds up to 1. This proportioned volume is what is used for calculation of Volume Based Cost. This proportion I have declared it as a decision variable and have used it for an impvar called VolumeInsideBox  When i do this, I am getting error for non-linearity. I am able to understand that my Volume and Shipment based costs are not written linearly, same is the case for constraints. I added constraints for Proportion_CFS and Proportion_CYS to make sure it adds up to 1.  Here is my code below . I will send the 5 files as well. Boxrate files I have broken down into 3 parts for memory size restrictions. Another thing is in the create data step, want to make sure there are no duplicates. Appreciate your support..

proc optmodel;

set <str> ORG;
read data CASUSER.Unique_ORG into ORG = [ORG];

set <str> DES; 
read data CASUSER.Unique_DES into DES = [DES];

set <str> BOX; 
read data CASUSER.Unique_BOX into BOX = [BOX];

set <str> MOL; 
read data CASUSER.Unique_MOL into MOL = [MOL];

set <str> T1; 
read data CASUSER.Unique_T1 into T1 = [T1];

set <str> T2; 
read data CASUSER.Unique_T2 into T2 = [T2];

/*Read ISN Wt and Volume for a given ISN* - START */
set <str> ISN;
str Org_ISN {ISN};
str Des_ISN {ISN};
str T1_ISN {ISN};
str T2_ISN {ISN};
num Volume_ISN {ISN};
num Weight_ISN {ISN};

read data CASUSER.InputData_AssetMix into ISN=[ISN] Org_ISN=ORG Des_ISN=DES Volume_ISN=Volume Weight_ISN=Weight T1_ISN=T1 T2_ISN=T2;

/*Read ISN Wt and Volume for a given ISN* - END*/

/*Read Wt and Volume Capacity for a given ORG, DES, BOX - START */
num Volume_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
num Weight_Capacity {ORG,DES,BOX,MOL,T1,T2} init 0;  num Weight_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
read data CASUSER.BOXSPECS into [ORG DES BOX MOL T1 T2] 
Weight_Capacity=Weight_Capacity
Volume_Min=Volume_Min
Weight_Min=Weight_Min;

num Volume_Capacity {BOX}; 
read data CASUSER.BOXSPECS into [BOX] Volume_Capacity=Volume_Capacity;

num Volume_Capacity_CFS{BOX,T2};
read data CASUSER.BOXSPECS into [BOX T2] Volume_Capacity_CFS=Volume_Capacity;
/*Read Wt and Volume Capacity for a given ORG, DES, BOX - END */


/* A Binary variable that is 0 or 1 for a given asset for a given lane, 0 indicated not available, 1- available */
num Is_BoxAvalable_for_a_lane {ORG,DES,BOX,MOL,T1,T2};
read data CASUSER.BOXSpecs into [ORG Des Box Mol T1 T2] Is_BoxAvalable_for_a_lane = BoxAvailability;

/* Decision Variable - START */
var BOXNeeded_CYS {i in ISN,b in BOX} >= 0 integer <= ceil(Volume_ISN[i] / Volume_Capacity[b]);
var BOXNeeded_CFS {b in BOX,w in T2} integer >=0 <= ceil(sum {i in ISN} Volume_ISN[i] / Volume_Capacity[b]);
var Is_ISN_MOL{ISN,MOL} binary;

var Proportion_CYS {ISN,BOX} >= 0 <= 1;
impvar VolumeInsideBox_CYS {i in ISN, b in BOX} = Volume_ISN[i] * Proportion_CYS[i,b];

var Proportion_CFS {BOX,T2} >= 0 <= 1;
impvar VolumeInsideBox_CFS {b in BOX, w in T2} = sum{i in ISN} Volume_ISN[i] * Proportion_CFS[b,w];

/* Decision Variable and Associated Impvars - END */

/*Define Rates and ImplicitVariables START */
/*Box Based Costs START */

set <str,str,str,str,str,str> PerBox_Based_Rate_NoZeroes;
num PerBox_Based_Rate {PerBox_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes=[ORG DES BOX MOL T1 T2] PerBox_Based_Rate=Rate;

impvar PerBox_Based_Costs_CYS {i in ISN} = sum {b in BOX,m in {'CYS'}}
PerBox_Based_Rate[Org_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]] * BOXNeeded_CYS[i,b];

set <str,str> PerBox_Based_Rate_NoZeroes_CFS;
num PerBox_Based_Rate_CFS {PerBox_Based_Rate_NoZeroes_CFS}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and 'CFS' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes_CFS=[BOX T2] PerBox_Based_Rate_CFS=Rate;

impvar PerBox_Based_Costs_CFS {w in T2} = sum {b in BOX} PerBox_Based_Rate_CFS[b,w] * BOXNeeded_CFS[b,w];
impvar TotalBoxBasedCost = sum {i in ISN} PerBox_Based_Costs_CYS[i] + sum {w in T2} PerBox_Based_Costs_CFS[w];

/*Box Based Costs END */
/*Vol Based Costs START*/
set <str,str,str,str,str> PerVol_Based_Rate_NoZeroes;
num PerVol_Based_Rate {PerVol_Based_Rate_NoZeroes} init 0; 
read data CASUSER.BOXRATE (where=(RateBasis="PerVolUOM" and Ratetype='Origin' and Rate>=0)) 
into PerVol_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerVol_Based_Rate=Rate;

impvar VolBasedCost_CYS {i in ISN, b in BOX} = VolumeInsideBox_CYS[i,b]*Proportion_CYS[i,b] * 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CYS'];

impvar VolBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN} VolumeInsideBox_CFS[b,w]*Proportion_CFS[b,w]*
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CFS'];


impvar TotalVolBasedCost = sum {i in ISN, b in BOX} VolBasedCost_CYS[i,b] + sum {b in BOX, w in T2}VolBasedCost_CFS[b,w];
/*Vol Based Costs END*/

/*Shipment Based Costs START*/
set <str,str,str,str,str> PerShp_Based_Rate_NoZeroes;
num PerShp_Based_Rate {PerShp_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerShipment" and Ratetype='Document' and Rate>=0)) 
into PerShp_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerShp_Based_Rate=Rate;

impvar ShipmentBasedCost_CYS {i in ISN, b in BOX} = Proportion_CYS[i,b] * 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CYS'];

impvar ShipmentBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN} Proportion_CFS[b,w]*
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CFS'];


impvar TotalShipmentBasedCost = sum {i in ISN, b in BOX} ShipmentBasedCost_CYS[i,b] + sum {b in BOX, w in T2}ShipmentBasedCost_CFS[b,w];
/*Shipment Based Costs END*/
/*Define Rates and ImplicitVariables END*/


Min TotalCost = TotalBoxBasedCost+ TotalVolBasedCost + TotalShipmentBasedCost;

/* Constraints START*/

con OneMOL{i in ISN}:
    sum{m in MOL} Is_ISN_MOL[i,m] = 1; /* This is to make sure one ISN can go either CYS or CFS */

con SumProportionToOne_CYS {i in ISN}:
      sum {b in BOX} VolumeInsideBox_CYS[i,b]= sum {b in Box}Volume_ISN[i]*Proportion_CYS[i,b]*IS_ISN_MOL[i,'CYS'];

con SumProportionToOne_CFS {w in T2}:
      sum {b in BOX} VolumeInsideBox_CFS[b,w]= sum {i in ISN,b in Box}Volume_ISN[i]*Proportion_CFS[b,w]*IS_ISN_MOL[i,'CFS'];


con BoxConCYS {i in ISN, b in BOX}:
      Volume_Capacity[b] * BOXNeeded_CYS[i,b] >= VolumeInsideBox_CYS[i,b];


impvar TotalVol {m in MOL,w in T2} = sum {i in ISN} Volume_ISN[i] * Is_ISN_MOL[i,m];

con BoxConCFS {w in T2}: sum {b in BOX} Volume_Capacity_CFS[b,w] * BOXNeeded_CFS[b,w] >= sum {b in BOX} TotalVol['CFS',w]*VolumeInsideBox_CFS[b,w];

solve with milp / decomp=(method=concomp);

num optCYSCost {ISN,BOX};

for {i in ISN, b in BOX} optCYSCost[i,b] = PerBox_Based_Costs_CYS[i] + VolBasedCost_CYS[i,b] + ShipmentBasedCost_CYS[i,b];
print PerBox_Based_Costs_CYS VolBasedCost_CYS ShipmentBasedCost_CYS optCYSCost;

   num volShareCFS {i in ISN,w in T2} = Volume_ISN[i] * Is_ISN_MOL[i,'CFS'].sol / TotalVol['CFS',w].sol;

   print Is_ISN_MOL; 
   print BOXNeeded_CYS BOXNeeded_CFS;
   print PerBox_Based_Costs_CYS PerBox_Based_Costs_CFS;
   print volShareCFS VolBasedCost_CFS VolBasedCost_CYS TotalVolBasedCost TotalVol;
   print ShipmentBasedCost;

/*Output*/
create data CASUSER.SolutionDataCYS from [ISN=i BoxType=b]={i in ISN, b in BOX: BOXNeeded_CYS[i,b] > 0.5}
MOL='CYS'
Org=Org_ISN[i] 
Des=Des_ISN[i] 
T1=T1_ISN[i] 
T2=T2_ISN[i] 
Volume=Volume_ISN[i] 
Weight=Weight_ISN[i]
BoxNeeded=BOXNeeded_CYS 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CYS[i,b]
VolumeInsideBox=VolumeInsideBox_CYS[i,b]
VolShare=1
BoxBasedCost=(PerBox_Based_Rate[ORG_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]]*BOXNeeded_CYS[i,b]) 
VolBasedCost=VolBasedCost[i]  
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CYS[i,b]);
;

create data CASUSER.SolutionDataCFS
(where=(VolShare>0)) from [ISN=i BoxType=b T2=w]={i in ISN, b in BOX, w in T2: BOXNeeded_CFS[b,w] > 0.5}
MOL='CFS' 
Org=Org_ISN[i] 
Des=Des_ISN[i] 
T1=T1_ISN[i] 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CFS[b,w]
VolumeInsideBox=VolumeInsideBox_CFS[b,w]
Weight=Weight_ISN[i]
BoxNeeded=(volShareCFS[i,w]*BOXNeeded_CFS[b,w]) 
Vol_InsideBox=Volume_ISN[i] VolShare=volShareCFS[i,w]
BoxBasedCost=(volShareCFS[i,w]*PerBox_Based_Rate_CFS[b,w]*BOXNeeded_CFS[b,w]) 
VolBasedCost=VolBasedCost[i] 
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CFS[b,w]);
quit;

 

1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ

I already replied to Santha in response to a private message, but for the benefit of the rest of the community, here was my recommendation:

 

The introduction of Proportion into the optimization model seems to complicate things.  I recommend going back to the model that you said worked smoothly last Saturday (https://communities.sas.com/t5/Mathematical-Optimization/AssetOpt-OutputViews-FullModel/td-p/885576) and computing Proportion after the fact if you need it for reporting.

View solution in original post

13 REPLIES 13
Santha
Pyrite | Level 9
 
Santha
Pyrite | Level 9

boxrate 2

Santha
Pyrite | Level 9

boxrate3

Santha
Pyrite | Level 9
 
RobPratt
SAS Super FREQ

Here are several comments and corrections.

 

1. You also need new unique_t1, unique_t2, and unique_box tables.

 

2. The num Is_BoxAvalable_for_a_lane parameter is declared and populated but not used in the optimization model.

 

3. The following IMPVAR declaration cannot be correct because it does not link i to b or w.  In particular, you want only the i for which T2_ISN[i] = w.

impvar VolumeInsideBox_CFS {b in BOX, w in T2} = sum{i in ISN} Volume_ISN[i] * Proportion_CFS[b,w];

 

4. You do not need to sum over m here:

/*   impvar PerBox_Based_Costs_CYS {i in ISN} = sum {b in BOX,m in {'CYS'}}*/
   impvar PerBox_Based_Costs_CYS {i in ISN} = sum {b in BOX}
      PerBox_Based_Rate[Org_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]] * BOXNeeded_CYS[i,b];

 

5. You do not need Proportion_CYS or Is_ISN_MOL here, and removing them avoids nonlinearity:

/*   impvar VolBasedCost_CYS {i in ISN, b in BOX} = VolumeInsideBox_CYS[i,b] * Proportion_CYS[i,b] * */
/*      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} */
/*      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CYS'];*/
   impvar VolBasedCost_CYS {i in ISN, b in BOX} =
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CYS[i,b];

 

6. Similar comment here, but the VolumeInsideBox[b,w] variable doesn't depend on i, so I suspect you want a different coefficient:

/*   impvar VolBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN} VolumeInsideBox_CFS[b,w] * Proportion_CFS[b,w] * */
/*      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} */
/*      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CFS'];*/
   impvar VolBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN} 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CFS[b,w];

 

7. You do not need both Proportion_CYS and Is_ISN_MOL here, but I don't know which one you want because in the toy example each shipment happened to use only one box.

   impvar ShipmentBasedCost_CYS {i in ISN, b in BOX} = Proportion_CYS[i,b] *
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes}
      PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CYS'];

 

8. Similar comment to #3 and #7:

   impvar ShipmentBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN} Proportion_CFS[b,w] * 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
      PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * Is_ISN_MOL[i,'CFS'];

 

9. Avoid nonlinearity:

   con SumProportionToOne_CYS {i in ISN}:
/*      sum {b in BOX} VolumeInsideBox_CYS[i,b]= sum {b in Box}Volume_ISN[i] * Proportion_CYS[i,b] * IS_ISN_MOL[i,'CYS'];*/
      sum {b in BOX} Proportion_CYS[i,b] = IS_ISN_MOL[i,'CYS'];

   con SumProportionToOne_CFS {w in T2}:
/*      sum {b in BOX} VolumeInsideBox_CFS[b,w]= sum {i in ISN,b in Box}Volume_ISN[i] * Proportion_CFS[b,w] * IS_ISN_MOL[i,'CFS'];*/
      sum {b in BOX} Proportion_CFS[b,w] = 1;

 

10. This constraint needs to hold for each b, not a sum over b:

/*   con BoxConCFS {w in T2}:*/
/*      sum {b in BOX} Volume_Capacity_CFS[b,w] * BOXNeeded_CFS[b,w] >= sum {b in BOX} TotalVol['CFS',w] * VolumeInsideBox_CFS[b,w];*/
   con BoxConCFS {w in T2, b in BOX}:
      Volume_Capacity_CFS[b,w] * BOXNeeded_CFS[b,w] >= VolumeInsideBox_CFS[b,w];

 

11. Both CREATE DATA statements refer to parameters that are not defined:

/*       VolBasedCost=VolBasedCost[i]   */
      VolBasedCost=VolBasedCost_CYS[i,b]  
      
/*       VolBasedCost=VolBasedCost[i]  */
      VolBasedCost=VolBasedCost_CFS[b,w] 

 

I recommend working these issues out with the toy data before attempting to solve with your full data.

Santha
Pyrite | Level 9

Rob

Thanks a lot for the comments and fixes. Here are my replies to your points. I will reply in the next thread about the model run results with these.

1) Yes. I have new BOX , Unique_T1 and Unique_T2 tables in model.  

2) The binary variable " Is_BoxAvalable_for_a_lane"  is not used in the model right now, but may be in future. So probably I can get rid of it as it does not get used in model. 

3) I have changed to like this based on the linkage between i and w: 

impvar VolumeInsideBox_CFS {b in BOX, w in T2} = sum{i in ISN:T2_ISN[i]=w} Volume_ISN[i] * Proportion_CFS[b,w];

4) Got it. Changed it.

5) Got the reason for non-linearity. Changed it.

6) Changed it like this below:  The only change is adding a clause of T2_ISN[i]=w so that only relevant ISN in that week are picked. Similar to approach taken for #3 above. 

impvar VolBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN:T2_ISN[i]=w} 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CFS[b,w];

7) I have removed Is_ISN_MOL.

😎Changed similar to #3 and #7 by removing Is_ISN_MOL and adding T2_ISN[i]=w

9) I am good with constraint SumProportiontoOne_CYS. But the constraint SumProportionOne_CFS i am not sure why you are adding the sum and enforcing it to be 1 on the right hand side. I would think this as saying forcing it via CFS? So i tried this one below but got syntax

issues:. 

/*sum {i in ISN:T2_ISN[i]=w,b in BOX} Proportion_CFS[b,w] = Is_ISN_MOL[i,'CFS'];*/

The idea of this constraint is to say if some ISNs are chosen by the model go via CFS, then only for those ISN's volume, when the model determines the asset mix, the proportion of the boxes should add up to 1. If CFS is not at all chosen for that week, then the proportion is 0. 

10) Got it. Changed it. 

11) Create Data step: Incorporated your changes

Here is my full code below:

proc optmodel;

set <str> ORG;
read data CASUSER.Unique_ORG into ORG = [ORG];

set <str> DES; 
read data CASUSER.Unique_DES into DES = [DES];

set <str> BOX; 
read data CASUSER.Unique_BOX into BOX = [BOX];

set <str> MOL; 
read data CASUSER.Unique_MOL into MOL = [MOL];

set <str> T1; 
read data CASUSER.Unique_T1 into T1 = [T1];

set <str> T2; 
read data CASUSER.Unique_T2 into T2 = [T2];

/*Read ISN Wt and Volume for a given ISN* - START */
set <str> ISN;
str Org_ISN {ISN};
str Des_ISN {ISN};
str T1_ISN {ISN};
str T2_ISN {ISN};
num Volume_ISN {ISN};
num Weight_ISN {ISN};

read data CASUSER.InputData_AssetMix into ISN=[ISN] Org_ISN=ORG Des_ISN=DES Volume_ISN=Volume Weight_ISN=Weight T1_ISN=T1 T2_ISN=T2;

/*Read ISN Wt and Volume for a given ISN* - END*/

/*Read Wt and Volume Capacity for a given ORG, DES, BOX - START */
num Volume_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
num Weight_Capacity {ORG,DES,BOX,MOL,T1,T2} init 0;  num Weight_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
read data CASUSER.BOXSPECS into [ORG DES BOX MOL T1 T2] 
Weight_Capacity=Weight_Capacity
Volume_Min=Volume_Min
Weight_Min=Weight_Min;

num Volume_Capacity {BOX}; 
read data CASUSER.BOXSPECS into [BOX] Volume_Capacity=Volume_Capacity;

num Volume_Capacity_CFS{BOX,T2};
read data CASUSER.BOXSPECS into [BOX T2] Volume_Capacity_CFS=Volume_Capacity;
/*Read Wt and Volume Capacity for a given ORG, DES, BOX - END */

/* Decision Variable - START */
var BOXNeeded_CYS {i in ISN,b in BOX} >= 0 integer <= ceil(Volume_ISN[i] / Volume_Capacity[b]);
var BOXNeeded_CFS {b in BOX,w in T2} integer >=0 <= ceil(sum {i in ISN} Volume_ISN[i] / Volume_Capacity[b]);
var Is_ISN_MOL{ISN,MOL} binary;

var Proportion_CYS {ISN,BOX} >= 0 <= 1;
impvar VolumeInsideBox_CYS {i in ISN, b in BOX} = Volume_ISN[i] * Proportion_CYS[i,b];

var Proportion_CFS {BOX,T2} >= 0 <= 1;
impvar VolumeInsideBox_CFS {b in BOX, w in T2} = sum{i in ISN:T2_ISN[i]=w} Volume_ISN[i] * Proportion_CFS[b,w];

impvar TotalVol {m in MOL,w in T2} = sum {i in ISN} Volume_ISN[i] * Is_ISN_MOL[i,m];
/*impvar VolumeInsideBox_CFS {b in BOX, w in T2}=TotalVol['CFS',w]*Proportion_CFS[b,w];*/


/* Decision Variable and Associated Impvars - END */

/*Define Rates and ImplicitVariables START */
/*Box Based Costs START */

set <str,str,str,str,str,str> PerBox_Based_Rate_NoZeroes;
num PerBox_Based_Rate {PerBox_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes=[ORG DES BOX MOL T1 T2] PerBox_Based_Rate=Rate;

impvar PerBox_Based_Costs_CYS {i in ISN} = sum {b in BOX}
PerBox_Based_Rate[Org_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]] * BOXNeeded_CYS[i,b];

set <str,str> PerBox_Based_Rate_NoZeroes_CFS;
num PerBox_Based_Rate_CFS {PerBox_Based_Rate_NoZeroes_CFS}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and 'CFS' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes_CFS=[BOX T2] PerBox_Based_Rate_CFS=Rate;

impvar PerBox_Based_Costs_CFS {w in T2} = sum {b in BOX} PerBox_Based_Rate_CFS[b,w] * BOXNeeded_CFS[b,w];
impvar TotalBoxBasedCost = sum {i in ISN} PerBox_Based_Costs_CYS[i] + sum {w in T2} PerBox_Based_Costs_CFS[w];

/*Box Based Costs END */
/*Vol Based Costs START*/
set <str,str,str,str,str> PerVol_Based_Rate_NoZeroes;
num PerVol_Based_Rate {PerVol_Based_Rate_NoZeroes} init 0; 
read data CASUSER.BOXRATE (where=(RateBasis="PerVolUOM" and Ratetype='Origin' and Rate>=0)) 
into PerVol_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerVol_Based_Rate=Rate;

impvar VolBasedCost_CYS {i in ISN, b in BOX} =
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CYS[i,b];

impvar VolBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN}
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CFS[b,w];

impvar TotalVolBasedCost = sum {i in ISN, b in BOX} VolBasedCost_CYS[i,b] + sum {b in BOX, w in T2}VolBasedCost_CFS[b,w];

/*Vol Based Costs END*/

/*Shipment Based Costs START*/
set <str,str,str,str,str> PerShp_Based_Rate_NoZeroes;
num PerShp_Based_Rate {PerShp_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerShipment" and Ratetype='Document' and Rate>=0)) 
into PerShp_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerShp_Based_Rate=Rate;

impvar ShipmentBasedCost_CYS {i in ISN, b in BOX} = Proportion_CYS[i,b] * 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]];


impvar ShipmentBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN:T2_ISN[i]=w} Proportion_CFS[b,w]*
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]];


impvar TotalShipmentBasedCost = sum {i in ISN, b in BOX} ShipmentBasedCost_CYS[i,b] + sum {b in BOX, w in T2}ShipmentBasedCost_CFS[b,w];
/*Shipment Based Costs END*/
/*Define Rates and ImplicitVariables END*/


Min TotalCost = TotalBoxBasedCost+ TotalVolBasedCost + TotalShipmentBasedCost;

/* Constraints START*/

con OneMOL{i in ISN}:
    sum{m in MOL} Is_ISN_MOL[i,m] = 1; /* This is to make sure one ISN can go either CYS or CFS */

con SumProportionToOne_CYS {i in ISN}:
      sum {b in BOX} Proportion_CYS[i,b] = IS_ISN_MOL[i,'CYS'];

con SumProportionToOne_CFS {w in T2}:
sum {b in BOX} Proportion_CFS[b,w] = 1;      
/*sum {i in ISN:T2_ISN[i]=w,b in BOX} Proportion_CFS[b,w] = Is_ISN_MOL[i,'CFS'];*/
/*expand SumProportionToOne_CFS;*/

con BoxConCYS {i in ISN, b in BOX}:
      Volume_Capacity[b] * BOXNeeded_CYS[i,b] >= VolumeInsideBox_CYS[i,b];




con BoxConCFS {w in T2, b in BOX}:
      Volume_Capacity_CFS[b,w] * BOXNeeded_CFS[b,w] >= VolumeInsideBox_CFS[b,w];
solve with milp / decomp=(method=concomp);

num optCYSCost {ISN,BOX};

for {i in ISN, b in BOX} optCYSCost[i,b] = PerBox_Based_Costs_CYS[i] + VolBasedCost_CYS[i,b] + ShipmentBasedCost_CYS[i,b];
print PerBox_Based_Costs_CYS VolBasedCost_CYS ShipmentBasedCost_CYS optCYSCost;

   num volShareCFS {i in ISN,w in T2} = Volume_ISN[i] * Is_ISN_MOL[i,'CFS'].sol / TotalVol['CFS',w].sol;

   print Is_ISN_MOL; 
   print BOXNeeded_CYS BOXNeeded_CFS;
   print PerBox_Based_Costs_CYS PerBox_Based_Costs_CFS;
   print volShareCFS VolBasedCost_CFS VolBasedCost_CYS TotalVolBasedCost TotalVol;
   print ShipmentBasedCost_CYS;
/* Output*/
create data CASUSER.SolutionDataCYS from [ISN=i BoxType=b]={i in ISN, b in BOX: BOXNeeded_CYS[i,b] > 0.5}
MOL='CYS'
Org=Org_ISN[i] 
Des=Des_ISN[i] 
T1=T1_ISN[i] 
T2=T2_ISN[i] 
Volume=Volume_ISN[i] 
Weight=Weight_ISN[i]
BoxNeeded=BOXNeeded_CYS 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CYS[i,b]
VolumeInsideBox=VolumeInsideBox_CYS[i,b]
VolShare=1
BoxBasedCost=(PerBox_Based_Rate[ORG_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]]*BOXNeeded_CYS[i,b]) 
VolBasedCost=VolBasedCost_CYS[i,b]   
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CYS[i,b])
;

create data CASUSER.SolutionDataCFS
(where=(VolShare>0)) from [ISN=i BoxType=b T2=w]={i in ISN, b in BOX, w in T2: BOXNeeded_CFS[b,w] > 0.5}
MOL='CFS' 
Org=Org_ISN[i] 
Des=Des_ISN[i] 
T1=T1_ISN[i] 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CFS[b,w]
VolumeInsideBox=VolumeInsideBox_CFS[b,w]
Weight=Weight_ISN[i]
BoxNeeded=(volShareCFS[i,w]*BOXNeeded_CFS[b,w]) 
Vol_InsideBox=Volume_ISN[i] 
VolShare=volShareCFS[i,w]
BoxBasedCost=(volShareCFS[i,w]*PerBox_Based_Rate_CFS[b,w]*BOXNeeded_CFS[b,w]) 
VolBasedCost=VolBasedCost_CFS[b,w] 
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CFS[b,w]);
quit;

Santha
Pyrite | Level 9

Rob 

Ok. With the non-linearity being removed, the model is running, in a very few seconds. I took two weeks worth of data (W369 and W371) for testing purposes as you recommended. I have tried to incorporate the changes you suggested to the best I could but I think I have not set it right. Here are my observations about the results. I request your support.  I will attach my results in the next one as it is not letting me in this reply.

1) The model routes everything via CFS. While this can happen, I highly doubt if the SumProportion_CFS forces it or some other constraints. When I removed this particular constraint, the model solves but the optimal cost is 0 which makes me think that the CYS costs/ constraints is not right.

2) BoxBasedCost : this looks right. the cost of a 40H is $4,863 and so this times 23 = $111,849 is there in BoxBasedCost column.

3)VolBasedCost and ShipmentBasedCost: This is not correct as the shipment volume is summed across all ISN combinations based on how i was able to write it. I know it is wrong but not able to fix it.

4) Overall Cost: The solver reports $9,536,945 as optimal. It cannot be this much and so this has to be same pattern as #3 above.

5) Create Data Step: I have this below because I wanted the "w" for T2 for CFS create data step. but it resulted in all combinations of T and D. In the results if I filter for W, I can see days that are not associated with W. that is W369 has D2577 and D2583 only. W371 has D2595,D2596 and D2597. 

create data CASUSER.SolutionDataCFS
(where=(VolShare>0)) from [ISN=i BoxType=b T2=w]={i in ISN, b in BOX, w in T2: BOXNeeded_CFS[b,w] 

6) Not able to test proportion  as the model decides everything via 40H. The VolShare for CYS is not 1. Basically, want to capture volume for all ISNs that is the input, if the model splits into multiple box types, what is the volume in each box type.  Like Volshare=VolumeInsideBox_CYS[i,b]/Volume_ISN[i]. 

Santha
Pyrite | Level 9

results of toy

RobPratt
SAS Super FREQ

For the syntax issue, the logical condition must appear last in the index set, and here are two correct approaches:

/* sum {i in ISN:T2_ISN[ i]=w,b in BOX} */
sum {i in ISN: T2_ISN[i]=w} sum {b in BOX}
sum {i in ISN, b in BOX: T2_ISN[i]=w}

 

For the second CREATE DATA statement, you want only the w for that i:

/*      (where=(VolShare>0)) from [ISN=i BoxType=b T2=w]={i in ISN, b in BOX, w in T2: BOXNeeded_CFS[b,w] > 0.5}*/
      (where=(VolShare>0)) from [ISN=i BoxType=b T2=w]={i in ISN, b in BOX, w in {T2_ISN[i]}: BOXNeeded_CFS[b,w] > 0.5}

 

For the remaining modeling issues, I recommend writing out the values of all decision variables and the resulting costs for a toy example, like you did in the spreadsheet before.  It is not clear to me what you want Proportion_CFS[b,w] to be, and I suspect you might instead want Proportion_CFS[i,b], where w = T2_ISN[i].

Santha
Pyrite | Level 9

Rob

Thank you. I have attached the desired solutions I would like to see.  I just put an example. It may not be optimal but the example is just to explain the outputs.  You can argue that in the case of CFS example (Cells A16 to S21), we could have sent it via CYS for a cheaper cost. Yes we could have and model could have chosen CYS based on the cost but the point I want to make is how I want to see the outputs. 

 

For CYS, it is just the ability to have the ISN split into multiple box types. In the attached example, you can see that  when the MOL ='CYS' (Cells A14 to S16), the output is seen as 2x40H and 1x20. The proportion of 40H is 0.95 (=152/160) and 20F is 0.05 (=8/160). Proportion of an ISN adds up to 1 for different box sizes. This is in the Vol_Share column. 

For CFS (Cells A16 to S21): The total volume is 155. Let us just assume model decides to ship it via 2x40H and 1x20, though in reality, the model may chose CYS for this 155 volume based on the rates. For explaining this CFS purpose, it is okay to turn off CYS as option temporarily. For now, lets just pretend it went via CFS. So there are 3 ISNs (v1, v2 and v3).  What I am trying to see is if it is a CFS, then for a given week (W1 in this example),  what are the ISNs that go to CFS for that week (v1, v2 and v3) along with what is their individual volume (v1=30, v2=40 and v3=85), consolidated volume (155 CBMs), what is the proportion between box types (=2/155 = 2% for 20F and 152/155 =98% for 40H) which adds up to 1. 

 

The logic is exactly same for CFS and CYS , with the only difference is that I would like to see for CFS, by ISN and box type  in the input, though in the model , for CFS variables, impvar and constraints, I am not sure of writing it correctly.  If this CFS thing output cannot be achieved, then whatever output view you recommend, I shall take it for sure. 

Hope this one helps. 

Thank you

 

 

Santha
Pyrite | Level 9

Here is my code . I have incorporated the filter for CFS filter and Create data step based on your recommendation. I feel close to the finish line.  Request you to look at this code and make amends as you see fit,  so that the impvars and variables are declared correctly and model solves. All the data elements like rate , box specs and input data all remain same.  Another thing is that though, the volume based cost is a costperVol * Volume for a given MOL this, I am trying to build the model so that  it can be used  for the combinations of it -  ORG, DES, MOL, BOX, T1 and T2 . Same is the case for other costs. So this is the full model in that sense that all the indices needs to be considered

proc optmodel;

set <str> ORG;
read data CASUSER.Unique_ORG into ORG = [ORG];

set <str> DES; 
read data CASUSER.Unique_DES into DES = [DES];

set <str> BOX; 
read data CASUSER.Unique_BOX into BOX = [BOX];

set <str> MOL; 
read data CASUSER.Unique_MOL into MOL = [MOL];

set <str> T1; 
read data CASUSER.Unique_T1 into T1 = [T1];

set <str> T2; 
read data CASUSER.Unique_T2 into T2 = [T2];

/*Read ISN Wt and Volume for a given ISN* - START */
set <str> ISN;
str Org_ISN {ISN};
str Des_ISN {ISN};
str T1_ISN {ISN};
str T2_ISN {ISN};
num Volume_ISN {ISN};
num Weight_ISN {ISN};

read data CASUSER.InputData_AssetMix into ISN=[ISN] Org_ISN=ORG Des_ISN=DES Volume_ISN=Volume Weight_ISN=Weight T1_ISN=T1 T2_ISN=T2;

/*Read ISN Wt and Volume for a given ISN* - END*/

/*Read Wt and Volume Capacity for a given ORG, DES, BOX - START */
num Volume_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
num Weight_Capacity {ORG,DES,BOX,MOL,T1,T2} init 0;  num Weight_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
read data CASUSER.BOXSPECS into [ORG DES BOX MOL T1 T2] 
Weight_Capacity=Weight_Capacity
Volume_Min=Volume_Min
Weight_Min=Weight_Min;

num Volume_Capacity {BOX}; 
read data CASUSER.BOXSPECS into [BOX] Volume_Capacity=Volume_Capacity;

num Volume_Capacity_CFS{BOX,T2};
read data CASUSER.BOXSPECS into [BOX T2] Volume_Capacity_CFS=Volume_Capacity;
/*Read Wt and Volume Capacity for a given ORG, DES, BOX - END */


/* A Binary variable that is 0 or 1 for a given asset for a given lane, 0 indicated not available, 1- available */
num Is_BoxAvalable_for_a_lane {ORG,DES,BOX,MOL,T1,T2};
read data CASUSER.BOXSpecs into [ORG Des Box Mol T1 T2] Is_BoxAvalable_for_a_lane = BoxAvailability;

/* Decision Variable - START */
var BOXNeeded_CYS {i in ISN,b in BOX} >= 0 integer <= ceil(Volume_ISN[i] / Volume_Capacity[b]);
var BOXNeeded_CFS {b in BOX,w in T2} integer >=0 <= ceil(sum {i in ISN} Volume_ISN[i] / Volume_Capacity[b]);
var Is_ISN_MOL{ISN,MOL} binary;

var Proportion_CYS {ISN,BOX} >= 0 <= 1;
impvar VolumeInsideBox_CYS {i in ISN, b in BOX} = Volume_ISN[i] * Proportion_CYS[i,b];

var Proportion_CFS {BOX,T2} >= 0 <= 1;
impvar VolumeInsideBox_CFS {b in BOX, w in T2} = sum{i in ISN:T2_ISN[i]=w} Volume_ISN[i] * Proportion_CFS[b,w];

impvar TotalVol {m in MOL,w in T2} = sum {i in ISN} Volume_ISN[i] * Is_ISN_MOL[i,m];
/*impvar VolumeInsideBox_CFS {b in BOX, w in T2}=TotalVol['CFS',w]*Proportion_CFS[b,w];*/


/* Decision Variable and Associated Impvars - END */

/*Define Rates and ImplicitVariables START */
/*Box Based Costs START */

set <str,str,str,str,str,str> PerBox_Based_Rate_NoZeroes;
num PerBox_Based_Rate {PerBox_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes=[ORG DES BOX MOL T1 T2] PerBox_Based_Rate=Rate;

impvar PerBox_Based_Costs_CYS {i in ISN} = sum {b in BOX}
PerBox_Based_Rate[Org_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]] * BOXNeeded_CYS[i,b];

set <str,str> PerBox_Based_Rate_NoZeroes_CFS;
num PerBox_Based_Rate_CFS {PerBox_Based_Rate_NoZeroes_CFS}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and 'CFS' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes_CFS=[BOX T2] PerBox_Based_Rate_CFS=Rate;

impvar PerBox_Based_Costs_CFS {w in T2} = sum {b in BOX} PerBox_Based_Rate_CFS[b,w] * BOXNeeded_CFS[b,w];
impvar TotalBoxBasedCost = sum {i in ISN} PerBox_Based_Costs_CYS[i] + sum {w in T2} PerBox_Based_Costs_CFS[w];

/*Box Based Costs END */
/*Vol Based Costs START*/
set <str,str,str,str,str> PerVol_Based_Rate_NoZeroes;
num PerVol_Based_Rate {PerVol_Based_Rate_NoZeroes} init 0; 
read data CASUSER.BOXRATE (where=(RateBasis="PerVolUOM" and Ratetype='Origin' and Rate>=0)) 
into PerVol_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerVol_Based_Rate=Rate;

impvar VolBasedCost_CYS {i in ISN, b in BOX} =
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CYS[i,b];

impvar VolBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN:T2_ISN[i]=w}
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CFS[b,w];

impvar TotalVolBasedCost = sum {i in ISN, b in BOX} VolBasedCost_CYS[i,b] + sum {b in BOX, w in T2}VolBasedCost_CFS[b,w];

/*Vol Based Costs END*/

/*Shipment Based Costs START*/
set <str,str,str,str,str> PerShp_Based_Rate_NoZeroes;
num PerShp_Based_Rate {PerShp_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerShipment" and Ratetype='Document' and Rate>=0)) 
into PerShp_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerShp_Based_Rate=Rate;

impvar ShipmentBasedCost_CYS {i in ISN, b in BOX} = Proportion_CYS[i,b] * 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]];


impvar ShipmentBasedCost_CFS {b in BOX, w in T2} = sum{i in ISN:T2_ISN[i]=w} Proportion_CFS[b,w]*
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]];


impvar TotalShipmentBasedCost = sum {i in ISN, b in BOX} ShipmentBasedCost_CYS[i,b] + sum {b in BOX, w in T2}ShipmentBasedCost_CFS[b,w];
/*Shipment Based Costs END*/
/*Define Rates and ImplicitVariables END*/


Min TotalCost = TotalBoxBasedCost+ TotalVolBasedCost + TotalShipmentBasedCost;

/* Constraints START*/

con OneMOL{i in ISN}:
    sum{m in MOL} Is_ISN_MOL[i,m] = 1; /* This is to make sure one ISN can go either CYS or CFS */

con SumProportionToOne_CYS {i in ISN}:
      sum {b in BOX} Proportion_CYS[i,b] = IS_ISN_MOL[i,'CYS'];

con SumProportionToOne_CFS {w in T2}:
sum {b in BOX} Proportion_CFS[b,w] = 1;      
/*sum {i in ISN:T2_ISN[i]=w,b in BOX} Proportion_CFS[b,w] = Is_ISN_MOL[i,'CFS'];*/
/*expand SumProportionToOne_CFS;*/

con BoxConCYS {i in ISN, b in BOX}:
      Volume_Capacity[b] * BOXNeeded_CYS[i,b] >= VolumeInsideBox_CYS[i,b];


con BoxConCFS {w in T2, b in BOX}:
      Volume_Capacity_CFS[b,w] * BOXNeeded_CFS[b,w] >= VolumeInsideBox_CFS[b,w];
solve with milp / decomp=(method=concomp);

num optCYSCost {ISN,BOX};

for {i in ISN, b in BOX} optCYSCost[i,b] = PerBox_Based_Costs_CYS[i] + VolBasedCost_CYS[i,b] + ShipmentBasedCost_CYS[i,b];
print PerBox_Based_Costs_CYS VolBasedCost_CYS ShipmentBasedCost_CYS optCYSCost;

   num volShareCFS {i in ISN,w in T2} = Volume_ISN[i] * Is_ISN_MOL[i,'CFS'].sol / TotalVol['CFS',w].sol;

   print Is_ISN_MOL; 
   print BOXNeeded_CYS BOXNeeded_CFS;
   print PerBox_Based_Costs_CYS PerBox_Based_Costs_CFS;
   print volShareCFS VolBasedCost_CFS VolBasedCost_CYS TotalVolBasedCost TotalVol;
   print ShipmentBasedCost_CYS;
/* Output*/
create data CASUSER.SolutionDataCYS from [ISN=i BoxType=b]={i in ISN, b in BOX: BOXNeeded_CYS[i,b] > 0.5}
MOL='CYS'
Org=Org_ISN[i] 
Des=Des_ISN[i] 
T1=T1_ISN[i] 
T2=T2_ISN[i] 
Volume=Volume_ISN[i] 
Weight=Weight_ISN[i]
BoxNeeded=BOXNeeded_CYS 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CYS[i,b]
VolumeInsideBox=VolumeInsideBox_CYS[i,b]
VolShare=1
BoxBasedCost=(PerBox_Based_Rate[ORG_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]]*BOXNeeded_CYS[i,b]) 
VolBasedCost=VolBasedCost_CYS[i,b]   
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CYS[i,b])
;

create data CASUSER.SolutionDataCFS
(where=(VolShare>0)) from [ISN=i BoxType=b T2=w]={i in ISN, b in BOX, w in {T2_ISN[i]}: BOXNeeded_CFS[b,w] > 0.5}
T1=T1_ISN[i] 
MOL='CFS' 
Org=Org_ISN[i] 
Des=Des_ISN[i] 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CFS[b,w]
VolumeInsideBox=VolumeInsideBox_CFS[b,w]
Weight=Weight_ISN[i]
BoxNeeded=(volShareCFS[i,w]*BOXNeeded_CFS[b,w]) 
Vol_InsideBox=Volume_ISN[i] 
VolShare=volShareCFS[i,w]
BoxBasedCost=(volShareCFS[i,w]*PerBox_Based_Rate_CFS[b,w]*BOXNeeded_CFS[b,w]) 
VolBasedCost=VolBasedCost_CFS[b,w] 
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CFS[b,w]);
quit;


data CASUSER.SolutionData;
   set CASUSER.SolutionDataCYS CASUSER.SolutionDataCFS;
   Total = BoxBasedCost + VolBasedCost + ShipmentBasedCost;
   Utilization = Volume/Volume_Capacity;
run;

proc print data=CASUSER.SolutionData;
   sum _numeric_;
run;
quit;
*/

 

Santha
Pyrite | Level 9

Rob

Today, I added the filters connecting i and w, like you recommended. Model is solving but the answers are not right. I have attached a spreadsheet which has the desired solutions. This spreadsheet should make it very clear. 

(a) CYS: For a given i and b, the proportion shd add up to 1. We shd be able to capture the volume inside box

(b) CFS: The proportion here, I changed to [i,b,w] and if you look at the spreadhseet it adds up to 1 for a given week, across all vendors and all box types. I have changed the constraints as well. 

I sincerely, request your support on getting this model work.  I am under pressure to get this delivered Monday.  Thank you as always.

 

proc optmodel;

set <str> ORG;
read data CASUSER.Unique_ORG into ORG = [ORG];

set <str> DES; 
read data CASUSER.Unique_DES into DES = [DES];

set <str> BOX; 
read data CASUSER.Unique_BOX into BOX = [BOX];

set <str> MOL; 
read data CASUSER.Unique_MOL into MOL = [MOL];

set <str> T1; 
read data CASUSER.Unique_T1 into T1 = [T1];

set <str> T2; 
read data CASUSER.Unique_T2 into T2 = [T2];

/*Read ISN Wt and Volume for a given ISN* - START */
set <str> ISN;
str Org_ISN {ISN};
str Des_ISN {ISN};
str T1_ISN {ISN};
str T2_ISN {ISN};
num Volume_ISN {ISN};
num Weight_ISN {ISN};

read data CASUSER.InputData_AssetMix into ISN=[ISN] Org_ISN=ORG Des_ISN=DES Volume_ISN=Volume Weight_ISN=Weight T1_ISN=T1 T2_ISN=T2;

/*Read ISN Wt and Volume for a given ISN* - END*/

/*Read Wt and Volume Capacity for a given ORG, DES, BOX - START */
num Volume_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
num Weight_Capacity {ORG,DES,BOX,MOL,T1,T2} init 0;  num Weight_Min {ORG,DES,BOX,MOL,T1,T2} init 0;
read data CASUSER.BOXSPECS into [ORG DES BOX MOL T1 T2] 
Weight_Capacity=Weight_Capacity
Volume_Min=Volume_Min
Weight_Min=Weight_Min;

num Volume_Capacity {BOX}; 
read data CASUSER.BOXSPECS into [BOX] Volume_Capacity=Volume_Capacity;

num Volume_Capacity_CFS{BOX,T2};
read data CASUSER.BOXSPECS into [BOX T2] Volume_Capacity_CFS=Volume_Capacity;
/*Read Wt and Volume Capacity for a given ORG, DES, BOX - END */


/* A Binary variable that is 0 or 1 for a given asset for a given lane, 0 indicated not available, 1- available */
num Is_BoxAvalable_for_a_lane {ORG,DES,BOX,MOL,T1,T2};
read data CASUSER.BOXSpecs into [ORG Des Box Mol T1 T2] Is_BoxAvalable_for_a_lane = BoxAvailability;

/* Decision Variable - START */
var BOXNeeded_CYS {i in ISN,b in BOX} >= 0 integer <= ceil(Volume_ISN[i] / Volume_Capacity[b]);
var BOXNeeded_CFS {b in BOX,w in T2} integer >=0 <= ceil(sum {i in ISN} Volume_ISN[i] / Volume_Capacity[b]);
var Is_ISN_MOL{ISN,MOL} binary;

var Proportion_CYS {ISN,BOX} >= 0 <= 1;
impvar VolumeInsideBox_CYS {i in ISN, b in BOX} = Volume_ISN[i] * Proportion_CYS[i,b];

var Proportion_CFS {ISN,BOX,T2} >= 0 <= 1;
impvar VolumeInsideBox_CFS {b in BOX,w in T2} = sum{i in ISN:t2_ISN[i]=w}Volume_ISN[i] * Proportion_CFS[i,b,w];

impvar TotalVol {m in MOL,w in T2} = sum {i in ISN} Volume_ISN[i] * Is_ISN_MOL[i,m];

/* Decision Variable and Associated Impvars - END */

/*Define Rates and ImplicitVariables START */
/*Box Based Costs START */

set <str,str,str,str,str,str> PerBox_Based_Rate_NoZeroes;
num PerBox_Based_Rate {PerBox_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes=[ORG DES BOX MOL T1 T2] PerBox_Based_Rate=Rate;

impvar PerBox_Based_Costs_CYS {i in ISN} = sum {b in BOX}
PerBox_Based_Rate[Org_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]] * BOXNeeded_CYS[i,b];

set <str,str> PerBox_Based_Rate_NoZeroes_CFS;
num PerBox_Based_Rate_CFS {PerBox_Based_Rate_NoZeroes_CFS}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerBox" and Ratetype='Linehaul' and 'CFS' and Rate>0)) 
into PerBox_Based_Rate_NoZeroes_CFS=[BOX T2] PerBox_Based_Rate_CFS=Rate;

impvar PerBox_Based_Costs_CFS {w in T2} = sum {b in BOX} PerBox_Based_Rate_CFS[b,w] * BOXNeeded_CFS[b,w];
impvar TotalBoxBasedCost = sum {i in ISN} PerBox_Based_Costs_CYS[i] + sum {w in T2} PerBox_Based_Costs_CFS[w];

/*Box Based Costs END */
/*Vol Based Costs START*/
set <str,str,str,str,str> PerVol_Based_Rate_NoZeroes;
num PerVol_Based_Rate {PerVol_Based_Rate_NoZeroes} init 0; 
read data CASUSER.BOXRATE (where=(RateBasis="PerVolUOM" and Ratetype='Origin' and Rate>=0)) 
into PerVol_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerVol_Based_Rate=Rate;

impvar VolBasedCost_CYS {i in ISN, b in BOX} =
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CYS[i,b];

impvar VolBasedCost_CFS {b in BOX, w in T2}=sum {i in ISN:T2_ISN[i]=w}
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerVol_Based_Rate_NoZeroes} 
      PerVol_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]] * VolumeInsideBox_CFS[b,w];

impvar TotalVolBasedCost = sum {i in ISN, b in BOX} VolBasedCost_CYS[i,b] + sum{i in ISN,b in BOX, w in T2:T2_ISN[i]=w}VolBasedCost_CFS[b,w];

/*Vol Based Costs END*/

/*Shipment Based Costs START*/
set <str,str,str,str,str> PerShp_Based_Rate_NoZeroes;
num PerShp_Based_Rate {PerShp_Based_Rate_NoZeroes}; 
read data CASUSER.BOXRATE (where=(RateBasis="PerShipment" and Ratetype='Document' and Rate>=0)) 
into PerShp_Based_Rate_NoZeroes=[ORG DES MOL T1 T2] PerShp_Based_Rate=Rate;

impvar ShipmentBasedCost_CYS {i in ISN, b in BOX} = Proportion_CYS[i,b] * 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]];


impvar ShipmentBasedCost_CFS {i in ISN, b in BOX, w in T2:T2_ISN[i]=w} = 
      sum {<Org_ISN[i],Des_ISN[i],m,T1_ISN[i],T2_ISN[i]> in PerShp_Based_Rate_NoZeroes} 
PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]]*Proportion_CFS[i,b,w];


impvar TotalShipmentBasedCost = sum {i in ISN, b in BOX} ShipmentBasedCost_CYS[i,b] + sum{i in ISN,b in BOX, w in T2:T2_ISN[i]=w} ShipmentBasedCost_CFS[i,b,w];
/*Shipment Based Costs END*/
/*Define Rates and ImplicitVariables END*/


Min TotalCost = TotalBoxBasedCost+ TotalVolBasedCost + TotalShipmentBasedCost;

/* Constraints START*/

con OneMOL{i in ISN}:
    sum{m in MOL} Is_ISN_MOL[i,m] = 1; /* This is to make sure one ISN can go either CYS or CFS */

con SumProportionToOne_CYS {i in ISN}:
      sum {b in BOX} Proportion_CYS[i,b] = IS_ISN_MOL[i,'CYS'];

con SumProportionToOne_CFS {w in T2}:
sum {b in BOX,i in ISN:T2_ISN[i]=w} Proportion_CFS[i,b,w] = 1;      

con BoxConCYS {i in ISN, b in BOX}:
      Volume_Capacity[b] * BOXNeeded_CYS[i,b] >= VolumeInsideBox_CYS[i,b];

con BoxConCFS {w in T2, b in BOX}:
      Volume_Capacity_CFS[b,w] * BOXNeeded_CFS[b,w] >= VolumeInsideBox_CFS[b,w];

expand BoxConCFS;


solve with milp / decomp=(method=concomp);

num optCYSCost {ISN,BOX};

for {i in ISN, b in BOX} optCYSCost[i,b] = PerBox_Based_Costs_CYS[i] + VolBasedCost_CYS[i,b] + ShipmentBasedCost_CYS[i,b];
print PerBox_Based_Costs_CYS VolBasedCost_CYS ShipmentBasedCost_CYS optCYSCost;

   num volShareCFS {i in ISN,w in T2} = Volume_ISN[i] * Is_ISN_MOL[i,'CFS'].sol / TotalVol['CFS',w].sol;

   print Is_ISN_MOL; 
   print BOXNeeded_CYS BOXNeeded_CFS;
   print PerBox_Based_Costs_CYS PerBox_Based_Costs_CFS TotalBoxBasedCost;
   print volShareCFS VolBasedCost_CFS VolBasedCost_CYS TotalVolBasedCost TotalVol;
   print ShipmentBasedCost_CYS ShipmentBasedCost_CFS TotalShipmentBasedCost;

/* Output*/
create data CASUSER.SolutionDataCYS from [ISN=i BoxType=b]={i in ISN, b in BOX: BOXNeeded_CYS[i,b] > 0.5}
MOL='CYS'
Org=Org_ISN[i] 
Des=Des_ISN[i] 
T1=T1_ISN[i] 
T2=T2_ISN[i] 
Volume=Volume_ISN[i] 
Weight=Weight_ISN[i]
BoxNeeded=BOXNeeded_CYS 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CYS[i,b]
VolumeInsideBox=VolumeInsideBox_CYS[i,b]
VolShare=1
BoxBasedCost=(PerBox_Based_Rate[ORG_ISN[i],Des_ISN[i],b,'CYS',T1_ISN[i],T2_ISN[i]]*BOXNeeded_CYS[i,b]) 
VolBasedCost=VolBasedCost_CYS[i,b]   
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CYS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CYS[i,b])
;

create data CASUSER.SolutionDataCFS
(where=(VolShare>0)) from [ISN=i BoxType=b T2=w]={i in ISN, b in BOX, w in {T2_ISN[i]}: BOXNeeded_CFS[b,w] > 0.5}
T1=T1_ISN[i] 
MOL='CFS' 
Org=Org_ISN[i] 
Des=Des_ISN[i] 
ShipmentVolume=Volume_ISN[i] 
Proportion=Proportion_CFS[i,b,w]
VolumeInsideBox=VolumeInsideBox_CFS[b,w]
Weight=Weight_ISN[i]
BoxNeeded=(volShareCFS[i,w]*BOXNeeded_CFS[b,w]) 
Vol_InsideBox=Volume_ISN[i] 
VolShare=volShareCFS[i,w]
BoxBasedCost=(volShareCFS[i,w]*PerBox_Based_Rate_CFS[b,w]*BOXNeeded_CFS[b,w]) 
VolBasedCost=VolBasedCost_CFS[b,w] 
ShipmentBasedCost=PerShp_Based_Rate[Org_ISN[i],Des_ISN[i],'CFS',T1_ISN[i],T2_ISN[i]]
Volume_Capacity=(Volume_Capacity[b]*BOXNeeded_CFS[b,w]);
quit;


data CASUSER.SolutionData;
   set CASUSER.SolutionDataCYS CASUSER.SolutionDataCFS;
   Total = BoxBasedCost + VolBasedCost + ShipmentBasedCost;
   Utilization = Volume/Volume_Capacity;
run;

/*proc print data=CASUSER.SolutionData;
   sum _numeric_;
run;
quit;
*/
RobPratt
SAS Super FREQ

I already replied to Santha in response to a private message, but for the benefit of the rest of the community, here was my recommendation:

 

The introduction of Proportion into the optimization model seems to complicate things.  I recommend going back to the model that you said worked smoothly last Saturday (https://communities.sas.com/t5/Mathematical-Optimization/AssetOpt-OutputViews-FullModel/td-p/885576) and computing Proportion after the fact if you need it for reporting.

SAS Innovate 2025: Call for Content

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!

Submit your idea!

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
  • 13 replies
  • 5249 views
  • 0 likes
  • 2 in conversation