HardConstraint Basics Bike Sharing System problem

Hello all,

First of all, thank you for your help in advance!

I’m triying to solve a BikeSharing reallocation problem with JSPRIT and their HardConstraints.

The idea of the problem is the following:

Multiple customers who have shipments and deliveries (The bike stations which need be rebalanced taking or putting bikes).

The trucks have a fixed capacity (e.g 10 bikes). In this case, the transported commodity is the same. For instance, bikes picked from a station could be put in other station in the same route.

Following the example in the documentation (MultipleProductsWithLoadConstraintExample) I have tried to adapt it to my problem:

public class SingleProductWithRouteConstraintExample {

private static final Logger logger = LoggerFactory.getLogger(VehicleRoutingAlgorithm.class);
static final int BIKES_DIMENSION_INDEX = 0;

//static class EnoughPickupsForDeliveriesimplements HardActivityStateLevelConstraint { //v1.3.1
static class EnoughPickupsForDeliveriesimplements HardActivityConstraint {

    private StateManager stateManager;

    EnoughPickupsForDeliveries(StateManager stateManager) {
        this.stateManager = stateManager;
    }

    private boolean hasBikesInVehicle(TourActivity prevAct) {

        Capacity prevLoad = stateManager.getActivityState(prevAct, InternalStates.LOAD, Capacity.class); //1.3.2-SNAPSHOT & upcoming release v1.4
        if (prevLoad == null) {
            return false;
        } else {
            return prevLoad.get(BIKES_DIMENSION_INDEX) > 0;
        }
    }

    private Capacity getLoadAtPreviousAct(TourActivity prevAct) {
        Capacity prevLoad = stateManager.getActivityState(prevAct, InternalStates.LOAD, Capacity.class); //1.3.2-SNAPSHOT & upcoming release v1.4
        if (prevLoad != null) return prevLoad;
        else return Capacity.Builder.newInstance().build();
    }

    @Override
    public ConstraintsStatus fulfilled(JobInsertionContext jobInsertionContext, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {

        if (newAct.getName().equals("pickup")) {
            //Check current capacity
            return ConstraintsStatus.FULFILLED;
        } else {
            if(hasBikesInVehicle(prevAct)){
                return ConstraintsStatus.FULFILLED;
            }else{
                return ConstraintsStatus.NOT_FULFILLED;
            }
        }
    }
}


public static void main(String[] args) {


    VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(BIKES_DIMENSION_INDEX, 10).build();

    VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocation(loc(Coordinate.newInstance(0, 0)))
        .setType(type).build();


    Delivery bikes_1 = Delivery.Builder.newInstance("bikes_1_delivery")
        .addSizeDimension(BIKES_DIMENSION_INDEX, 1)
        .setLocation(loc(Coordinate.newInstance(5, 5))).build();

    Delivery bikes_2 = Delivery.Builder.newInstance("bikes_2_delivery")
        .addSizeDimension(BIKES_DIMENSION_INDEX, 1)
        .setLocation(loc(Coordinate.newInstance(5, 2))).build();

    Delivery bikes_3 = Delivery.Builder.newInstance("bikes_3_delivery")
        .addSizeDimension(BIKES_DIMENSION_INDEX, 1)
        .setLocation(loc(Coordinate.newInstance(5, 3))).build();

    Pickup bikes_4 = Pickup.Builder.newInstance("bikes_4_pickup").addSizeDimension(BIKES_DIMENSION_INDEX, 1).setLocation(loc(Coordinate.newInstance(5, 4))).build();
    Pickup bikes_5 = Pickup.Builder.newInstance("bikes_5_pickup").addSizeDimension(BIKES_DIMENSION_INDEX, 1).setLocation(loc(Coordinate.newInstance(5, 1))).build();
    Pickup bikes_6 = Pickup.Builder.newInstance("bikes_6_pickup").addSizeDimension(BIKES_DIMENSION_INDEX, 1).setLocation(loc(Coordinate.newInstance(5, 6))).build();


    VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
        .setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
        .addJob(bikes_1)
        .addJob(bikes_2)
        .addJob(bikes_3)
        .addJob(bikes_4)
        .addJob(bikes_5)
        .addJob(bikes_6)
        .addVehicle(vehicle)
        //.addJob(bikes_7)
        .build();


    StateManager stateManager = new StateManager(vrp);
    ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
    constraintManager.addLoadConstraint();
    constraintManager.addConstraint(new EnoughtPickupsForDeliveries(stateManager), ConstraintManager.Priority.CRITICAL);

    VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp)
        .setStateAndConstraintManager(stateManager, constraintManager)
        .setCustomAcceptor(new SolutionAcceptor() {
            @Override
            public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> collection, VehicleRoutingProblemSolution vehicleRoutingProblemSolution) {
                return vehicleRoutingProblemSolution.getUnassignedJobs().size() == 0;
            }
        })
        .buildAlgorithm();

    Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();

    SolutionPrinter.print(vrp, Solutions.bestOf(solutions), SolutionPrinter.Print.VERBOSE);

    new GraphStreamViewer(vrp, Solutions.bestOf(solutions)).labelWith(GraphStreamViewer.Label.ID).setRenderShipments(true).display();

}

private static Location loc(Coordinate coordinate) {
    return Location.Builder.newInstance().setCoordinate(coordinate).build();
}

}

I’m always getting a invalid solution with more deliveries before pickups.

Thank you so much in advance!!!