VariableListener 损坏

VariableListener corruption

我正在研究自定义影子变量和自定义变量侦听器。我发现 "Exam timetabling" 示例使用自定义影子变量在 "Leading Exam" 更改时更新 "Following exams"。 因此,我所做的断言在这个问题中提出的问题是正确的 我在下面的考试 class 中添加了第二个影子变量,它引用了变量 "period" ,然后在LeadingExam 计划实体(PeriodUpdatingVariableListener)我更新了两个变量。

这是 "FollowingExam" class

的代码
@PlanningEntity
@XStreamAlias("FollowingExam")
public class FollowingExam extends Exam {

protected LeadingExam leadingExam;

// Shadow variables
protected Period period;
protected Integer var;

@CustomShadowVariable(variableListenerClass = PeriodUpdatingVariableListener.class, sources = {
        @CustomShadowVariable.Source(entityClass = LeadingExam.class, variableName = "period") })
public Period getPeriod() {
    return period;
}

public void setPeriod(Period period) {
    this.period = period;
}

@CustomShadowVariable(variableListenerRef = @PlanningVariableReference(variableName = "period"))
public Integer getVar() {
    return var;
}

public void setVar(Integer var) {
    this.var = var;
}

public LeadingExam getLeadingExam() {
    return leadingExam;
}

public void setLeadingExam(LeadingExam leadingExam) {
    this.leadingExam = leadingExam;
}

}

在 "PeriodUpdatingVariableListener" 我有下一个代码

public class PeriodUpdatingVariableListener implements VariableListener<LeadingExam> {

public void beforeEntityAdded(ScoreDirector scoreDirector, LeadingExam leadingExam) {
    // Do nothing
}

public void afterEntityAdded(ScoreDirector scoreDirector, LeadingExam leadingExam) {
    updatePeriod(scoreDirector, leadingExam);
}

public void beforeVariableChanged(ScoreDirector scoreDirector, LeadingExam leadingExam) {
    // Do nothing
}

public void afterVariableChanged(ScoreDirector scoreDirector, LeadingExam leadingExam) {
    updatePeriod(scoreDirector, leadingExam);
}

public void beforeEntityRemoved(ScoreDirector scoreDirector, LeadingExam leadingExam) {
    // Do nothing
}

public void afterEntityRemoved(ScoreDirector scoreDirector, LeadingExam leadingExam) {
    // Do nothing
}

protected void updatePeriod(ScoreDirector scoreDirector, LeadingExam leadingExam) {
    Period period = leadingExam.getPeriod();
    for (FollowingExam followingExam : leadingExam.getFollowingExamList()) {
        scoreDirector.beforeVariableChanged(followingExam, "period");
        followingExam.setPeriod(period);
        scoreDirector.afterVariableChanged(followingExam, "period");

        //additional lines of code to update the "var" variable
        Integer var = followingExam.getVar();
        if(var == null){
            var = new Integer(1);
        }
        else var++;
        scoreDirector.beforeVariableChanged(followingExam, "var");
        followingExam.setVar(var);
        scoreDirector.afterVariableChanged(followingExam, "var");

    }
}

}

OptaPlanner 似乎也没有问题注册这是另一个影子变量,因为我在 运行 应用程序

时收到此消息
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE     Model annotations parsed for Solution Examination:
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE         Entity Exam:
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE             Variable room (genuine)
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE         Entity LeadingExam:
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE             Variable period (genuine)
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE         Entity FollowingExam:
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE             Variable period (shadow)
2016-04-11 15:26:15,309 [AWT-EventQueue-0] TRACE             Variable var (shadow)

我得到的错误是下一个错误,只有当我将环境模式更改为 FULL_ASSERT 时才会出现此错误,但是当它保留为默认 REPRODUCIBLE 时它 运行s 没有任何错误。

Caused by: java.lang.IllegalStateException: VariableListener corruption: the entity (426)'s shadow variable (FollowingExam.var)'s corrupted value (null) changed to uncorrupted value (1) after all VariableListeners were triggered without changes to the genuine variables.
Probably the VariableListener class for that shadow variable (FollowingExam.var) forgot to update it when one of its sources changed after completedAction (Initial score calculated).
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.assertShadowVariablesAreNotStale(AbstractScoreDirector.java:349)
at org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller.solvingStarted(BestSolutionRecaller.java:84)
at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:196)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:175)
at org.optaplanner.examples.common.business.SolutionBusiness.solve(SolutionBusiness.java:307)
at org.optaplanner.examples.common.swingui.SolverAndPersistenceFrame$SolveWorker.doInBackground(SolverAndPersistenceFrame.java:287)
at org.optaplanner.examples.common.swingui.SolverAndPersistenceFrame$SolveWorker.doInBackground(SolverAndPersistenceFrame.java:1)
at javax.swing.SwingWorker.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at javax.swing.SwingWorker.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

变量侦听器中的这段代码是错误的:

    Integer var = followingExam.getVar();
    ...
    var++;
    ...
    followingExam.setVar(var);
    ...

如果它被多次调用,var 就会改变,即使真正的 var 没有改变。如果在评分规则中使用该变量,则对于同一解决方案,解决方案的分数并不总是相同。

影子变量是基于至少 1 个真实变量(直接或间接)的公式结果的缓存。例如阴影 C = 真正的 A + 问题 属性 B。因此,如果 B 为 10,A 的范围为 1 到 5,则如果 A 为 1,则 C 将为 11,如果 A 为 2,则为 12,等等