问题
We are trying to create a simple example to test the capabilities of OptaPlanner. In the following we show what we came up with. The problem with our example is that when we are selecting an exhaustive search algorithm for solving the problem, OptaPlanner terminates quickly with the wrong answer, which is always zero, even if zero is not a possible solution available from the ValueRangeProvider. Furthermore the PlanningVariable is not set during solving, as opposed to when local search is used.
We tried to change the algorithms in the examples that come with OptaPlanner (e.g. TSP), which worked. Therefore our question is: Why is our code not working?
MyPlanningEntity.java:
import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.variable.PlanningVariable;
@PlanningEntity
public class MyPlanningEntity {
@PlanningVariable(valueRangeProviderRefs = {"myListValueRangeProvider"})
private int myPlanningVariable;
public int getMyPlanningVariable() {
return myPlanningVariable;
}
public void setMyPlanningVariable(int myPlanningVariable) {
this.myPlanningVariable = myPlanningVariable;
}
}
MySolution.java:
import org.optaplanner.core.api.domain.solution.PlanningEntityProperty;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.domain.solution.Solution;
import org.optaplanner.core.api.domain.valuerange.CountableValueRange;
import org.optaplanner.core.api.domain.valuerange.ValueRangeFactory;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.score.buildin.simple.SimpleScore;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@PlanningSolution
public class MySolution implements Solution<SimpleScore> {
@PlanningEntityProperty
private MyPlanningEntity myPlanningEntity;
private SimpleScore score;
public MyPlanningEntity getMyPlanningEntity() {
return myPlanningEntity;
}
public void setMyPlanningEntity(MyPlanningEntity myPlanningEntity) {
this.myPlanningEntity = myPlanningEntity;
}
@ValueRangeProvider(id = "myListValueRangeProvider")
public List<Integer> getListValueRange(){
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
return list;
}
@Override
public SimpleScore getScore() {
return score;
}
@Override
public void setScore(SimpleScore simpleScore) {
this.score = simpleScore;
}
@Override
public Collection<?> getProblemFacts() {
return null;
}
}
MyScoreCalculator.java:
import org.optaplanner.core.api.score.Score;
import org.optaplanner.core.api.score.buildin.simple.SimpleScore;
import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator;
public class MyScoreCalculator implements EasyScoreCalculator<MySolution>{
@Override
public Score calculateScore(MySolution mySolution) {
// The higher the input, the higher the output
int value = mySolution.getMyPlanningEntity().getMyPlanningVariable();
return SimpleScore.valueOf(value);
}
}
ESTest.java:
import org.optaplanner.core.api.solver.Solver;
import org.optaplanner.core.api.solver.SolverFactory;
public class ESTest {
public static void run(){
SolverFactory solverFactory = SolverFactory.createFromXmlResource("resources/myPlanningProblem.xml");
Solver solver = solverFactory.buildSolver();
MySolution mySolution = new MySolution();
MyPlanningEntity myPlanningEntity = new MyPlanningEntity();
mySolution.setMyPlanningEntity(myPlanningEntity);
solver.solve(mySolution);
MySolution bestSolution = (MySolution) solver.getBestSolution();
System.out.println("Best solution: " + bestSolution.getMyPlanningEntity().getMyPlanningVariable());
}
public static void main(String args[]){
run();
}
}
myPlanningProblem.xml:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
<!-- Domain model configuration -->
<scanAnnotatedClasses/>
<scoreDirectorFactory>
<scoreDefinitionType>SIMPLE</scoreDefinitionType>
<easyScoreCalculatorClass>MyScoreCalculator</easyScoreCalculatorClass>
</scoreDirectorFactory>
<!-- THIS DOES NOT WORK STAND ALONE -->
<!--<constructionHeuristic>-->
<!--<constructionHeuristicType>FIRST_FIT</constructionHeuristicType>-->
<!--</constructionHeuristic>-->
<!-- THIS DOES NOT WORK STAND ALONE -->
<exhaustiveSearch>
<exhaustiveSearchType>BRUTE_FORCE</exhaustiveSearchType>
<termination>
<stepCountLimit>100</stepCountLimit>
</termination>
</exhaustiveSearch>
<!-- THIS WORKS BEAUTIFULLY -->
<!--<localSearch>-->
<!--<localSearchType>HILL_CLIMBING</localSearchType>-->
<!--<termination>-->
<!--<secondsSpentLimit>10</secondsSpentLimit>-->
<!--</termination>-->
<!--</localSearch>-->
</solver>
We are using OptaPlanner 6.3 Final.
This is what we get when OptaPlanner is started with this configuration:
14:58:58.742 [main] INFO o.o.core.impl.solver.DefaultSolver - Solving started: time spent (4), best score (0), environment mode (REPRODUCIBLE), random (JDK with seed 0).
14:58:58.745 [main] INFO o.o.c.i.e.DefaultExhaustiveSearchPhase - Exhaustive Search phase (0) ended: step total (0), time spent (7), best score (0).
14:58:58.745 [main] INFO o.o.core.impl.solver.DefaultSolver - Solving ended: time spent (7), best score (0), average calculate count per second (285), environment mode (REPRODUCIBLE).
Best solution: 0
Process finished with exit code 0
回答1:
A planning variable should be an Integer
, not an int
. It should start out as null
. If it starts out as 0
, OptaPlanner presumes it's already initialized and - by default - does not reinitialize that variable in CH or ES.
Maybe we should ban primitive types for planning variables?
来源:https://stackoverflow.com/questions/36309803/exhaustive-search-in-optaplanner-does-not-work-on-very-simple-example