Compartment Routing

Hello,

Trying to implement compartment routing with JSPRIT.

A compartment is defined on Vehicle Type level, each compartment can hold items of certain item type .
Example: a vehicle can have 2 compartments, FROZEN and CHILLED , some items have item type FROZEN and other items have item type CHILLED. When creating a route, routing algorithm should send vehicles with empty space in specific compartment to service orders of items of specific item type.

Any suggestions on how to implement this? or whether it is achievable or not ?

Thank you,
Karim

This can be implemented using CapacityDimension for VehicleType and SizeDimension for Shipment and Service orders.

Thanks for the reply, this will only check whether a service of certain Size can fit in a truck of certain Capacity.
However, how will the algorithm understand that the capacity is split into 2 compartments, and the service order contains items that can only be stored in one of either compartments and can’t be stored in the other.

Thank you,
Karim

That is why you can use multiple indices to specify which dimension or compartment has this capacity. For instance, if you have space for 4 boxes in the FROZEN compartment and 10 in the CHILLED, you can give the data to the VehicleType as in the following example:

vehicleType = VehicleTypeImpl.Builder.newInstance("type1")
    .addCapacityDimension(0, 4) // FROZEN
    .addCapacityDimension(1, 10) // CHILLED
    .build();

Then if you have a box that absolutely has to be in the frozen compartment, you can do the following:

service = Service.Builder.newInstance("service1")
    .addSizeDimension(0, 1) // FROZEN
    .build();

By leaving out the other dimension(s), they take the value of 0. This mean that the above code will give the following SizeDimensions for service1:

  • 1 frozen
  • 0 chilled

/Patrik

Thanks again for the reply, this is very logical.

My understanding of index usage in Vehicle Type Capacities was to accommodate for different units of measure.
For example:
Index 0 will be for vehicle capacity in Cases
Index 1 will be for vehicle capacity in KGs

and so on.

if i utilize the indexes to accommodate for compartments, how can I add different units of measure too ?

would it be index 0 : Frozen Cases , index 1: Chilled Cases , index 2: Frozen KGs, index 3: Chilled KGs ??
in that case how will order I define the order ?

Karim.

After pondering this for a while, I believe using 6 indices would be the way to go (I could be wrong).

  • 0, All Frozen space (maybe area, volume, or weight)
  • 1, All Chilled space (maybe area, volume, or weight)
  • 2, Frozen Cases
  • 3, Chilled Cases
  • 4, Frozen KGs
  • 5, Chilled KGs

Where the 2 first indices are used to make sure that you can pack both cases and KGs in, but not above a certain treshhold. If the VehicleType is made to only carry either cases or KGs, then these two indices won’t necessarily be needed.

The code would then look like this for a chilled KG of weight 500:

service = Service.Builder.newInstance("service1")
    .addSizeDimension(1, 500) // CHILLED WEIGHT
    .addSizeDimension(5, 1) // CHILLED KG
    .build();

Similarly, building the VehicleType (if it can carry both cases and KGs):

vehicleType = VehicleTypeImpl.Builder.newInstance("type1")
    .addCapacityDimension(0, 1000) // FROZEN WEIGHT
    .addCapacityDimension(1, 3600) // CHILLED WEIGHT
    .addCapacityDimension(2, 4) // FROZEN CASES
    .addCapacityDimension(3, 10) // CHILLED CASES
    .addCapacityDimension(4, 8) // FROZEN KGs (are smaller, can pack more of these)
    .addCapacityDimension(5, 20) // CHILLED KGs (are smaller, can pack more of these)
    .build();

Does this help?

/Patrik

Hello Patrik,

Yes sure this helps ! I will test it with a few orders I have and get back to you with results.
I will try something along these lines:

0, All Cases
1, All KGs
2, Frozen Cases
3, Chilled Cases
4, Frozen KGs
5, Chilled KGs

vehicleType = VehicleTypeImpl.Builder.newInstance(“type1”)
.addCapacityDimension(0, 1000) // Total Cases
.addCapacityDimension(1, 3600) // Total KGs
.addCapacityDimension(2, 500) // FROZEN CASES
.addCapacityDimension(3, 500) // CHILLED CASES
.addCapacityDimension(4, 2000) // FROZEN KGs
.addCapacityDimension(5, 1600) // CHILLED KGs
.build();

The sum of compartments should add up to total capacity : 500 Chilled + 500 Frozen should come up to 1000 Total cases, and so on…

Then to build an order with 20 Chilled cases ( that happen to translate to 5 KGs ) and 30 Frozen Cases (That happen to translate to 10KGs) would be:

service = Service.Builder.newInstance(“service1”)
.addSizeDimension(0, 50) // Total of 50 Cases (20+30)
.addSizeDimension(1, 15) // Total of 15 KGs(5+10)
.addSizeDimension(2, 20) // CHILLED Cases
.addSizeDimension(3, 30) // FROZEN Cases
.addSizeDimension(4, 5) // Chilled KGs
.addSizeDimension(5, 10) // Frozen KGs
.build();

What do you think ?

Karim.

Won’t indices 0 and 1 become redundant if they only constrain the sum of the cases respective KGs?

/Patrik

True, then only last 4 are required ? can’t seem to understand why the first two are needed then

Karim

I might have written my last comment a little odd. What I meant, with using the first two as constraints for total space/mass available, was that within the frozen area, you can fit either fully with cases, fully with KGs, or fully with a mix of cases and KGs.
Therefore, what we are interested in is how much space of the frozen area do both cases and KGs take together. We may not need to know how many cases or KGs we have in total in a service.

I would then, before creating the services, calculate how much space these KGs take space in each areas.

So the Service should be written as something like:

service = Service.Builder.newInstance("service1")
    .addSizeDimension(0, y) // Total of 25 CHILLED (20+y1)
    .addSizeDimension(1, x) // Total of 40 FROZEN (30+x1)
    .addSizeDimension(2, 20) // CHILLED Cases
    .addSizeDimension(3, 30) // FROZEN Cases
    .addSizeDimension(4, 5) // Chilled KGs
    .addSizeDimension(5, 10) // Frozen KGs
    .build();

Where y1 and x1 are the amount of space they take if they were cases, and y and x are the total area available as cases. Note, you can do this other ways. This is only my thought to a solution.

/Patrik

Hello Patrik,

Thanks for your time,

I have looked more into this, and can’t seem to have found the best solution yet, I want to build this in a way that enables the user to define as many compartments as required.


Total: | 200 CASES | 500 KGS | 700 LITERES


Comp1: | 150 CASES| 400 KGs | 250 LITERES


Remaining:| 50 CASES | 100 KGs | 450 LITERES


in the example above, 3 sizes are defined and 1 compartment is added (comp1) the remaining will be added as another compartment by default by the software to take items that don’t require a compartment.

I can’t seem to get a final idea, until I get this written in code, I won’t be able to give a clear picture to you.

Thanks.
Karim.

Aah, okay. Then I think your latest code suggestion should work. Aka, this:

Though I would recommend to have all indices for the same compartment beside each other, to keep some sort of organization. It also would ease automation of inserting different compartments, in case it’s not manually inserted every time, but from an external software.

/Patrik