1

The goal of the opl model below is to choose the freights with total minimum cost to fulfill all orders, I have a constraint of the order on a freight must be delivered to <= 2 clientId. Currently the optimal solution is to use the third freight for all orders (since it's the cheapest), but with the new constraint, the 3rd freight can carry at most two orders (since each order is for different clientId). but how to encode that constraint?

current .mod file (model file)

tuple TFreightTypes {
  key string Destination;
  key string VehicleType;
  int TotalWeight;
  key string Company;
  int Cost;
};

tuple TOrders {
  key int OrderNumber;
  float Weight;
  string ClientId;
  string Destination;
  string MaterialCategory;
  int CategoryPriority;
};

{TFreightTypes}    FreightTypes = ...;
{TOrders}    Orders = ...;


dvar boolean Assignment[Orders][FreightTypes];


dexpr float objective = 
  sum(o in Orders, f in FreightTypes)
     Assignment[o][f] * f.Cost;


//choose freight with total minimum cost
minimize objective;


subject to{

  //c1: all order must be fulfilled
  forall(o in Orders)
    sum(f in FreightTypes) Assignment[o][f]==1;
    
  //c2: the order on a freight must be less than 2 destination
   
}

.dat file (data file)

FreightTypes = {
    <"LONDON","Type1",20000,"SP TRANSPORTS",40000>,
    <"LONDON","Type2",20000,"SP TRANSPORTS",40000>,
    <"DURHAM","Type3",10000,"SP TRANSPORTS",30000>,

};
Orders = {
    <1,5000,"Client1","LONDON","A",0>,
    <2,1000,"Client2","DURHAM","B",1>,
    <3,2000,"Client3","LONDON","C",1>,      

};
 
william007
  • 17,375
  • 25
  • 118
  • 194

1 Answers1

1

You can write

//c2: the orders on a freight must be less than 2 
  forall(f in FreightTypes)
    ctMax2:
      sum(o in Orders) Assignment[o][f]<=2;

and 2 comply with the 2 destinations, the complete model could look like

tuple TFreightTypes {
  key string Destination;
  key string VehicleType;
  int TotalWeight;
  key string Company;
  int Cost;
};

tuple TOrders {
  key int OrderNumber;
  float Weight;
  string ClientId;
  string Destination;
  string MaterialCategory;
  int CategoryPriority;
};



{TFreightTypes}    FreightTypes = ...;
{TOrders}    Orders = ...;


dvar boolean Assignment[Orders][FreightTypes];


dexpr float objective = 
  sum(o in Orders, f in FreightTypes)
     Assignment[o][f] * f.Cost;

{string} destinations={i.Destination | i in Orders};

dvar boolean Destination[FreightTypes][destinations];


//choose freight with total minimum cost
minimize objective;


subject to{
  
  forall(f in FreightTypes,d in destinations)
    Destination[f][d]==(1<=sum(o in Orders:o.Destination==d)Assignment[o][f]);

  //c1: all order must be fulfilled
  forall(o in Orders)
    sum(f in FreightTypes) Assignment[o][f]==1;
    
  //c2: the order on a freight must be less than 2 destinations
  forall(f in FreightTypes)
    ctMax2:
      sum(d in destinations) Destination[f][d]<=2;
   
}
Alex Fleischer
  • 9,276
  • 2
  • 12
  • 15
  • I does not look right since it’s not one freight has at most two order – william007 Jun 24 '22 at 09:36
  • Right, I updated the model. – Alex Fleischer Jun 24 '22 at 09:52
  • Thanks that works! with that catch that destination needs to switch to client Id. Another question is would `dvar boolean Destination` be misleading here since it's not strictly a decision variable? – william007 Jun 24 '22 at 11:55
  • Destination is a decision variable. You could remove it if you replace Destination[f][d] in the constraint with (1<=sum(o in Orders:o.Destination==d)Assignment[o][f]) but then the model is harder to read for us (human beings) – Alex Fleischer Jun 24 '22 at 12:20