Hard Constraint doesn't seem to be applying

Hi @kneekill,

I tested on the following example:

    VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type")
            .addCapacityDimension(0, 3)
            .build();
    VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1")
            .setType(type)
            .setReturnToDepot(false)
            .setStartLocation(Location.newInstance(0, 0))
            .build();
    Delivery s1 = Delivery.Builder.newInstance("s1")
            .setLocation(Location.newInstance(0, 0))
            .build();
    Delivery s2 = Delivery.Builder.newInstance("s2")
            .setLocation(Location.newInstance(0, 0))
            .build();
    Service s3 = Service.Builder.newInstance("s3")
            .setLocation(Location.newInstance(0, 1))
            .build();
    VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
            .addJob(s1)
            .addJob(s2)
            .addJob(s3)
            .addVehicle(v1)
            .setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
            .build();

    Jsprit.Builder algorithmBuilder = Jsprit.Builder.newInstance(vrp);
    StateManager stateManager = new StateManager(vrp);
    ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
    constraintManager.addConstraint(new HardActivityConstraint() {
        @Override
        public ConstraintsStatus fulfilled(
                JobInsertionContext iFacts,
                TourActivity prevAct,
                TourActivity newAct,
                TourActivity nextAct,
                double prevActDepTime) {

            if(isInstanceOfDelivery(prevAct) && isInstanceOfDelivery(newAct)) {
                return ConstraintsStatus.NOT_FULFILLED;
            }
            if(isInstanceOfDelivery(newAct) && isInstanceOfDelivery(nextAct)) {
                return ConstraintsStatus.NOT_FULFILLED;
            }

            return ConstraintsStatus.FULFILLED;
        }
    }, ConstraintManager.Priority.HIGH);
    algorithmBuilder.setStateAndConstraintManager(stateManager, constraintManager);

    VehicleRoutingAlgorithm algorithm = algorithmBuilder.buildAlgorithm();
    VehicleRoutingProblemSolution s = Solutions.bestOf(algorithm.searchSolutions());
    SolutionPrinter.print(vrp, s, SolutionPrinter.Print.VERBOSE);

so now, as you have observed, even with the constraint that two delivery activities cannot be in a row, I get a solution with cost 1 and sequence s1, s2, s3 - two delivery activities in a row.

Then I add the following InsertionStartsListener:

    algorithm.addListener(new InsertionStartsListener() {
        @Override
        public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
            Map<TourActivity, VehicleRoute> toDeleteActRouteMap = new HashMap<>();
            for(VehicleRoute route : routes){
                for (int i = 0; i < route.getActivities().size() - 1; i++) {
                    TourActivity act1 = route.getActivities().get(i);
                    TourActivity act2 = route.getActivities().get(i + 1);
                    if(isInstanceOfDelivery(act1) && isInstanceOfDelivery(act2)) {
                        toDeleteActRouteMap.put(act1, route);
                    }
                }
            }
            for (Map.Entry<TourActivity, VehicleRoute> entry : toDeleteActRouteMap.entrySet()) {
                TourActivity act = entry.getKey();
                VehicleRoute route = entry.getValue();
                if (act instanceof TourActivity.JobActivity) {
                    Job job = ((TourActivity.JobActivity) act).getJob();
                    boolean removed = route.getTourActivities().removeJob(job);
                    if(removed) {
                        unassignedJobs.add(job);
                    }
                }
            }
        }
    });

now I get a solution with cost 2 and sequence s2, s3, s1 - it follows the constraint.

Hopefully this helps.

Best regards,
He