Based on this question i tried the following:
public void doFactChange() {
Location toBeRemovedLocation = customerToBeRemoved.getLocation();
Location lookUpWorkingObject = (Location) scoreDirector.lookUpWorkingObject(toBeRemovedLocation);
scoreDirector.beforeProblemFactRemoved(lookUpWorkingObject);
routingSolution.getLocationList().remove(lookUpWorkingObject);
scoreDirector.afterProblemFactRemoved(lookUpWorkingObject);
Customer workingCustomer = (Customer) scoreDirector.lookUpWorkingObject(customerToBeRemoved);
for (Customer customer : routingSolution.getCustomerList()) {
while (customer != null) {
if (customer == workingCustomer) {
if (customer.getPreviousStandstill() != null) {
scoreDirector.beforeVariableChanged(customer, "previousStandstill");
customer.getPreviousStandstill().setNextCustomer(customer.getNextCustomer());
scoreDirector.afterVariableChanged(customer, "previousStandstill");
}
scoreDirector.beforeVariableChanged(customer, "nextCustomer");
customer.getNextCustomer().setPreviousStandstill(customer.getPreviousStandstill());
scoreDirector.afterVariableChanged(customer, "nextCustomer");
}
customer = customer.getNextCustomer();
}
}
scoreDirector.beforeEntityRemoved(workingCustomer);
routingSolution.getCustomerList().remove(workingCustomer);
scoreDirector.afterEntityRemoved(workingCustomer);
scoreDirector.triggerVariableListeners();
}
Note: customerToBeRemoved
is an instance object that's created before calling doFactChange()
But I received the following exception even before calling scoreDirector.triggerVariableListeners
java.lang.IllegalStateException: The entity (Customer--9048381398840634905) has a variable (previousStandstill) with value (Customer--9070671076516032025) which has a sourceVariableName variable (nextCustomer) with a value (Customer-8518512081385427431) which is not that entity. Verify the consistency of your input problem for that sourceVariableName variable.
Another question:
I tried to remove the entity directly as follows:
public void doFactChange() {
Location toBeRemovedLocation = customerToBeRemoved.getLocation();
Location lookUpWorkingObject = (Location) scoreDirector.lookUpWorkingObject(toBeRemovedLocation);
scoreDirector.beforeProblemFactRemoved(lookUpWorkingObject);
routingSolution.getLocationList().remove(lookUpWorkingObject);
scoreDirector.afterProblemFactRemoved(lookUpWorkingObject);
Customer workingCustomer = (Customer) scoreDirector.lookUpWorkingObject(customerToBeRemoved);
scoreDirector.beforeEntityRemoved(workingCustomer);
routingSolution.getCustomerList().remove(workingCustomer);
scoreDirector.afterEntityRemoved(workingCustomer);
scoreDirector.triggerVariableListeners();
}
Is that valid?
This method works fine with optaplanner VRP example using easy, incremental and drl score calculators:
public void removeRandomCustomer()
{
doProblemFactChange(scoreDirector -> {
VehicleRoutingSolution solution = scoreDirector.getWorkingSolution();
int rnd = 4; //select a random customer
if (solution.getCustomerList().size() > rnd)
{
Customer customer = solution.getCustomerList().get(rnd);
scoreDirector.beforeEntityRemoved(customer);
removeCustomer(solution, customer);
scoreDirector.afterEntityRemoved(customer);
scoreDirector.triggerVariableListeners();
}
});
}
private void removeCustomer(VehicleRoutingSolution solution, Customer customer)
{
Standstill anchor = customer.getPreviousStandstill();
Customer nextCustomer = customer.getNextCustomer();
//anchor shouldn't be null in an initialized solution
if (anchor != null)
anchor.setNextCustomer(nextCustomer);
if (nextCustomer != null)
nextCustomer.setPreviousStandstill(anchor);
solution.getCustomerList().remove(customer);
}
Edit:
Alternative approach for shadow variables with easy/incremental scoring:
private void removeCustomer(ScoreDirector<VehicleRoutingSolution> scoreDirector, VehicleRoutingSolution solution, Customer removeCustomer)
{
final Customer customer = scoreDirector.lookUpWorkingObject(removeCustomer);
Standstill anchor = customer.getPreviousStandstill();
Customer nextCustomer = customer.getNextCustomer();
//scoreDirector.beforeVariableChanged(anchor, "nextCustomer");
scoreDirector.beforeVariableChanged(customer, "previousStandstill"); //sets anchor.nextCustomer=null
customer.setPreviousStandstill(null);
scoreDirector.afterVariableChanged(customer, "previousStandstill");
//scoreDirector.afterVariableChanged(anchor, "nextCustomer");
if(nextCustomer!=null)
{
//scoreDirector.beforeVariableChanged(customer, "nextCustomer");
scoreDirector.beforeVariableChanged(nextCustomer, "previousStandstill"); //sets customer.nextCustomer=null
nextCustomer.setPreviousStandstill(anchor);
scoreDirector.afterVariableChanged(nextCustomer, "previousStandstill");
//scoreDirector.afterVariableChanged(customer, "nextCustomer");
}
scoreDirector.beforeEntityRemoved(customer);
//clone customer list
ArrayList<Customer> changedList = new ArrayList<>(solution.getCustomerList());
solution.setCustomerList(changedList);
solution.getCustomerList().remove(customer);
scoreDirector.afterEntityRemoved(customer);
scoreDirector.triggerVariableListeners(); //sets customer.vehicle=null, sets all nextCustomer.vehicle=null
}
The solution should be in a valid state now but you'll probably have to fix the incremental scoring (easy score is fine because doProblemFactChange()
recalculates it automatically), perhaps by removing the retraction in VehicleRoutingIncrementalScoreCalculator.beforeEntityRemoved()
. If everything else fails you could first move the customer to the end of the chain and remove it from there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With