Nous essayons de créer un exemple simple pour tester les capacités de OptaPlanner. Dans la suite, nous montrons ce que nous avons imaginé. Le problème avec notre exemple est que lorsque nous sélectionnons un algorithme de recherche exhaustive pour résoudre le problème, OptaPlanner se termine rapidement avec la mauvaise réponse, qui est toujours zéro, même si zéro n'est pas une solution possible disponible à partir du ValueRangeProvider. En outre, PlanningVariable n'est pas défini pendant la résolution, contrairement à lorsque la recherche locale est utilisée.Recherche exhaustive dans OptaPlanner ne fonctionne pas sur un exemple très simple
Nous avons essayé de modifier les algorithmes dans les exemples fournis avec OptaPlanner (par exemple, TSP), ce qui a fonctionné. Par conséquent, notre question est la suivante: pourquoi notre code ne fonctionne-t-il pas?
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>
Nous utilisons OptaPlanner 6.3 final.
C'est ce que nous obtenons quand OptaPlanner commence avec cette 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
Une recherche exhaustive fait beaucoup d'étapes, donc un 'stepCountLimit' de 100 semble très faible. Pouvez-vous supprimer cette ligne entièrement? Cela n'aura pas d'importance: 1 entité avec 4 valeurs signifierait 4^1 solutions, donc peu probable que nous atteindrons 100 pas, même avec force brute ou branch et bound. –
Jetez également un coup d'œil à 'ValueRangeFactory.createIntValueRange (1,5)' pour économiser de la mémoire. –