Hello. First, thank for this fantastic library: it’s great.
I’m trying to implement a constraint to limit the number of routes that start in a particular time window (e.g. limiting the number of departures per day). My thinking was to add a StateUpdater to increment the number of routes that start within a particular time window and a HardRouteConstraint to inspect the state and return whether or not the maxDepartures limit is satisfied.
My code is as follows:
public class DeparturesPerDay implements HardRouteConstraint {
private StateManager stateManager;
private StateId stateId;
private int maxDeparturesPerDay;
public DeparturesPerDay(StateManager stateManager, StateId stateID, int maxDeparturesPerDay) {
this.stateManager = stateManager;
this.stateId = stateID;
this.maxDeparturesPerDay = maxDeparturesPerDay;
}
private int getMax(HashMap<Integer, HashMap<VehicleRoute, Integer>> map) {
Map.Entry<Integer, Integer> maxEntry = null;
if (map == null || map.isEmpty()) {
return 0;
} else {
int max = 0;
for(Map<VehicleRoute, Integer> val: map.values())
{
int sum_of_all_departing = 0;
for(Integer i: val.values())
{
sum_of_all_departing+=i;
}
max = sum_of_all_departing > max ? sum_of_all_departing: max;
}
return max;
}
}
public boolean fulfilled(JobInsertionContext iFacts) {
// get the maximum number of departures per day in the problem state
HashMap<Integer, HashMap<VehicleRoute, Integer>> maxDepaturesState = stateManager.getProblemState(stateId, HashMap.class);
Integer maxDeparturesInADay = getMax(maxDepaturesState);
System.out.println(maxDeparturesInADay);
return (maxDeparturesInADay <= maxDeparturesPerDay);
}
}
public class UpdateDeparturesPerDay implements StateUpdater, ActivityVisitor, IterationEndsListener {
private StateManager stateManager;
private StateId maxBoatStateId;
private HashMap<Integer, HashMap<VehicleRoute, Integer>> departuresPerDay = new HashMap<>();
private VehicleRoute route;
UpdateDeparturesPerDay(StateManager stateManager, StateId maxBoatStateID) {
this.stateManager = stateManager;
this.maxBoatStateId = maxBoatStateID;
}
@Override
public void informIterationEnds(int iteration, VehicleRoutingProblem vrp, Collection<VehicleRoutingProblemSolution> soln) {
this.departuresPerDay.clear();
}
@Override
public void begin(VehicleRoute route) {
this.route = route;
double departureTime = route.getStart().getEndTime();
int departureDay = (int) Math.ceil(departureTime / (24.0 * 60.0));
HashMap<VehicleRoute, Integer> routeDepartures = departuresPerDay.get(departureDay);
if (routeDepartures == null) {
// there have been no route keys inserted on the day
routeDepartures = new HashMap<>();
}
routeDepartures.put(this.route, 1);
departuresPerDay.put(departureDay, routeDepartures);
stateManager.putProblemState(maxBoatStateId, HashMap.class, departuresPerDay);
}
@Override
public void visit(TourActivity activity) {
}
@Override
public void finish() {
}
}
StateManager stateManager = new StateManager(this.problem);
stateManager.addStateUpdater(new UpdateDeparturesPerDay(
stateManager,
stateManager.createStateId("max_departures_per_day")));
//create relevant constraints
DeparturesPerDay departuresPerDayConstraint = new DeparturesPerDay(
stateManager,
stateManager.createStateId("max_departures_per_day"),
appConfig.max_boats_per_day_from_port
);
ConstraintManager constraintManager = new ConstraintManager(this.problem, stateManager);
constraintManager.addConstraint(departuresPerDayConstraint);
}
But the constraint is not being enforced. Obviously I’m misunderstanding how to do this, so any steering help would be appreciated.