2.10 约束分值查看

324 阅读3分钟

这是我参与更文挑战的第13天,活动详情查看: 更文挑战

内容概要

上一篇章里,我们已经学习了如何为每个约束编写ConstraintWeight,以及如何动态调整约束权重,这一章我们来学习如何查看一个求解结果,哪些约束匹配了,又是多少分值。

在开发过程中,查看约束分值的最简单方法是打印 explainScore()的返回值,但此方法只能看到大概的信息。

System.out.println(scoreManager.explainScore(solution));

例如,在会议安排中,这意味着Task S51打破了硬约束:Speaker required room tag

Explanation of score (-1hard/-806soft):
    Constraint match totals:
        -1hard: constraint (Speaker required room tag) has 1 matches:
            -1hard: justifications ([S51])
        -340soft: constraint (Theme track conflict) has 32 matches:
            -20soft: justifications ([S68, S66])
            -20soft: justifications ([S61, S44])
            ...
        ...
    Indictments (top 5 of 72):
        -1hard/-22soft: justification (S51) has 12 matches:
            -1hard: constraint (Speaker required room tag)
            -10soft: constraint (Theme track conflict)
            ...
        ...

这些信息都是概略性的信息,如果要查看每个约束的匹配结果及分值,则可以通过ConstraintMatch API进行查看。

在求解器外使用Solver

例如web界面,需要呈现一个解决方案的分数和约束匹配信息,请使用ScoreManager API

ScoreManager<CloudBalance, HardSoftScore> scoreManager = ScoreManager.create(solverFactory);
ScoreExplanation<CloudBalance, HardSoftScore> scoreExplanation = scoreManager.explain(cloudBalance);

获取求解结果的总分值:

HardSoftScore score = scoreExplanation.getScore();

此外,ScoreExplanation可以通过约束性匹配总数 and/or 来查看分值。

scoreVisualization_edit.png

约束匹配信息

要查看每个约束条件的得分,可以从ScoreExplanation中获得ConstraintMatchTotals

Collection<ConstraintMatchTotal<HardSoftScore>> constraintMatchTotals = scoreExplanation.getConstraintMatchTotalMap().values();
for (ConstraintMatchTotal<HardSoftScore> constraintMatchTotal : constraintMatchTotals) {
    String constraintName = constraintMatchTotal.getConstraintName();
    // The score impact of that constraint
    HardSoftScore totalScore = constraintMatchTotal.getScore();

    for (ConstraintMatch<HardSoftScore> constraintMatch : constraintMatchTotal.getConstraintMatchSet()) {
        List<Object> justificationList = constraintMatch.getJustificationList();
        HardSoftScore score = constraintMatch.getScore();
        ...
    }
}

每个ConstraintMathTotal数代表一个约束匹配信息,并占总分数的一部分。所有ConstraintMatchTotal.getScore()的总和等于总分数。

规划实体热图

需要在用户界面中显示一个热图,可以查看每个PlanningEntity所匹配到的约束Score信息,突出PlanningEntityProblemFactScore的影响,可以从ScoreExplanation中获取Indictment信息:

Map<Object, Indictment<HardSoftScore>> indictmentMap = scoreExplanation.getIndictmentMap();
for (CloudProcess process : cloudBalance.getProcessList()) {
    Indictment<HardSoftScore> indictment = indictmentMap.get(process);
    if (indictment == null) {
        continue;
    }
    // The score impact of that planning entity
    HardSoftScore totalScore = indictment.getScore();

    for (ConstraintMatch<HardSoftScore> constraintMatch : indictment.getConstraintMatchSet()) {
        String constraintName = constraintMatch.getConstraintName();
        HardSoftScore score = constraintMatch.getScore();
        ...
    }
}

每个Indictment是对象所涉及的所有约束的总和。所有Indictment.getScoreTotal()的总和与总体分数不同,因为多个Indictments可以共享同一个ConstraintMatch

测试约束

建议为每个分数约束单独写一个单元测试,以检查它是否正确。不同的分数计算类型会有不同的测试工具。更多内容请我们后续会学习到。

总结

这一篇章比较短,但是非常的关键,我们通常编写一个约束规则后,需要进行测试查看此约束是否生效,匹配的次数,分值的情况,如果没有这些我们没有办法去判断一个约束是否起到了作用,而且在需要做一个页面来支持动态调整PlanningEntity、ProblemFact,来观察最后的约束分值情况,以帮助我们来进行约束调整。后面我会单独抽出一个章节,来讲解如何使用。

结束语

至此我们已经学习了OptaPlanner绝大多数的概念,后面的篇章会围绕如何编写约束规则来进行,结合案例来学习,使大家更能掌握这一技能。

创作不易,禁止未授权的转载。如果我的文章对您有帮助,就请点赞/收藏/关注鼓励支持一下吧💕💕💕💕💕💕