熟悉optaplanner我创建了一个简单的测试项目。我只有一个解决方案和一个实体类。实体只有一个介于0和9之间的值。应该只有奇数,并且所有的总和应该小于10(这只是我提出的一些随机约束)。
作为分数我使用简单的HardSoftScore。这是代码:
public class TestScoreCalculator implements EasyScoreCalculator<TestSolution>{
@Override
public HardSoftScore calculateScore(TestSolution sol) {
int hardScore = 0;
int softScore = 0;
int valueSum = 0;
for (TestEntity entity : sol.getTestEntities()) {
valueSum += entity.getValue() == null? 0 : entity.getValue();
}
// hard Score
for (TestEntity entity : sol.getTestEntities()) {
if(entity.getValue() == null || entity.getValue() % 2 == 0)
hardScore -= 1; // constraint: only odd numbers
}
if(valueSum > 10)
hardScore -= 2; // constraint: sum should be less than 11
// soft Score
softScore = valueSum; // maximize
return HardSoftScore.valueOf(hardScore, softScore);
}
}
这是我的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
<!-- Domain model configuration -->
<scanAnnotatedClasses/>
<!-- Score configuration -->
<scoreDirectorFactory>
<easyScoreCalculatorClass>score.TestScoreCalculator</easyScoreCalculatorClass>
</scoreDirectorFactory>
<!-- Optimization algorithms configuration -->
<termination>
<secondsSpentLimit>30</secondsSpentLimit>
</termination>
</solver>
出于某种原因,OptaPlanner无法找到可行的解决方案。它以LS step (161217), time spent (29910), score (-2hard/10soft), best score (-2hard/10soft)...
和解决方案9 1 0 0
终止。
所以hardScore是-2,因为这两个0并不奇怪。例如,可能的解决方案是7 1 1 1
。为什么是这样 ?这应该是一个非常简单的例子......
(当我将“开始”值设置为7 1 1 1
时,它会以此解决方案终止,得分为(0hard/10soft)
它应该如何)
实体类
@PlanningEntity
public class TestEntity {
private Integer value;
@PlanningVariable(valueRangeProviderRefs = {"TestEntityValueRange"})
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
@ValueRangeProvider(id = "TestEntityValueRange")
public CountableValueRange<Integer> getStartPeriodRange() {
return ValueRangeFactory.createIntValueRange(0, 10);
}
}
解决方案类
@PlanningSolution
public class TestSolution {
private List<TestEntity> TestEntities;
private HardSoftScore score;
@PlanningEntityCollectionProperty
public List<TestEntity> getTestEntities() {
return TestEntities;
}
public void setTestEntities(List<TestEntity> testEntities) {
TestEntities = testEntities;
}
@PlanningScore
public HardSoftScore getScore() {
return score;
}
public void setScore(HardSoftScore score) {
this.score = score;
}
@Override
public String toString() {
String str = "";
for (TestEntity testEntity : TestEntities)
str += testEntity.getValue()+" ";
return str;
}
}
主程序课程
public class Main {
public static final String SOLVER_CONFIG = "score/TestConfig.xml";
public static int printCount = 0;
public static void main(String[] args) {
init();
}
private static void init() {
SolverFactory<TestSolution> solverFactory = SolverFactory.createFromXmlResource(SOLVER_CONFIG);
Solver<TestSolution> solver = solverFactory.buildSolver();
TestSolution model = new TestSolution();
List<TestEntity> list = new ArrayList<TestEntity>();
// list.add(new TestEntity(){{setValue(7);}});
// list.add(new TestEntity(){{setValue(1);}});
// list.add(new TestEntity(){{setValue(1);}});
// list.add(new TestEntity(){{setValue(1);}});
for (int i = 0; i < 4; i++) {
list.add(new TestEntity());
}
model.setTestEntities(list);
// Solve the problem
TestSolution solution = solver.solve(model);
// Display the result
System.out.println(solution);
}
}
答案 0 :(得分:1)
它陷入局部最优,因为没有从实体获取1并将其交给另一个实体的移动。通过自定义移动,您可以添加。 这些类型的移动仅适用于数值范围(很少见,通常值范围是员工列表等),但它们应该是开箱即用的(随意为它们创建jira)。
无论如何,获得良好解决方案的另一种方法是添加 <exhaustiveSearch/>
,绕过本地搜索,从而绕过本地最优。但这并不能很好地扩展。