2016-03-30 2 views
2

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 
+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. –

+0

Jetez également un coup d'œil à 'ValueRangeFactory.createIntValueRange (1,5)' pour économiser de la mémoire. –

Répondre

3

Une variable de planification devrait être un Integer, pas int. Il devrait commencer comme null. S'il commence comme 0, OptaPlanner suppose qu'il est déjà initialisé et - par défaut - ne réinitialise pas cette variable dans CH ou ES.

Maybe we should ban primitive types for planning variables?

+0

Interdire les types primitifs est une excellente idée. Cependant, lorsque nous implémentons la version 'Integer', nous obtenons un' NullPointerExeption' dans le calcul du score. Nous devons attraper ce cas explicitement et lui donner un très mauvais score. Y a-t-il une meilleure manière de faire cela? – Konstantin

+0

Effectue une vérification nulle dans le calcul du score. Par exemple dans les règles de drools: 'quand MyEntity (myValue! = Null, $ v: value) alors ... addSoft (- $ v); fin » –