Search code examples
optaplanner

CustomShadowVariables and ScoreDirector


I have a custom shadow variable that is supposed to update a list of assignments for a person as they're assigned to jobs. This is to enable a rule that, e.g. a Person can only have x shifts per week. I figure maintaining this list of shifts per person as we go in a shadow variable should be easier than trying to calculate it in the solver rules.

When I run the solver, on the first iteration, the Solver crashes with this exception:

Exception in thread "main" java.lang.IllegalArgumentException: The entity (Black) was never added to this ScoreDirector. Usually the cause is that that specific instance was not in your Solution's entities.

I'm not entirely sure what this means. The entity Black is an instance of a planning entity which is both annotated and defined in the config.xml, and it's in the set of problem facts.

My shadow variable is defined as:

@CustomShadowVariable(
        variableListenerClass = PersonAssignmentListener.class,
        sources = {@CustomShadowVariable.Source(
                variableName = "startingTimeGrain",
                entityClass = Assignment.class)
        }
)
public List<Assignment> getAssignments() {
    return assignments;
}

The listener for the shadow variable looks like this:

@Override
public void afterEntityAdded(ScoreDirector scoreDirector, 
                             Assignment assignment) {
    updatePerson(scoreDirector, assignment);
}

@Override
public void afterVariableChanged(ScoreDirector scoreDirector,
                             Assignment assignment) {
    updatePerson(scoreDirector, assignment);
}

private void updatePerson(ScoreDirector scoreDirector,
                          Assignment sourceAssignment) {

    Shift shift = sourceAssignment.getShift();
    Person p = sourceAssignment.getPerson();

    scoreDirector.beforeVariableChanged(away, "assignments");
    p.getAssignments().add(sourceAssignment);
    scoreDirector.afterVariableChanged(away, "assignments");
}

The exception occurs on the "afterVariableChanged" call.


Solution

  • It's unrelated to the chained or shadow vars.

    Check the methods on your PlanningSolution class that have a EntityCollectionProperty annotation. That instance Black won't be in there.