Search code examples
timefold

How to implement a previous standstill change in TimeFold


I have a VRP problem I'm solving using timefold. It's working well but I want to be able to load in existing schedules for analysis and allow changes to the routes through a GUI. To do that I've written a ProblemChange, but it seems like the code must already exist in Timefold, or I'm doing it wrong. So, is there already a method like this? If not, will this allow for changing the previousStandStill of a Customer?

`public class PreviousStandstillChange implements ProblemChange {

    private final TimeWindowedCustomer timeWindowedCustomer;
    private final Standstill previousStandstill;

    public PreviousStandstillChange(TimeWindowedCustomer timeWindowedCustomer, Standstill previousStandstill) {
        this.timeWindowedCustomer = timeWindowedCustomer;
        this.previousStandstill = previousStandstill;
    }

    @Override
    public void doChange(VehicleRoutingSolution vehicleRoutingSolution,
            ProblemChangeDirector problemChangeDirector) {
        TimeWindowedCustomer workingTimeWindowedCustomer = problemChangeDirector
                .lookUpWorkingObjectOrFail(timeWindowedCustomer);
        Standstill currentPreviousStandstill = workingTimeWindowedCustomer.getPreviousStandstill();
        TimeWindowedCustomer currentNexTimeWindowedCustomer = workingTimeWindowedCustomer.getNextCustomer();
        // First find the TimeWindowedCustomer that points to the standstill
        for (TimeWindowedCustomer timeWindowedCustomer : vehicleRoutingSolution.getCustomerList()) {
            if (timeWindowedCustomer.getPreviousStandstill() == previousStandstill) {
                timeWindowedCustomer.setPreviousStandstill(workingTimeWindowedCustomer);
                workingTimeWindowedCustomer.setNextCustomer(timeWindowedCustomer);
                workingTimeWindowedCustomer.setPreviousStandstill(previousStandstill);
                previousStandstill.setNextCustomer(workingTimeWindowedCustomer);
                break;
            }
        }
        // Then connect the previous and next of the customer being moved
        if (currentPreviousStandstill != null) {
            if (currentNexTimeWindowedCustomer != null) {
                currentNexTimeWindowedCustomer.setPreviousStandstill(currentPreviousStandstill);
                currentPreviousStandstill.setNextCustomer(currentNexTimeWindowedCustomer);
            } else {
                currentPreviousStandstill.setNextCustomer(null);
            }
        }
    }
}`

I'm trying to implement a ProblemChange properly.


Solution

  • When you change variables or properties, you need to call either changeVariable or changeProblemProperty respectively. I would change your code to:

     public void doChange(VehicleRoutingSolution vehicleRoutingSolution,
                ProblemChangeDirector problemChangeDirector) {
            TimeWindowedCustomer workingTimeWindowedCustomer = problemChangeDirector
                    .lookUpWorkingObjectOrFail(timeWindowedCustomer);
            Standstill currentPreviousStandstill = workingTimeWindowedCustomer.getPreviousStandstill();
            TimeWindowedCustomer currentNexTimeWindowedCustomer = workingTimeWindowedCustomer.getNextCustomer();
            // First find the TimeWindowedCustomer that points to the standstill
            for (TimeWindowedCustomer timeWindowedCustomer : vehicleRoutingSolution.getCustomerList()) {
                if (timeWindowedCustomer.getPreviousStandstill() == previousStandstill) {
                    problemChangeDirector.changeVariable(timeWindowedCustomer, "previousStandstill", entity -> entity.setPreviousStandstill(workingTimeWindowedCustomer));
                    problemChangeDirector.changeVariable(workingTimeWindowedCustomer, "nextCustomer", entity -> entity.setNextCustomer(timeWindowedCustomer));
                    problemChangeDirector.changeVariable(workingTimeWindowedCustomer, "previousStandstill", entity -> entity.setPreviousStandstill(previousStandstill));
                    problemChangeDirector.changeVariable(previousStandstill, "nextCustomer", entity -> entity.setNextCustomer(workingTimeWindowedCustomer));
                    break;
                }
            }
            // Then connect the previous and next of the customer being moved
            if (currentPreviousStandstill != null) {
                if (currentNexTimeWindowedCustomer != null) {
                    problemChangeDirector.changeVariable(currentNexTimeWindowedCustomer, "previousStandstill", entity -> entity.setPreviousStandstill(currentPreviousStandstill));
                    problemChangeDirector.changeVariable(currentPreviousStandstill, "nextCustomer", entity -> entity.setNextCustomer(currentNexTimeWindowedCustomer));
                } else {
                    problemChangeDirector.changeVariable(currentPreviousStandstill, "nextCustomer", entity -> entity.setNextCustomer(null));
                }
            }
        }