Question A is super easy.
Question B not so.
As for A, you need to be at a position where you can access the object graph (say, after deserializing a solution). Then, you get the first customer of that vehicle, setting its previousStandstill
to null
:
Customer nextCustomer = vehicle.getNextCustomer();
if (nextCustomer != null){
scoreDirector.beforeVariableChanged(nextCustomer, "previousStandstill");
nextCustomer.setPreviousStandstill(null);
scoreDirector.afterVariableChanged(nextCustomer, "previousStandstill");
scoreDirector.triggerVariableListeners();
}
I believe that Question B warrants more attention. The default way of doing this is to implement an OrderListener
which triggers on previousStandstill
of the customer, the listener updating all the customers in a vehicle's chain whenever a previousStandstill
is changed on any customer:
@CustomShadowVariable(variableListenerClass = OrderListener.class,
sources = {@PlanningVariableReference(variableName = "previousStandstill")})
public Integer getPositionInVehicleChain() {
return position;
}
and then in the OrderListener
's afterVariableChanged
method to have something like this:
while (nextCustomer != null) {
if (position == nextTe.getPositionInVehicleChain()) break;
scoreDirector.beforeVariableChanged(nextCustomer, "position");
nextCustomer.setPositionInStapelabschnitt(pos);
scoreDirector.afterVariableChanged(nextCustomer, "position");
pos++;
nextCustomer = nextCustomer.getNextCustomer();
}
Then you implement an isBeforeCustomer(Customer otherCustomer)
in your Customer
class, where you compare the two position
s.
However, this is certainly not the most elegant method, as its time complexity is O(n)
, where n
is the total number of planning entities. The nice way of doing this is to implement a so called Order Maintenance data structure on the customers per vehicle. This data structure supports the operations
- Insert (x, y): This is inserting a new customer in an existing chain
- Delete (x): This is removing a customer in an existing chain, see question A.
- Order (x, y): Determine whether x precedes y in the chain order - this is what you're after.
The state of the art algorithms (see, e.g., "Bender M.A., Cole R., Demaine E.D., Farach-Colton M., Zito J. (2002) Two Simplified Algorithms for Maintaining Order in a List. In: Möhring R., Raman R. (eds) Algorithms — ESA 2002. ESA 2002. Lecture Notes in Computer Science, vol 2461. Springer, Berlin, Heidelberg") support O(1)
amortized insertion/deletion time and O(1)
worst-case query time, much better than the system proposed above (but a lot more work). Have a look around for transitivity utils if you're interested in an implementation. I would be very interested if such a data structure were included as shadow variables out of the box in optaplanner - the question of whether an entity is before another in a chain is ubiquitous.