Java OptaPlanner';腐败的神话分数
我对我的模型使用增量分数计算器。在“完全断言”模式下进行数小时/数天的优化后,将抛出分数损坏异常:Java OptaPlanner';腐败的神话分数,java,optimization,optaplanner,Java,Optimization,Optaplanner,我对我的模型使用增量分数计算器。在“完全断言”模式下进行数小时/数天的优化后,将抛出分数损坏异常: java.lang.IllegalStateException: Score corruption: the workingScore (-86591/-2765/-422/-591) is not the uncorruptedScore (-86591/-2873/-422/-591) after completedAction [...]: Uncorrupted: Score calcul
java.lang.IllegalStateException: Score corruption: the workingScore (-86591/-2765/-422/-591) is not the uncorruptedScore (-86591/-2873/-422/-591) after completedAction [...]:
Uncorrupted: Score calculator 3718238 [schedule=Schedule6422-2015-04-16T09:47:36.932[-86591/-2873/-422/-591], prioritiesScore=-422, timelineGapsScore=-2873, requirementGapsScore=-86591, timelineVersionsScore=-591]
Corrupted: Score calculator 3717237 [schedule=Schedule6422-2015-04-16T09:47:36.932[-86591/-2873/-422/-591], prioritiesScore=-422, timelineGapsScore=-2873, requirementGapsScore=-86591, timelineVersionsScore=-591]
这就是参数TimeLineGapScore
中的分数不同。分数实例是从分数计算器对象字段prioritizesscore
,timelinegapscore
,requirementgapscore
和timelineversionscore
创建的。根据日志,这两个分数的实例在这些字段中是相等的,但optaplanner引擎发现了差异(-86591/-2765/-422/-591)与(-86591/-2873/-422/-591)。这怎么可能
我怀疑在解决方案克隆(它的具体实现和深度复制)上存在引用泄漏,但仔细的代码检查并没有显示此类错误
UPD:我忘了提到:optaplanner在守护程序模式下运行,模型能够实时更改事实。所以我怀疑模型中的种族条件。但我不知道在optaplanner的保护下如何实现变化(信息不够)。“当解决方案发生变化时,增量分数计算(也称为基于增量的分数计算)将计算具有先前状态的增量以找到新分数,而不是在每次解决方案评估时重新计算整个分数
例如,如果一个皇后a从第1行移动到第2行,它就不需要检查皇后B和皇后C是否可以互相攻击,因为它们都没有改变。”
当增量分数和实际分数(=未损坏分数)不同步时,分数损坏发生。
可能有几个原因。如果您使用Drools分数计算,它甚至可能是Drools中的一个bug。如果你能把它分离出来,用复制机归档一份jira,那么我们通常会很快给你看
隔离意味着(按此顺序!):
这是我的实现错误。在增量分数计算器实现时要准确(或者尝试使用Drools)。我使用普通Java分数计算器而不是Drools,不幸的是,这段代码是高度耦合的。根据日志,optaplanner将原始解决方案S0克隆到S1,然后在S0上执行几个步骤,这些步骤从逻辑上导致初始解决方案(例如,交换移动AB、BA、AC、CA),然后检查分数等价性分数(S0)=分数(S1)。当然,在我的例子中,这样的等式是成立的,但是分数实例是不同的,尽管我使用简单的代码创建分数:
return BendableScore.valueOf(new int[]{requirementgapscore,timelinegapscore},new int[]{priorityesscore,timelineversionscore})
使用EasyJavaScoreCalculator
,分数损坏是不可能的。我猜您正在使用增量JavaScoreCalculator
?很高兴听到Drools中没有bug:)在NQueens示例实现中,在sandwished的情况下,B和C被认为是相互攻击的。但即使sandswish并没有攻击要求,您也可以通过跟踪sandswish状态来进行增量计算以更好地扩展。@GeoffreyDeSmet我为问题添加了细节。顺便说一句,关于文档:误导:calculateScore()调用不是在每次交换移动之后。在实时模型更改的描述中可能存在类似的错误:)OptaPlanner可以跳过calculateScore()
,如果它不需要它(或者它可以预测它),以提高性能,因此我可以在调用calculateScore()
之前先做几步。如果使用CompositeMove(例如,如果您的实体上有2个变量),则这一点更为重要。只要您正确使用addProblemFactChange()
修改解算器中的模型(因为该回调在解算器线程内执行),就不可能出现争用条件。请注意addProblemFactChange()
确实可能很棘手。它通常需要进行更深入的克隆,而不仅仅是计划中的克隆。例如,要在CB示例中添加新计算机,需要克隆computerList(这在计划克隆中不会发生)。