2017-08-10 2 views
0

pour se familiariser avec optaplanner J'ai créé un projet de test simple. J'ai seulement une solution et une classe d'entité. L'entité n'a qu'une seule valeur entre 0 et 9. Il ne devrait y avoir que des nombres impairs et la somme de tous devrait être inférieure à 10 (ce ne sont que quelques contraintes aléatoires que j'ai trouvées).Exemple simple OptaPlaner ne peut pas trouver la solution possible

Comme Score j'utilise un HardSoftScore simple. Voici le code:

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

et voici mon fichier de configuration:

<?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> 

pour une raison OptaPlanner ne peux pas trouver une solution réalisable. Il se termine par LS step (161217), time spent (29910), score (-2hard/10soft), best score (-2hard/10soft)... et la solution 9 1 0 0. Donc le hardScore est -2 car les deux 0 ne sont pas impairs. Une solution possible serait 7 1 1 1 par exemple. Pourquoi est-ce ? Cela devrait être un exemple très facile ...

(quand je mets les valeurs de début de 7 1 1 1 termine avec cette solution et un score de (0hard/10soft) comment il devrait être)


Edit:

L'entité classe

@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); 
    } 

} 

La solution classe

@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; 
    }  
} 

La classe

Programme principal
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

Pouvez-vous joindre une source de solution/entité et un ensemble de jeux de données que vous utilisez? –

Répondre

1

Il se coince dans une optima locale parce qu'il n'y a aucun mouvement qui prend 1 de l'entité et donne à une autre entité. Avec un déplacer personnalisé, vous pouvez ajouter cela. Ces types de mouvements ne s'appliquent qu'aux plages de valeurs numériques (qui sont rares, généralement les plages de valeurs sont une liste d'employés, etc.), mais elles devraient probablement exister immédiatement (n'hésitez pas à créer un jira).

Quoi qu'il en soit, une autre façon d'obtenir la bonne solution est d'ajouter <exhaustiveSearch/>, que de contourner la recherche locale et donc les optima locaux. Mais cela ne va pas bien.

+0

ah ok je pense que je comprends ce que le problème est ... mal essayer avec un mouvement personnalisé – MrWoffle