Adding shipments to a initial route throws exception at VehicleRoute.Builder.build()

Hi,

I am trying to run the optimizer while vehicles still have shipments to pick up and deliveries to (obviously) deliver. However, the optimizer throws an exception when I run VehicleRoute.Builder.build():

java.lang.IllegalArgumentException: there are still shipments that have not been delivered yet.
at com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute$Builder.build(VehicleRoute.java:298)

The code runs fine if I choose to not add shipments to the initial route. Code structure given below:

VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
    vrpBuilder.setRoutingCost(costMatrix);

    for (int i = 0; i < vehicles.size(); i++) {
        VehicleType vehicleType = VehicleTypeImpl.Builder.newInstance("vehicleType" + i)
                // *** foo ***
                .build();

        VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle" + i)
                // *** foo ***
                .setType(vehicleType)
                .build();

        vrpBuilder.addVehicle(vehicle);

        VehicleRoute.Builder initialRoute = VehicleRoute.Builder.newInstance(vehicle);
        for (int j = 0; j < assignedPackages.size(); j++) {
            // check if package is picked up yet
            if ( !assignedPackIsPicked.get(i) ) {
                Shipment shipment = Shipment.Builder.newInstance("" + i)
                        // *** foo ***
                        .build();
                vrpBuilder.addJob(shipment);
                initialRoute.addPickup(shipment);  // remove this line, and the optimizer runs fine, but without the shipments it should pick up
            }
            else {
                Delivery service = Delivery.Builder.newInstance("" + i)
                        // *** foo ***
                        .build();
                vrpBuilder.addJob(service);
                initialRoute.addService(service);
            }
        }

        vrpBuilder.addInitialVehicleRoute(initialRoute.build());  // exception thrown here
    }

I have tried finding a solution to it for quite some time now, without success. Can anyone help with this?

EDIT: Wanted to add, that I am using JSprit 1.7-RC1

Hi @PHillner,

Unfortunately you cannot build an initial route which has shipments that are picked up but not delivered.

If you would like to model such case, you might have to model such shipments as pairs of pickup and delivery jobs, and add those pickups in the initial routes. However, you will need a hard constraint to make sure those deliveries will be in the same routes as the corresponding pickups and be inserted after them. Moreover, there might be issues with capacity constraint - in jsprit, a pickup job means the unloading happens at the end of the route, and a delivery job means the loading happens at the beginning of the route.

Best regards,
He

Aah, I see. So in addition to having “addPickup”, I would need “addDelivery” for the same shipment?

However, you will need a hard constraint to make sure those deliveries will be in the same routes as the corresponding pickups and be inserted after them.

That would explain how the assigned jobs, that weren’t yet picked up, were able to switch vehicles in my simulations.

Moreover, there might be issues with capacity constraint - in jsprit, a pickup job means the unloading happens at the end of the route, and a delivery job means the loading happens at the beginning of the route.

That, indeed, is an issue. Do you think it would be possible, sometime in the future, to implement shipments to the initial route, the way you similarly add shipments to the VehicleRoute as a job? In other words, instead of using “initialRoute.addPickup(shipment)” and/or “.addDelivery(shipment)”, you could use “.addShipment(shipment)”.

I found a way to implement shipments to the initial route (sort of). As some shipments have already been assigned to a ship by a previous optimization, I used the skill implementation to force each shipment to the ship it was assigned to. The string used was the string you feed the constructor/newInstance -method of VehicleImpl.Builder, which works as an id of sorts.
Basically, since each vehicle has their own id, having that id for each pre-assigned shipments’ required skill will give only one choice for the shipments to be assigned to by the optimizer.

1 Like