Discard a route in IterationsEndListener

Hello All,

I want to discard a route and make those jobs unassigned so that they are calculated against unassigned jobs cost. How can I do this at the End of IterationsEndListener. Are the solutions modifiable at in IterationsEndListener?

Thanks.

solution.getUnassignedJobs().addAll(route.getTourActivities().getJobs());
solution.getRoutes().remove(route);
for (Job u : route.getTourActivities().getJobs()) {
	reasonTracker.informJobUnassigned(u, unassignmentReason);
}

I tried using above code to remove the route in iterationsEndslistener but it doesn’t seem to work. If i debug it shows it is removing the route but the final solution is giving me that route in the output.

What else can i do here?

Could you describe your scenario a little more? What is your goal?

I want to remove the routes which are not fulfilling minimum capacity constraints. for example, a vehicle has a capacity of 10 and minimum capacity constraint is 5 then that vehicle must cater at least 5 shipments, if not, unassign those shipments and keep the vehicle free. I was trying to do this by implementing IterationsEndsListener but a best solution with all those shipments assigned is already available in bestEver in VRA. So using iterationsEndsListener is not the correct solution. so i tried implementing algorithmStartsListener but it doesn’t work. Implementing InsertionStartsListener started giving me ConcurrentModificationException.

So at the end i rewrote the objective function to discard the routes and then calculate the costs for remaining routes and unassigned jobs. It’s working fine now.

return new SolutionCostCalculator() {
		@Override
		public double getCosts(VehicleRoutingProblemSolution solution) {
			if (checkMinimumCapacity)
				checkForMinimumCapacity(solution, reasonTracker, minLoad);
			double costs = 0.;
			for (VehicleRoute route : solution.getRoutes()) {
				costs += route.getVehicle().getType().getVehicleCostParams().fix;
				boolean hasBreak = false;
				TourActivity prevAct = route.getStart();
				for (TourActivity act : route.getActivities()) {
					if (act instanceof BreakActivity)
						hasBreak = true;
					costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), act.getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle());
					costs += vrp.getActivityCosts().getActivityCost(act, act.getArrTime(), route.getDriver(), route.getVehicle());
					prevAct = act;
				}
				costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), route.getEnd().getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle());
				if (route.getVehicle().getBreak() != null && !hasBreak && route.getEnd().getArrTime() > route.getVehicle().getBreak().getTimeWindow().getEnd()) {
					costs += 4 * (maxCosts * 2 + route.getVehicle().getBreak().getServiceDuration()
							* route.getVehicle().getType().getVehicleCostParams().perServiceTimeUnit);
				}
			}
			for (Job j : solution.getUnassignedJobs()) {
				costs += maxCosts * 2 * (11 - j.getPriority());
			}
			return costs;
		}
	};
2 Likes

This is a common need, what do you think do a pull request in the jsprit-examples project?

Can you tell why a softconstraint does not apply in this scenario?

Sure. I will do a pull request in the jsprit-examples.

I tried implementing a soft constraint as below -
Implement a softrouteconstraint to encourage job insertion until minimum capacity is fulfilled and in the objectivefunction penalize the routes not fulfilling the minimum capacity of vehicle. However, this is not generating expected output always. Sometimes there are still some routes not fulfilling minimum capacity. And i needed a HardConstraint hence i used this approach. Do you think there could be other way of doing this?

In my experience the softconstraint influences the construction of the solution, which in the case of minimum quantity would not work well. I liked the solution you used.

I have a similar problem, which is to perform first deliveries with greater weight, with the use of softconstraint is still not working well, I tried to also use the SolutionCostCalculator.

Maybe you can use a SoftActivityConstraint here(you may have tried this, i am just sharing my thoughts), this constraint will give you control if the new activity is inserted between 2 jobs and as per your condition if it is not correct then penalize. And also penalize the route in objective function as well if your constraint is not fulfilled.

Yes I agree. Thanks for sharing your opinion.

Have you had any news regarding multiple breaks in vehicles? I’m trying to implement this feature.

I want to implement the same.

@jie31best has given heads up here Multiple breaks per Vehicle

Thanks for your sharing. What is implementation of checkForMinimumCapacity function?

Here you go -

private void checkForMinimumCapacity(VehicleRoutingProblemSolution solution, UnassignedJobReasonTracker reasonTracker, int minLoad) {
	List<String> unassignmentReason = new ArrayList<>();
	unassignmentReason.add("MINIMUM_LOAD_NOT_FULFILLED");
	List<VehicleRoute> discardedRoutes = new ArrayList<>();
	for (VehicleRoute route : solution.getRoutes()) {
		int load = 0;
		for (TourActivity act : route.getTourActivities().getActivities()) {
			load += act.getSize().get(0);
		}
		if (load < minLoad) {
			discardedRoutes.add(route);
		}
	}
	for (VehicleRoute route : discardedRoutes) {
		solution.getUnassignedJobs().addAll(route.getTourActivities().getJobs());
		solution.getRoutes().remove(route);
		for (Job u : route.getTourActivities().getJobs()) {
			reasonTracker.informJobUnassigned(u, unassignmentReason);
		}
	}
}

Thanks a lot

@koradeprashant Thanks for posting this. It has shown me a new way to influence jsprit and is working a treat for both minimum load and limiting pickup locations per route.

well done.

@grantm009 Thanks.