OptaPlaner简单示例无法找到可行的解决方案

时间:2017-08-10 12:49:32

标签: optaplanner drools-planner

熟悉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);
    }

}

1 个答案:

答案 0 :(得分:1)

它陷入局部最优,因为没有从实体获取1并将其交给另一个实体的移动。通过自定义移动,您可以添加。 这些类型的移动仅适用于数值范围(很少见,通常值范围是员工列表等),但它们应该是开箱即用的(随意为它们创建jira)。

无论如何,获得良好解决方案的另一种方法是添加 <exhaustiveSearch/> ,绕过本地搜索,从而绕过本地最优。但这并不能很好地扩展。