VariableListener损坏

时间:2016-04-11 13:41:08

标签: optaplanner

我正在玩自定义阴影变量和自定义变量监听器。我发现“检查时间表”示例使用自定义阴影变量在“Leading Exam”更改时更新“以下检查”。 所以我在这个问题中断言要求的是真的Custom VariableListener updating more than one shadow variables我在Follow Exam类中添加了第二个影子变量,它引用变量“period”,然后在LeadingExam规划实体的变量监听器中(PeriodUpdatingVariableListener)我更新了两个变量。

以下是“FollowingExam”类的代码

@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时,它会运行而没有任何错误。

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$1.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)

1 个答案:

答案 0 :(得分:2)

变量监听器中的这段代码很糟糕:

    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,则C将是12,等等。