What is the correct way to remove (=delete) a vehicle from planning entity collection (similar to VehicleRoutingSolution.VehicleList in OptaPlanner VRP samples) via ProblemFactChange?
So far I've tried to
- reset nextCustomer before deleting the vehicle
- reset nextCustomer of vehicle and prevStandstill of its first customer
- do the same for all chained customers on vehicle
- brute force through customer list
I'm getting IllegalStateException, either because of mismatch between prevStandstill and nextCustomer or Local Search phase start failing with an uninitialized solution.
Edit: moving the first customer in chain to another vehicle seems to be working fine.
Edit 2
I tried to reset all customers in chain with this snippet
Customer customer = vehicle.getNextCustomer();
while(customer!=null)
{
Customer nextCustomer = customer.getNextCustomer();
scoreDirector.beforeVariableChanged(customer, "previousStandstill"); //Exception on second customer
customer.setPreviousStandstill(null);
scoreDirector.afterVariableChanged(customer, "previousStandstill");
scoreDirector.beforeVariableChanged(customer, "nextCustomer");
customer.setNextCustomer(null);
scoreDirector.afterVariableChanged(customer, "nextCustomer");
customer.setVehicle(null);
customer=nextCustomer;
}
but I'm getting hit with IllegalStateException on second run through loop
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: The entity (CUST39(after CUST39)) has a variable (previousStandstill) with value (CUST39(after null)) which has a sourceVariableName variable (nextCustomer) with a value (null) which is not that entity.
Verify the consistency of your input problem for that sourceVariableName variable.
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.retract(SingletonInverseVariableListener.java:82)
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.beforeVariableChanged(SingletonInverseVariableListener.java:44)
at org.optaplanner.core.impl.domain.variable.listener.VariableListenerSupport.beforeVariableChanged(VariableListenerSupport.java:145)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.beforeVariableChanged(AbstractScoreDirector.java:257)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.beforeVariableChanged(AbstractScoreDirector.java:228)
It seems obvious (the state is invalid because first customer is detached from second, but second is still pointing at the first one), but I don't know what's the correct route ;) around it.
This
Customer nextCustomer = customer.getNextCustomer();
customer.setPreviousStandstill(null);
customer.setNextCustomer(null);
scoreDirector.beforeVariableChanged(customer, "previousStandstill");
scoreDirector.beforeVariableChanged(customer, "nextCustomer");
scoreDirector.afterVariableChanged(customer, "nextCustomer");
scoreDirector.afterVariableChanged(customer, "previousStandstill");
seems to work - CH is fired for each of the removed customers, move count is correct, EasyScore works and the exception is avoided. But, is it bad?