在TimeFold中实现PreviousStandstill变更:现成方法是否存在?自研代码可行吗?
Does TimeFold have built-in support for this?
TimeFold does not provide out-of-the-box ProblemChange implementations for modifying VRP routes (like moving a customer to a new position). This is because route adjustment use cases vary widely (insertions, swaps, reorders) and require customization to fit specific business rules. However, the core ProblemChange API is designed exactly for this kind of manual modification of the solution state, so your approach of implementing a custom ProblemChange is valid.
Code Review & Corrections
Your code attempts to modify a customer's previousStandstill, but it has several issues that will prevent it from working correctly in all scenarios. Here's a breakdown of the problems and how to fix them:
Key Issues in Your Current Code
- Ignores Vehicles as
previousStandstill: Your loop only checks customers, butpreviousStandstillcan be aVehicle(the start of a route). This means inserting a customer at the beginning of a vehicle's route will fail. - Inefficient lookup of the next customer: Instead of looping through all customers to find the one following
previousStandstill, you can directly accesspreviousStandstill.getNextCustomer()(a standard method in VRP domain models). - Direct field modifications without change tracking: You're setting fields like
setPreviousStandstilldirectly, but TimeFold requires usingProblemChangeDirector.changeProperty()to track these changes for accurate score recalculation. - Unnecessary complexity in insertion logic: The current loop-based approach overcomplicates connecting the customer to its new position.
Corrected Implementation
Here's a revised version of your PreviousStandstillChange class that addresses these issues:
public class PreviousStandstillChange implements ProblemChange<VehicleRoutingSolution> { private final TimeWindowedCustomer customerToMove; private final Standstill newPreviousStandstill; public PreviousStandstillChange(TimeWindowedCustomer customerToMove, Standstill newPreviousStandstill) { this.customerToMove = customerToMove; this.newPreviousStandstill = newPreviousStandstill; } @Override public void doChange(VehicleRoutingSolution workingSolution, ProblemChangeDirector changeDirector) { // Get working clones of the objects (critical for TimeFold's state management) TimeWindowedCustomer workingCustomer = changeDirector.lookUpWorkingObjectOrFail(customerToMove); Standstill workingNewPrevious = changeDirector.lookUpWorkingObjectOrFail(newPreviousStandstill); // Step 1: Disconnect the customer from its current position Standstill currentPrevious = workingCustomer.getPreviousStandstill(); TimeWindowedCustomer currentNext = workingCustomer.getNextCustomer(); if (currentPrevious != null) { changeDirector.changeProperty(currentPrevious, "nextCustomer", currentNext); } if (currentNext != null) { changeDirector.changeProperty(currentNext, "previousStandstill", currentPrevious); } // Step 2: Connect the customer to its new position TimeWindowedCustomer nextAfterNewPrevious = workingNewPrevious.getNextCustomer(); // Update the customer's previous and next changeDirector.changeProperty(workingCustomer, "previousStandstill", workingNewPrevious); changeDirector.changeProperty(workingCustomer, "nextCustomer", nextAfterNewPrevious); // Update the new previous standstill's next changeDirector.changeProperty(workingNewPrevious, "nextCustomer", workingCustomer); // Update the customer that was after the new previous (if exists) if (nextAfterNewPrevious != null) { changeDirector.changeProperty(nextAfterNewPrevious, "previousStandstill", workingCustomer); } } }
Key Improvements
- Handles both Vehicle and Customer as
previousStandstill: UsesworkingNewPrevious.getNextCustomer()which works for both types of Standstill. - Proper change tracking: Uses
changeDirector.changeProperty()to notify TimeFold of every modification, ensuring accurate score recalculation. - Simplified logic: Breaks the operation into clear disconnect/connect steps, making the code easier to maintain and debug.
- Null safety: Properly checks for null values when updating relationships.
Usage Notes
- Ensure your domain model (Vehicle, TimeWindowedCustomer) implements the necessary getters/setters for
previousStandstillandnextCustomer. - After applying this
ProblemChange, you can trigger a score calculation or continue optimizing the solution with TimeFold's solver.
内容的提问来源于stack exchange,提问作者elk-tamer

