Friday, June 21, 2013

Shadow variables, PlanningVariableListener and bi-directional variables

Most types of custom constraints are relatively straightforward to implement in OptaPlanner. There was one notorious exception: time windows for vehicle routing. But OptaPlanner 6.0.0.Beta4 supports shadow variables, which make that a lot easier to implement.

A shadow variable is a variables who's correct value can be deduced from the state of the genuine planning variables. Even though such a variable violates the principle of normalization by definition, in some use cases it can be very practical to use a shadow variable. For example in vehicle routing with time windows: the arrival time at a customer for a vehicle can be calculated based on the previously visited customers of that vehicle (and the known travel times between 2 locations).


To update the shadow variable(s) correctly, we can annotate a PlanningVariableListener on the genuine planning variable:

    @PlanningVariable(..., variableListenerClasses = {VehicleUpdatingVariableListener.class, ArrivalTimeUpdatingVariableListener.class})
    public Standstill getPreviousStandstill() {
        return previousStandstill;

Bi-directional variables

OptaPlanner reuses that system internally to provide support for bi-directional variables (like JPA), currently only for chained variables:

    @PlanningVariable(mappedBy = "previousStandstill")
    Customer getNextCustomer();

So if OptaPlanner changes the previousStandstill side, it automatically also changes the nextCustomer side accordingly.


  1. Can't wait to see the examples Geoffrey!

  2. It's already in master, in the vrp example, it works, but I am still improving the gui etc :)