使用 optaplanner 时不会过滤未初始化的影子变量

问题描述 投票:0回答:1

当我使用影子变量时,在分数计算过程中出现空指针异常。 我记得在optaplanner文档中,没有赋值的规划变量会被自动过滤掉。

我想要实现的是,当ComposeCourseClazz的规划变量发生变化时,CourseClazz的规划变量也随之变化。

我的代码

Planning entities: 

@PlanningEntity
@EqualsAndHashCode(of = "id")
public class ComposeCourseClazz {
   
   @PlanningId
   private String id;

   @PlanningVariable(valueRangeProviderRefs = {"slots"})
   private Timeslot slot;

   @ValueRangeProvider(id = "slots")
   private List<Timeslot> slotList;
   
   private List<CourseClazz> ccList;
   ...
}

@EqualsAndHashCode(of = "id")
@PlanningEntity
public class CourseClazz {

    @PlanningId
    private String id;

    @ShadowVariable(variableListenerClass = SlotUpdatingVariableListener.class,
            sourceEntityClass = ComposeCourseClazz.class, sourceVariableName = "slot")
    private Timeslot slot;
    ...
}

Listener:
public class SlotUpdatingVariableListener implements VariableListener<CourseSchedule, ComposeCourseClazz> {
  @Override
    public void afterVariableChanged(ScoreDirector<CourseSchedule> scoreDirector, ComposeCourseClazz composeCourseClazz) {
        updateSlotForCC(scoreDirector, composeCourseClazz);
        
    }

    @Override
    public void afterEntityAdded(ScoreDirector<CourseSchedule> scoreDirector, ComposeCourseClazz composeCourseClazz) {
        updateSlotForCC(scoreDirector, composeCourseClazz);
    }
    protected void updateSlotForCC(ScoreDirector<CourseSchedule> scoreDirector, ComposeCourseClazz composeCourseClazz) {
        Timeslot slot = composeCourseClazz.getSlot();
        for (CourseClazz cc : composeCourseClazz.getCcList()) {
            scoreDirector.beforeVariableChanged(cc, "slot");
            cc.setSlot(slot);
            scoreDirector.afterVariableChanged(cc, "slot");
        }
    }
}

异常消息:

org.drools.modelcompiler.constraints.ConstraintEvaluationException: Error evaluating constraint '' in  and in more rules
    at org.drools.modelcompiler.constraints.LambdaConstraint.isAllowed(LambdaConstraint.java:184) ~[drools-model-compiler-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.PhreakAccumulateNode.propagateResult(PhreakAccumulateNode.java:665) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.PhreakGroupByNode.evaluateResultConstraints(PhreakGroupByNode.java:75) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.PhreakAccumulateNode.doNode(PhreakAccumulateNode.java:109) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(RuleNetworkEvaluator.java:593) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(RuleNetworkEvaluator.java:562) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleNetworkEvaluator.evalNode(RuleNetworkEvaluator.java:389) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:349) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleNetworkEvaluator.evalStackEntry(RuleNetworkEvaluator.java:247) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:190) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:143) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleExecutor.evaluateNetwork(RuleExecutor.java:221) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleExecutor.evaluateNetworkIfDirty(RuleExecutor.java:231) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:76) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.core.concurrent.AbstractGroupEvaluator.evaluateAndFire(AbstractGroupEvaluator.java:46) ~[drools-core-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.kiesession.agenda.DefaultAgenda.fireLoop(DefaultAgenda.java:624) ~[drools-kiesession-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.kiesession.agenda.DefaultAgenda.internalFireAllRules(DefaultAgenda.java:571) ~[drools-kiesession-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.kiesession.agenda.DefaultAgenda.fireAllRules(DefaultAgenda.java:563) ~[drools-kiesession-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.kiesession.session.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1088) ~[drools-kiesession-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.kiesession.session.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1079) ~[drools-kiesession-8.44.0.Final.jar:8.44.0.Final]
    at org.drools.kiesession.session.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1071) ~[drools-kiesession-8.44.0.Final.jar:8.44.0.Final]
    at org.optaplanner.constraint.streams.drools.DroolsConstraintStreamScoreDirector.calculateScore(DroolsConstraintStreamScoreDirector.java:70) ~[optaplanner-constraint-streams-drools-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller.solvingStarted(BestSolutionRecaller.java:50) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.solver.AbstractSolver.solvingStarted(AbstractSolver.java:65) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:225) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:192) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.solver.DefaultSolverJob.call(DefaultSolverJob.java:109) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:317) ~[na:na]
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:1589) ~[na:na]

在评分函数中,我过滤掉未分配的影子变量。并添加新的惩罚函数来惩罚未分配的影子变量。

optaplanner
1个回答
0
投票

虽然不是您问题的直接答案,但您可能想查看 Timefold Solver - OptaPlanner 的一个维护良好的分支。与 OptaPlanner 代码库相比,它包含近 15 个月的新功能和错误修复,而且您提到的例外情况在那里甚至是不可能的。

您甚至可能受益于级联更新影子变量,这是最近推出的一项功能,它极大地简化了尾链的更新,并帮助用户在实现变量侦听器时避免错误。

© www.soinside.com 2019 - 2024. All rights reserved.