3.1。分数计算类型
Optaplanner有几种计算Score解的方法:
-
简单的 Java 分数计算:在 Java(或另一种 JVM 语言)中的单个方法中一起实现所有约束。不缩放。
-
约束流分数计算:在 Java(或另一种 JVM 语言)中将每个约束实现为单独的约束流。快速且可扩展。
-
增量 Java 分数计算(不推荐):在 Java(或另一种 JVM 语言)中实现多个低级方法。快速且可扩展。非常难以实施和维护。
-
Drools 分数计算(已弃用):将每个约束实现为 DRL 中的单独分数规则。可扩展。
每个分数计算类型都可以使用任何分数定义(例如HardSoftScore或HardMediumSoftScore)一起使用。所有分数计算类型都是面向对象的,并且可以重用现有的 Java 代码。
- 分数计算必须是只读的。它不得以任何方式改变规划实体或问题事实。例如,它不能在分数计算中调用计划实体的 setter 方法。
- 要在规划变量变化时更新规划实体,可使用影子变量。
3.2. 简单的 Java 分数计算
一种在 Java 中实现分数计算的简单方法。
-
优点:
-普通的旧 Java:没有学习曲线、
-将分数计算委托给现有代码库或遗留系统的机会 -
缺点:
-慢点
-无法扩展,因为没有增量分数计算
实现接口的一种方法EasyScoreCalculator:
public interface EasyScoreCalculator<Solution_, Score_ extends Score<Score_>> {
Score_ calculateScore(Solution_ solution);
}
例如在 n 个皇后中:
public class NQueensEasyScoreCalculator
implements EasyScoreCalculator<NQueens, SimpleScore> {
@Override
public SimpleScore calculateScore(NQueens nQueens) {
int n = nQueens.getN();
List<Queen> queenList = nQueens.getQueenList();
int score = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
Queen leftQueen = queenList.get(i);
Queen rightQueen = queenList.get(j);
if (leftQueen.getRow() != null && rightQueen.getRow() != null) {
if (leftQueen.getRowIndex() == rightQueen.getRowIndex()) {
score--;
}
if (leftQueen.getAscendingDiagonalIndex() == rightQueen.getAscendingDiagonalIndex()) {
score--;
}
if (leftQueen.getDescendingDiagonalIndex() == rightQueen.getDescendingDiagonalIndex()) {
score--;
}
}
}
}
return SimpleScore.valueOf(score);
}
}
在求解器配置中配置它:
<scoreDirectorFactory>
<easyScoreCalculatorClass>org.optaplanner.examples.nqueens.optional.score.NQueensEasyScoreCalculator</easyScoreCalculatorClass>
</scoreDirectorFactory>
如果需要在求解器配置中动态地配置EasyScoreCalculator的值(以便Benchmarker可以调整这些参数),请添加easyScoreCalculatorCustomProperties元素并使用自定义属性:
<scoreDirectorFactory>
<easyScoreCalculatorClass>...MyEasyScoreCalculator</easyScoreCalculatorClass>
<easyScoreCalculatorCustomProperties>
<property name="myCacheSize" value="1000" />
</easyScoreCalculatorCustomProperties>
</scoreDirectorFactory>
3.3. 增量 Java 分数计算
一种在 Java 中逐步实现分数计算的方法。
-
优点:
非常快速且可扩展
如果正确实施,目前最快 -
缺点:
很难写
-可扩展的实现大量使用地图、索引……(Drools 规则引擎可以为您做的事情)
-您必须自己学习、设计、编写和改进所有这些性能优化 -
难以阅读
定期更改分数约束可能会导致高昂的维护成本
实现接口IncrementalScoreCalculator的所有方法:
public interface IncrementalScoreCalculator<Solution_, Score_ extends Score<Score_>> {
void resetWorkingSolution(Solution_ workingSolution);
void beforeEntityAdded(Object entity);
void afterEntityAdded(Object entity);
void beforeVariableChanged(Object entity, String variableName);
void afterVariableChanged(Object entity, String variableName);
void beforeEntityRemoved(Object entity);
void afterEntityRemoved(Object entity);
Score_ calculateScore();
}