Originally posted by: flywithme
how to make the model below better and define search phase to improve search efficency?
I am a newbie to CP, and now try to learn modeling with OPL, so please give me some suggesttion for my model.
The problem below is something like a vehicle pickup and delivery problem.
there are customers' goods needed to be picked up and delivered to depot sites, for each customer, there are opportunities to collect goods constrained by time windows , for the vehicle, there is a maximal capacity to load the goods. there are also some delivery time windows for the vehicle to delivery the goods to depot site. The goods must be dilivered as a whole(cannot be split). the scheduling objective is to maximize the value of goods collected and delivered.
If the goods can be pickup and delivery at the same time, i.e. the pickup time window lines within the delivery time window,we call the pickup alternative a real time pickup, the real time pickup task must have the same execute time as delivery task. In the model data file, we have marked such pickup opportunity with a 'type' column.
The attachments are my model and sample data. for read convenience, I paste the model here. I want to know how to how to make the model below better and define search phase to improve search efficency?
using CP;
//Pickup task for Custom
tuple Pickup {
key int Id; //custom id
int Duration;//pickup times for custom
int Capacity;//capacity required for custom
int Priority;//priority of custom
int DeliveryDuration; //delivery times for custom
};
//Pickup Alternative Data for each custom
tuple PickupAlternativeData{
key int Id; // opportunity Id
int CustomId; // custom id
int StartMin;//earlist possible start time
int EndMax; // latest possible end time
int Type; //realtime opportunity ? 0 = no; 1 = yes;
};
//Pick up Alternative for each custom (combine Pickup and PickupAlternativeData together to avoid redundant input datas)
tuple PickupAlternative{
key int Id; // opportunity Id
int CustomId; // custom id
int StartMin;//earlist possible start time
int EndMax; // latest possible end time
int Duration;//pickup time for custom
int Capacity;//capacity required for custom
int Priority;//priority of custom
int Type; //delivery time for custom
};
{Pickup} Pickups = ...;
{PickupAlternativeData}PickupAlternativeDatas = ...;
{PickupAlternative} PickupAlternatives = {<j.Id,j.CustomId,j.StartMin,j.EndMax,
i.Duration,i.Capacity,i.Priority,j.Type> | i in Pickups, j in PickupAlternativeDatas : i.Id == j.CustomId};
//Delivery Alternative Data for vehicle
tuple DeliveryAlternativeData {
int PickupAltId; //Custom Pickup Opportunity Id
int CustomId; //Custom Id
int WindowId; //Vehicle's Delivery TimeWindow Id
};
//Delivery Time Window for vehicle
tuple DeliveryWindow
{
key int Id; //Vehicle's Delivery TimeWindow Id
int WindowStart; //Window Start Time
int WindowEnd; //Window End Time
}
{DeliveryWindow} DeliveryWindows = ...;
{DeliveryAlternativeData}DeliveryAlternativeDatas = {<i.Id,i.CustomId,j.Id> | i in PickupAlternatives,j in DeliveryWindows : i.StartMin + i.Duration <= j.WindowEnd};
//Delivery Alternative for each custom
tuple DeliveryAlternative{
int CustomId;
int WindowId;
int WindowStart;
int WindowEnd;
int Capacity;
int DeliveryDuration;
};
{DeliveryAlternative} DeliveryAlternatives = {<i.CustomId,i.WindowId,w.WindowStart,w.WindowEnd,j.Capacity,j.DeliveryDuration> |
i in DeliveryAlternativeDatas, j in Pickups, w in DeliveryWindows : i.CustomId == j.Id && i.WindowId == w.Id};
//Storage Capacity of vehicle
int StorageCapacity = ...;
{int} DeliveryWindowStart
j in Pickups = {jj.WindowStart|jj in DeliveryAlternatives : jj.CustomId == j.Id};
{int} DeliveryWindowEnd
j in Pickups = {jj.WindowEnd|jj in DeliveryAlternatives : jj.CustomId == j.Id};
{int} PickupWindowStart
j in Pickups = {jj.StartMin|jj in PickupAlternatives : jj.CustomId == j.Id};
{int} PickupWindowEnd
j in Pickups = {jj.EndMax|jj in PickupAlternatives : jj.CustomId == j.Id};
tuple Step { int x; int y; }
sorted{Step} StepsDeliverys
j in Pickups = { <x,0> | x in DeliveryWindowStart[j] } union { <x,100> | x in DeliveryWindowEnd[j]};
//Caledar for each custom's delivery
stepFunction CalendarDeliverys
j in Pickups = stepwise(s in StepsDeliverys[j]) {s.y -> s.x; 0};
sorted{Step} StepsPickups
j in Pickups = { <x,0> | x in PickupWindowStart[j] } union { <x,100> | x in PickupWindowEnd[j]};
//Caledar for each custom's pickup
stepFunction CalendarPickups
j in Pickups = stepwise(s in StepsPickups[j]) {s.y -> s.x; 0};
dvar interval DeliveryIntervals
i in Pickups optional size i.DeliveryDuration;
dvar interval DeliveryAltIntervals
i in DeliveryAlternatives optional in i.WindowStart..i.WindowEnd size i.DeliveryDuration;
dvar interval PickupIntervals
i in Pickups optional size i.Duration;
dvar interval PickupAltIntervals
i in PickupAlternatives optional in i.StartMin..i.EndMax size i.Duration;
cumulFunction CapacityUsage = sum(j in Pickups) stepAtStart(PickupIntervals[j], j.Capacity) - sum(j in Pickups) stepAtStart(DeliveryIntervals[j], j.Capacity);
maximize
sum(j in Pickups)(presenceOf(PickupIntervals[j]) * j.Priority ) ;
subject to{
forall(i in Pickups)
{
// for each custom , only one pickup can be scheduled
alternative(PickupIntervals[i],all(j in PickupAlternatives : j.CustomId == i.Id) PickupAltIntervals[j]);
// for each custom, only one delivery can be scheduled
alternative(DeliveryIntervals[i],all(j in DeliveryAlternatives : j.CustomId == i.Id) DeliveryAltIntervals[j]);
//if Pickup job is scheduled , its Delivery job must also be scheduled
presenceOf(PickupIntervals[i]) => presenceOf(DeliveryIntervals[i]);
presenceOf(DeliveryIntervals[i]) => presenceOf(PickupIntervals[i]);
//delivery job start after pickup
endBeforeStart(PickupIntervals[i],DeliveryIntervals[i]);
//each Delivery job can only be scheduled in its time windows
forbidExtent(DeliveryIntervals[i],CalendarDeliverys[i]);
//each Pickup job can only be scheduled in its time windows
forbidExtent(PickupIntervals[i],CalendarPickups[i]);
}
//real time Pickup job must have the same time as Delivery job
forall(i in PickupAlternatives : i.Type == 1)
{
synchronize(PickupAltIntervals[i],all(j in Pickups : i.CustomId == j.Id)DeliveryIntervals[j]);
}
//First in First out for pickup and delivery
forall(j in Pickups)
forall(jj in Pickups : jj != j)
startOf(PickupIntervals[j]) >= endOf(PickupIntervals
jj) => startOf(DeliveryIntervals[j]) >= endOf(DeliveryIntervals
jj);
//Storage Capacity
alwaysIn(CapacityUsage, 0, maxint, 0, StorageCapacity);
//no overlap of Pickup tasks, because of FiFo constraints, no need to define noOverlap constraints on Delivery intervals
noOverlap(all(j in Pickups) PickupIntervals[j]);
}
#DecisionOptimization#OPLusingCPOptimizer