Chapter 1. Changes that are not compatible with OptaPlanner 7.x or earlier
Chapter 1. Changes that are not compatible with OptaPlanner 7.x or earlier The changes listed in this section are not compatible with OptaPlanner 7.x or earlier versions of OptaPlanner. Java 11 or higher required Major , Public API If you are using JRE or JDK 8, upgrade to JDK 11 or higher. On Linux, get OpenJDK from your Linux software repository. On Fedora and Red Hat Enterprise Linux, enter the following command: sudo dnf install java-11-openjdk-devel On Windows and macOS, download OpenJDK from the AdoptOpenJDK website. SolverFactory and PlannerBenchmarkFactory no longer support KIE containers Major , Public API Because OptaPlanner now aligns with Kogito, the KIE container concept no longer applies. Therefore, SolverFactory no longer allows you to create Solver instances from KIE containers. This also applies to PlannerBenchmarkFactory and benchmarks. OSGi metadata removed Major , Public API Because of the limited usage of OSGi and the maintenance burden it brings, the OptaPlanner JAR files in the OptaPlanner 8.x series no longer include OSGi metadata in the META-INF/MANIFEST.MF file. Refrain from using Java serialization Minor , Public API In OptaPlanner 8, most uses of the Serializable marker interface were removed from the public API. Consider serializing with JSON or another format. SolverFactory.getScoreDirectorFactory() replaced with ScoreManager Major , Public API In version 7 of OptaPlanner, using ScoreDirectorFactory was necessary in order to explain the score. In version 8 of OptaPlanner, new functionality was added to the ScoreManager and as a result there is no longer any reason to create new instances of ScoreDirector . An example from a *.java file in OptaPlanner 7: ScoreDirectorFactory<CloudBalance> scoreDirectorFactory = solverFactory.getScoreDirectorFactory(); try (ScoreDirector<CloudBalance> scoreDirector = scoreDirectorFactory.buildScoreDirector()) { scoreDirector.setWorkingSolution(solution); Score score = scoreDirector.calculateScore(); } An example from a *.java file in OptaPlanner 8: ScoreManager<CloudBalance> scoreManager = ScoreManager.create(solverFactory); Score score = scoreManager.updateScore(solution); Methods that allowed you to retrieve an instance of ScoreDirector and ScoreDirectorFactory have been removed from the public API without replacement. A reduced version of the ScoreDirector interface was promoted to the public API to promote the ProblemFactChange interface to the public API. SolverFactory : getSolverConfig() removed Minor , Public API The SolverFactory.getSolverConfig() method has been deprecated and replaced with the SolverFactory.create(SolverConfig) method. A SolverConfig instance is now instantiated before a SolverFactory instance is instantiated, which is more natural. The order has been removed. An example from a *.java file in OptaPlanner 7: SolverFactory<MySolution> solverFactory = SolverFactory.createFromXmlResource(".../mySolverConfig.xml"); SolverConfig solverConfig = solverFactory.getSolverConfig(); ... Solver<MySolution> solver = solverFactory.buildSolver(); An example from a *.java file in OptaPlanner 8: SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); ... SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); If you were also passing a ClassLoader , pass it to both SolverConfig.createFromXmlResource() and SolverFactory.create() . SolverConfig : buildSolver() removed Minor , Public API The SolverConfig.buildSolver() method is an inner method that does not belong in the public API. Use the SolverFactory.buildSolver() method instead. An example from a *.java file in OptaPlanner 7: SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); ... Solver<MySolution> solver = solverConfig.buildSolver(); An example from a *.java file in OptaPlanner 8: SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); ... SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); PlannerBenchmarkConfig : buildPlannerBenchmark() removed Minor , Public API The PlannerBenchmarkConfig.buildPlannerBenchmark() method is an inner method that does not belong in the public API. Use the PlannerBenchmarkFactory.buildPlannerBenchmark() method instead. An example from a *.java file in OptaPlanner 7: PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); ... PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); An example from a *.java file in OptaPlanner 8: PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); ... PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.create(benchmarkConfig); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); SolverFactory : cloneSolverFactory() removed Minor , Public API The SolverFactory.cloneSolverFactory() method has been deprecated and replaced with the new SolverConfig(SolverConfig) copy constructors and the SolverFactory.cloneSolverFactory() method has been removed. An example from a *.java file in OptaPlanner 7: private SolverFactory<MySolution> base; public void userRequest(..., long userInput) { SolverFactory<MySolution> solverFactory = base.cloneSolverFactory(); solverFactory.getSolverConfig() .getTerminationConfig() .setMinutesSpentLimit(userInput); Solver<MySolution> solver = solverFactory.buildSolver(); ... } An example from a *.java file in OptaPlanner 8: private SolverConfig base; public void userRequest(..., long userInput) { SolverConfig solverConfig = new SolverConfig(base); // Copy it solverConfig.getTerminationConfig() .setMinutesSpentLimit(userInput); SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); ... } SolverFactory : createEmpty() removed Minor , Public API The SolverFactory.createEmpty() method has been deprecated and replaced with the new SolverConfig() method. The SolverFactory.createEmpty() method has been removed. An example from a *.java file in OptaPlanner 7: SolverFactory<MySolution> solverFactory = SolverFactory.createEmpty(); SolverConfig solverConfig = solverFactory.getSolverConfig() ... Solver<MySolution> solver = solverFactory.buildSolver(); An example from a *.java file in OptaPlanner 8: SolverConfig solverConfig = new SolverConfig(); ... SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); XML <solver/> root element now belongs to the http://www.optaplanner.org/xsd/solver namespace Major , Public API OptaPlanner now provides an XML schema definition for the solver configuration. Although OptaPlanner retains compatibility with versions of the existing XML configuration, migrating to the XSD is strongly recommended because OptaPlanner might support only valid configuration XML in the future. An example from the *SolverConfig.xml file in OptaPlanner 7: <?xml version="1.0" encoding="UTF-8"?> <solver> ... </solver> An example from the *SolverConfig.xml file in OptaPlanner 8: <?xml version="1.0" encoding="UTF-8"?> <solver xmlns="https://www.optaplanner.org/xsd/solver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd"> ... </solver> Using the XSD might require reordering some of the XML elements of the configuration. Use code completion in the IDE to migrate to a valid XML. Property subPillarEnabled in move selector configuration has been removed Minor , Public API The subPillarEnabled property in PillarSwapMoveSelector and PillarChangeMoveSelector has been deprecated and replaced with a new property, subPillarType . The subPillarEnabled property has been removed. An example from the *SolverConfig.xml and *BenchmarkConfig.xml files in OptaPlanner 7: <pillar...MoveSelector> ... <pillarSelector> <subPillarEnabled>false</subPillarEnabled> ... </pillarSelector> ... </pillar...MoveSelector> An example from the *SolverConfig.xml and *BenchmarkConfig.xml files in OptaPlanner 8: <pillar...MoveSelector> <subPillarType>NONE</subPillarType> <pillarSelector> ... </pillarSelector> ... </pillar...MoveSelector> Solver : getScoreDirectorFactory() removed Major , Public API The getScoreDirectorFactory() method has been deprecated and has now been removed from both Solver and SolverFactory classes. You no longer need to create a Solver instance just to calculate or explain a score in the UI. Use the ScoreManager API instead. An example from a *.java file in OptaPlanner 7: SolverFactory<VehicleRoutingSolution> solverFactory = SolverFactory.createFromXmlResource(...); Solver<VehicleRoutingSolution> solver = solverFactory.buildSolver(); uiScoreDirectorFactory = solver.getScoreDirectorFactory(); ... An example from a *.java file in OptaPlanner 8: SolverFactory<VehicleRoutingSolution> solverFactory = SolverFactory.createFromXmlResource(...); ScoreManager<VehicleRoutingSolution> scoreManager = ScoreManager.create(solverFactory); ... ScoreDirectorFactory should not be used anymore because it has always been outside the public API and all of its functionality is exposed in various parts of the public API. Solver.explainBestScore() has been removed Major , Public API The explainBestScore() method on the Solver interface was deprecated in 7.x and has now been removed. You can obtain the same information through the new ScoreManager API. Red Hat recommends that you do not parse the results of this method call in any way. An example from a *.java file in OptaPlanner 7: solver = ...; scoreExplanation = solver.explainBestScore(); An example from a *.java file in OptaPlanner 8: MySolution solution = ...; ScoreManager<MySolution> scoreManager = ...; scoreExplanation = scoreManager.explainScore(solution); The Solver interface methods getBestSolution() , getBestScore() , and getTimeMillisSpent() have been removed Minor , Public API Several methods on the Solver interface were deprecated in 7.x and have been removed. You can obtain the same information by registering an EventListener through the Solver.addEventListener(... ) . An example from a *.java file in OptaPlanner 7: solver = ...; solution = solver.getBestSolution(); score = solver.getBestScore(); timeMillisSpent = solver.getTimeMillisSpent(); An example from a *.java file in OptaPlanner 8: solver = ...; solver.addEventListener(event -> { solution = event.getNewBestSolution(); score = event.getNewBestScore(); timeMillisSpent = event.getTimeMillisSpent(); }); Annotation scanning has been removed Major , Public API The <scanAnnotatedClasses/> directive in the solver configuration was deprecated in 7.x and is now removed. An example from the *.xml file in OptaPlanner 7: <solver> ... <scanAnnotatedClasses/> ... </solver> An example from the *.xml file in OptaPlanner 8: <solver> ... <solutionClass>...</solutionClass> <entityClass>...</entityClass> ... </solver> New package for @PlanningFactProperty and @PlanningFactCollectionProperty Major , Public API The @PlanningFactProperty and @PlanningFactCollectionProperty annotations now share the same package with other similar annotations, such as @PlanningSolution . The old annotations were deprecated in 7.x and removed. An example from a *.java file in OptaPlanner 7: import org.optaplanner.core.api.domain.solution.drools.ProblemFactCollectionProperty; import org.optaplanner.core.api.domain.solution.drools.ProblemFactProperty; An example from a *.java file in OptaPlanner 8: import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty; import org.optaplanner.core.api.domain.solution.ProblemFactProperty; filterClassList replaced with a single filter class Minor , Public API The configuration of EntitySelector , ValueSelector , and MoveSelector now has a single filter class in both the configuration API and the solver configuration XML. In practice, you do not need multiple selection filter classes often, and you can replace them with a single selection filter class that implements the logic of all of them. Passing a single selection class now requires less boilerplate code. An example from a *.java file in OptaPlanner 7: ValueSelectorConfig valueSelectorConfig = new ValueSelectorConfig(); valueSelectorConfig.setFilterClassList(Collections.singletonList(MySelectionFilterClass.class)); An example from a *.java file in OptaPlanner 8: ValueSelectorConfig valueSelectorConfig = new ValueSelectorConfig(); valueSelectorConfig.setFilterClass(MySelectionFilterClass.class); Replacing multiple selection filter classes with a single selection filter class An example from the *.xml file in OptaPlanner 7: <swapMoveSelector> <entitySelector> <filterClass>com.example.FilterA</filterClass> <filterClass>com.example.FilterB</filterClass> </entitySelector> </swapMoveSelector> An example from a *.java file in OptaPlanner 7: package com.example; ... public class FilterA implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getValue() < 500; } } package com.example; ... public class FilterB implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getOrder() == Order.ASC; } } An example from the *.xml file in OptaPlanner 8: <swapMoveSelector> <entitySelector> <filterClass>com.example.SingleEntityFilter</filterClass> </entitySelector> </swapMoveSelector> An example from a *.java file in OptaPlanner 8: package com.example; ... public class SingleEntityFilter implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getValue() < 500 && selection.getOrder() == Order.ASC; } } AcceptorConfig renamed to LocalSearchAcceptorConfig Minor This only impacts the configuration API. The solver configuration XML file remains intact. Naming consistency with other local-search-specific configuration classes has been implemented. An example from a *.java file in OptaPlanner 7: LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig() .withAcceptorConfig(new AcceptorConfig().withEntityTabuSize(5)); An example from a *.java file in OptaPlanner 8: LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig() .withAcceptorConfig(new LocalSearchAcceptorConfig().withEntityTabuSize(5)); Custom properties XML configuration format changes Minor , Public API This issue only impacts the solver configuration XML, specifically <scoreDirectorFactory/> , <moveIteratorFactory/> , <moveListFactory/> , <partitionedSearch/> and <customPhase/> . This change was made to enforce the structure of the configuration XML in build time. An example from the *.xml file in OptaPlanner 7: <partitionedSearch> <solutionPartitionerClass>com.example.MySolutionPartitioner</solutionPartitionerClass> <solutionPartitionerCustomProperties> <partCount>4</partCount> <!-- a custom property --> <minimumProcessListSize>300</minimumProcessListSize> <!-- a custom property --> </solutionPartitionerCustomProperties> </partitionedSearch> An example from the *.xml file in OptaPlanner 8: <partitionedSearch> <solutionPartitionerClass>com.example.MySolutionPartitioner</solutionPartitionerClass> <solutionPartitionerCustomProperties> <property name="partCount" value="4"/> <!-- a custom property --> <property name="minimumProcessListSize" value="300"/> <!-- a custom property --> </solutionPartitionerCustomProperties> </partitionedSearch> <variableNameInclude/> elements are now wrapped by the <variableNameIncludes/> element Minor , Public API This update only impacts the solver configuration XML, specifically the <swapMoveSelector/> and <pillarSwapMoveSelector/> elements. This change was made to enforce the structure of the configuration XML in build time. An example from the *.xml file in OptaPlanner 7: <swapMoveSelector> <variableNameInclude>variableA</variableNameInclude> <variableNameInclude>variableB</variableNameInclude> </swapMoveSelector> An example from the *.xml file in OptaPlanner 8: <swapMoveSelector> <variableNameIncludes> <variableNameInclude>variableA</variableNameInclude> <variableNameInclude>variableB</variableNameInclude> </variableNameIncludes> </swapMoveSelector> Solution interface removed Minor , Public API The Solution interface was deprecated and removed. The AbstractSolution interface, which is only used by Business Central, has also been removed. Remove the Solution interface, annotate the getScore() method with @PlanningScore , and replace the getProblemFacts() method with a @ProblemFactCollectionProperty annotation directly on every problem fact getter (or field). An example from a *.java file in OptaPlanner 7: @PlanningSolution public class CloudBalance implements Solution<HardSoftScore> { private List<CloudComputer> computerList; ... private HardSoftScore score; @ValueRangeProvider(id = "computerRange") public List<CloudComputer> getComputerList() {...} public HardSoftScore getScore() {...} public void setScore(HardSoftScore score) {...} public Collection<? extends Object> getProblemFacts() { List<Object> facts = new ArrayList<Object>(); facts.addAll(computerList); ... return facts; } } An example from a *.java file in OptaPlanner 8: @PlanningSolution public class CloudBalance { private List<CloudComputer> computerList; ... private HardSoftScore score; @ValueRangeProvider(id = "computerRange") @ProblemFactCollectionProperty public List<CloudComputer> getComputerList() {...} @PlanningScore public HardSoftScore getScore() {...} public void setScore(HardSoftScore score) {...} } For a single problem fact that is not wrapped in a Collection , use the @ProblemFactProperty annotation, as shown in the following example, with field annotations this time: An example from a *.java file in OptaPlanner 7: @PlanningSolution public class CloudBalance implements Solution<HardSoftScore> { private CloudParametrization parametrization; private List<CloudBuilding> buildingList; @ValueRangeProvider(id = "computerRange") private List<CloudComputer> computerList; ... public Collection<? extends Object> getProblemFacts() { List<Object> facts = new ArrayList<Object>(); facts.add(parametrization); // not a Collection facts.addAll(buildingList); facts.addAll(computerList); ... return facts; } } An example from a *.java file in OptaPlanner 8: @PlanningSolution public class CloudBalance { @ProblemFactProperty private CloudParametrization parametrization; @ProblemFactCollectionProperty private List<CloudBuilding> buildingList; @ValueRangeProvider(id = "computerRange") @ProblemFactCollectionProperty private List<CloudComputer> computerList; ... } Do not add the @ProblemFactCollectionProperty annotation on getters (or fields) that have a @PlanningEntityCollectionProperty annotation. BestSolutionChangedEvent : isNewBestSolutionInitialized() removed Minor , Public API The BestSolutionChangedEvent.isNewBestSolutionInitialized() method has been deprecated and replaced with the BestSolutionChangedEvent.getNewBestSolution().getScore().isSolutionInitialized() method. The BestSolutionChangedEvent.isNewBestSolutionInitialized() method has been removed. An example from a *.java file in OptaPlanner 7: public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() && event.isNewBestSolutionInitialized()) { ... } } An example from a *.java file in OptaPlanner 8: public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() && event.getNewBestSolution().getScore().isSolutionInitialized()) { ... } } If you check isFeasible() , it checks if the solution is initialized. An example from a *.java file in OptaPlanner 8: public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() // isFeasible() checks isSolutionInitialized() too && event.getNewBestSolution().getScore().isFeasible()) { ... } } <valueSelector> : variableName is now an attribute Minor , Public API When power-tweaking move selectors, such as <changeMoveSelector> , in a use case with multiple planning variables, the <variableName> XML element has been replaced with a variableName="... " XML attribute. This change reduces the solver configuration verbosity. After being deprecated for the entire 7.x series, the old way has now been removed. An example from the *SolverConfig.xml and *BenchmarkConfig.xml files in OptaPlanner 7: <valueSelector> <variableName>room</variableName> </valueSelector> An example from the *SolverConfig.xml and *BenchmarkConfig.xml files in OptaPlanner 8: <valueSelector variableName="room"/> Partitioned Search: threadFactoryClass removed Minor , Public API Because <solver> has supported a <threadFactoryClass> element for some time, the <threadFactoryClass> element under <partitionedSearch> has been removed. An example from the *SolverConfig.xml and *BenchmarkConfig.xml files in OptaPlanner 7: <solver> ... <partitionedSearch> <threadFactoryClass>...MyAppServerThreadFactory</threadFactoryClass> ... </partitionedSearch> </solver> An example from the *SolverConfig.xml and *BenchmarkConfig.xml files in OptaPlanner 8: <solver> <threadFactoryClass>...MyAppServerThreadFactory</threadFactoryClass> ... <partitionedSearch> ... </partitionedSearch> </solver> SimpleDoubleScore and HardSoftDoubleScore removed Minor , Public API The use of double-based score types is not recommended because they can cause score corruption. They have been removed. An example from a *.java file in OptaPlanner 7: @PlanningSolution public class MyPlanningSolution { private SimpleDoubleScore score; ... } An example from a *.java file in OptaPlanner 8: @PlanningSolution public class MyPlanningSolution { private SimpleLongScore score; ... } Score.toInitializedScore() removed Minor , Public API The Score.toInitializedScore() method was deprecated and replaced with the Score.withInitScore(int) method in 7.x and is now removed. An example from a *.java file in OptaPlanner 7: score = score.toInitializedScore(); An example from a *.java file in OptaPlanner 8: score = score.withInitScore(0); Various justification Comparators removed Minor , Public API The following Comparator implementations were deprecated in 7.x and removed: org.optaplanner.core.api.score.comparator.NaturalScoreComparator org.optaplanner.core.api.score.constraint.ConstraintMatchScoreComparator org.optaplanner.core.api.score.constraint.ConstraintMatchTotalScoreComparator org.optaplanner.core.api.score.constraint.IndictmentScoreComparator An example from a *.java file in OptaPlanner 7: NaturalScoreComparator comparator = new NaturalScoreComparator(); ConstraintMatchScoreComparator comparator2 = new ConstraintMatchScoreComparator(); An example from a *.java file in OptaPlanner 8: Comparator<Score> comparator = Comparable::compareTo; Comparator<ConstraintMatch> comparator2 = Comparator.comparing(ConstraintMatch::getScore); FeasibilityScore removed Minor , Public API The FeasibilityScore interface was deprecated in 7.x and its only method isFeasible() moved to the Score supertype. The interface has now been removed. You should refer to Score s by their ultimate type, for example HardSoftScore instead of to Score . @PlanningEntity.movableEntitySelectionFilter removed Minor , Public API The movableEntitySelectionFilter field on the @PlanningEntity annotation was deprecated in 7.x and a new field pinningFilter has been introduced with a name that shows the relation to the @PlanningPin annotation. This filter implements a new PinningFilter interface, returning true if the entity is pinned, and false if movable. The logic of this new filter is therefore inverted as compared to the old filter. You should update your @PlanningEntity annotations by supplying the new filter instead of the old filter. The old filter has now been removed. An example from a *.java file in OptaPlanner 7: @PlanningEntity(movableEntitySelectionFilter = MyMovableEntitySelectionFilter.class) An example from a *.java file in OptaPlanner 8: @PlanningEntity(pinningFilter = MyPinningFilter.class) @PlanningVariable.reinitializeVariableEntityFilter removed Minor , Public API The reinitializeVariableEntityFilter field on the @PlanningVariable annotation was deprecated in 7.x and now removed. *ScoreHolder classes turned into interfaces Minor , Public API In OptaPlanner 7, ScoreHolder classes, used exclusively for Drools score calculation, exposed a number of public methods which, if used, allowed the user to unintentionally corrupt or otherwise negatively affect their scores. In OptaPlanner 8, these methods have been removed and the classes have been turned into interfaces. Most users do not use the removed and potentially harmful methods. However, if you do use these methods, you will find suitable replacements in the public API in areas of score explanation and constraint configuration. ValueRangeFactory class now final Minor ValueRangeFactory class is a factory class that has only static methods. There is no need for you to extend this class, and it has therefore been made final . An example from a *.java file in OptaPlanner 7: class MyValueRangeFactory extends ValueRangeFactory { ... } An example from a *.java file in OptaPlanner 8: class MyValueRangeFactory { ... } ConstraintMatchTotal and Indictment are now interfaces Minor , Public API ConstraintMatchTotal and Indictment classes have been converted into interfaces. As a result, their implementations were moved out of the public API, together with methods that allowed them to mutate their state. These methods were never intended for the public API, and therefore there is no replacement for them. You might still need the instances themselves if you choose to implement ConstraintMatchAwareIncrementalScoreCalculator : ConstraintMatchTotal maximumCapacityMatchTotal = new ConstraintMatchTotal(...); An example from a *.java file in OptaPlanner 8: ConstraintMatchTotal maximumCapacityMatchTotal = new DefaultConstraintMatchTotal(...); ScoreManager : generic type Score added Major , Public API The ScoreManager and ScoreExplanation APIs now have the generic type Score to avoid downcasts in your code, for example from Score to HardSoftScore . An example from a *.java file in OptaPlanner 7: @Inject // or @Autowired ScoreManager<TimeTable> scoreManager; An example from a *.java file in OptaPlanner 8: @Inject // or @Autowired ScoreManager<TimeTable, HardSoftScore> scoreManager; An example from a *.java file in OptaPlanner 7: ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); HardSoftScore score = (HardSoftScore) explanation.getScore(); An example from a *.java file in OptaPlanner 8: ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); HardSoftScore score = explanation.getScore(); ConstraintMatchTotal , ConstraintMatch , and Indictment : generic type Score added Major Similar to ScoreManager and ScoreExplanation , the ConstraintMatchTotal , ConstraintMatch , and Indictment APIs now have a generic type Score to avoid downcasts in your code, for example from Score to HardSoftScore . An example from a *.java file in OptaPlanner 7: ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); Map<String, ConstraintMatchTotal> constraintMatchTotalMap = scoreExplanation.getConstraintMatchTotalMap(); ConstraintMatchTotal constraintMatchTotal = constraintMatchTotalMap.get(contraintId); HardSoftScore totalScore = (HardSoftScore) constraintMatchTotal.getScore(); An example from a *.java file in OptaPlanner 8: ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); Map<String, ConstraintMatchTotal<HardSoftScore>> constraintMatchTotalMap = scoreExplanation.getConstraintMatchTotalMap(); ConstraintMatchTotal<HardSoftScore> constraintMatchTotal = constraintMatchTotalMap.get(contraintId); HardSoftScore totalScore = constraintMatchTotal.getScore(); An example from a *.java file in OptaPlanner 7: ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); Map<Object, Indictment> indictmentMap = scoreExplanation.getIndictmentMap(); Indictment indictment = indictmentMap.get(lesson); HardSoftScore totalScore = (HardSoftScore) indictment.getScore(); An example from a *.java file in OptaPlanner 8: ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); Map<Object, Indictment<HardSoftScore>> indictmentMap = scoreExplanation.getIndictmentMap(); Indictment<HardSoftScore> indictment = indictmentMap.get(lesson); HardSoftScore totalScore = indictment.getScore(); ConstraintMatchAwareIncrementalScoreCalculator : generic type Score added Minor The interface ConstraintMatchAwareIncrementalScoreCalculator now also has a generic type parameter for Score to avoid raw type usages of ConstraintMatchTotal and Indictment . An example from a *.java file in OptaPlanner 7: public class MachineReassignmentIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<MachineReassignment> { @Override public Collection<ConstraintMatchTotal> getConstraintMatchTotals() { ... } @Override public Map<Object, Indictment> getIndictmentMap() { ... } } An example from a *.java file in OptaPlanner 8: public class MachineReassignmentIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<MachineReassignment, HardSoftLongScore> { @Override public Collection<ConstraintMatchTotal<HardSoftLongScore>> getConstraintMatchTotals() { ... } @Override public Map<Object, Indictment<HardSoftLongScore>> getIndictmentMap() { ... } } AbstractCustomPhaseCommand was removed Minor , Public API The abstract class AbstractCustomPhaseCommand was removed. Any class that extends it should directly implement the CustomPhaseCommand interface. An example from a *.java file in OptaPlanner 7: public class DinnerPartySolutionInitializer extends AbstractCustomPhaseCommand<DinnerParty> { @Override public void changeWorkingSolution(ScoreDirector<DinnerParty> scoreDirector) { ... } } An example from a *.java file in OptaPlanner 8: public class DinnerPartySolutionInitializer implements CustomPhaseCommand<DinnerParty> { @Override public void changeWorkingSolution(ScoreDirector<DinnerParty> scoreDirector) { ... } } Score calculators moved to the public API Major The interfaces EasyScoreCalculator , IncrementalScoreCalculator , and ConstraintMatchAwareIncrementalScoreCalculator have moved to a new package in the public API. Their deprecated counterparts have been removed. The deprecated class org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator has also been removed. Replace the use of the removed interfaces and classes with their counterparts in the public API. An example from the EasyScoreCalculator.java file in OptaPlanner 7: ... import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator; ... public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance> { ... } An example from the EasyScoreCalculator.java file in OptaPlanner 8: ... import org.optaplanner.core.api.score.calculator.EasyScoreCalculator; ... public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance, HardSoftScore> { ... } An example from the IncrementalScoreCalculator.java file in OptaPlanner 7: ... import org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator; ... public class CloudBalancingIncrementalScoreCalculator extends AbstractIncrementalScoreCalculator<CloudBalance> { ... } An example from the IncrementalScoreCalculator.java file in OptaPlanner 8: ... import org.optaplanner.core.api.score.calculator.IncrementalScoreCalculator; ... public class CloudBalancingIncrementalScoreCalculator implements IncrementalScoreCalculator<CloudBalance, HardSoftScore> { ... } An example from the ConstraintMatchAwareIncrementalScoreCalculator.java file in OptaPlanner 7: ... import org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator; import org.optaplanner.core.impl.score.director.incremental.ConstraintMatchAwareIncrementalScoreCalculator; ... public class CheapTimeConstraintMatchAwareIncrementalScoreCalculator extends AbstractIncrementalScoreCalculator<CheapTimeSolution> implements ConstraintMatchAwareIncrementalScoreCalculator<CheapTimeSolution> { ... } An example from the ConstraintMatchAwareIncrementalScoreCalculator.java file in OptaPlanner 8: ... import org.optaplanner.core.api.score.calculator.ConstraintMatchAwareIncrementalScoreCalculator; ... public class CheapTimeConstraintMatchAwareIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<CheapTimeSolution, HardMediumSoftLongScore> { ... } PlannerBenchmarkFactory : createFromSolverFactory() removed Major , Public API The PlannerBenchmarkFactory.createFromSolverFactory() method has been deprecated and replaced with the PlannerBenchmarkFactory.createFromSolverConfigXmlResource(String) method. The PlannerBenchmarkFactory.createFromSolverFactory() method has been removed. An example from a *.java file in OptaPlanner 7: SolverFactory<CloudBalance> solverFactory = SolverFactory.createFromXmlResource( ".../cloudBalancingSolverConfig.xml"); PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromSolverFactory(solverFactory); An example from a *.java file in OptaPlanner 8: PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromSolverConfigXmlResource( ".../cloudBalancingSolverConfig.xml"); If you programmatically adjust the solver configuration, you can use PlannerBenchmarkConfig.createFromSolverConfig(SolverConfig) and then PlannerBenchmarkFactory.create(PlannerBenchmarkConfig) instead. PlannerBenchmarkFactory : getPlannerBenchmarkConfig() removed Minor , Public API The PlannerBenchmarkFactory.getPlannerBenchmarkConfig() method has been deprecated and replaced with the PlannerBenchmarkFactory.create(PlannerBenchmarkConfig) method. A PlannerBenchmarkConfig instance is now instantiated before a PlannerBenchmarkFactory instance is instantiated. This order is more logical. PlannerBenchmarkFactory.getPlannerBenchmarkConfig() has been removed. An example from a *.java file in OptaPlanner 7: PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); PlannerBenchmarkConfig benchmarkConfig = benchmarkFactory.getPlannerBenchmarkConfig(); ... PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); An example from a *.java file in OptaPlanner 8: PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); ... PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.create(benchmarkConfig); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); XML <plannerBenchmark/> root element now belongs to the http://www.optaplanner.org/xsd/benchmark namespace Minor , Public API OptaPlanner now provides an XML Schema Definition (XSD) for the benchmark configuration. Although OptaPlanner keeps compatibility with earlier versions of the existing XML configuration, migrating to the XSD is strongly recommended because OptaPlanner might support only valid configuration XML in the future. An example from the *BenchmarkConfig.xml file in OptaPlanner 7: <?xml version="1.0" encoding="UTF-8"?> <plannerBenchmark> ... </plannerBenchmark> An example from the *BenchmarkConfig.xml file in OptaPlanner 8: <?xml version="1.0" encoding="UTF-8"?> <plannerBenchmark xmlns="https://www.optaplanner.org/xsd/benchmark" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.optaplanner.org/xsd/benchmark https://www.optaplanner.org/xsd/benchmark/benchmark.xsd"> ... </plannerBenchmark> Using the XSD might require reordering some of the XML elements of the configuration. Use code completion in the IDE to migrate to a valid XML. ProblemBenchmarksConfig : xStreamAnnotatedClass removed Major , Public API The <xStreamAnnotatedClass/> has been removed from the <problemBenchmarks/> configuration together with the corresponding getXStreamAnnotatedClassList() and setXStreamAnnotatedClassList() methods in the ProblemBenchmarksConfig class. An example from a *.java file in OptaPlanner 7: ProblemBenchmarksConfig problemBenchmarksConfig = new ProblemBenchmarksConfig(); problemBenchmarksConfig.setXStreamAnnotatedClassList(MySolution.class); An example from a *.java file in OptaPlanner 8: package com.example; ... public class MySolutionFileIO extends XStreamSolutionFileIO<MySolution> { public MySolutionFileIO() { super(MySolution.class); } } ... ProblemBenchmarksConfig problemBenchmarksConfig = new ProblemBenchmarksConfig(); problemBenchmarksConfig.setSolutionFileIOClass(MySolutionFileIO.class); An example from the *BenchmarkConfig.xml file in OptaPlanner 7: <plannerBenchmark> ... <solverBenchmark> <problemBenchmarks> <xStreamAnnotatedClass>com.example.MySolution</xStreamAnnotatedClass> ... </problemBenchmarks> ... </solverBenchmark> ... </plannerBenchmark> An example from the *BenchmarkConfig.xml file in OptaPlanner 8: <plannerBenchmark> ... <solverBenchmark> <problemBenchmarks> <!-- See the "After in *.java" section to create the MySolutionFileIO. --> <solutionFileIOClass>com.example.MySolutionFileIO</solutionFileIOClass> ... </problemBenchmarks> ... </solverBenchmark> ... </plannerBenchmark> BenchmarkAggregatorFrame.createAndDisplay(PlannerBenchmarkFactory) removed Minor The BenchmarkAggregatorFrame.createAndDisplay(PlannerBenchmarkFactory) method has been deprecated and replaced with the BenchmarkAggregatorFrame.createAndDisplayFromXmlResource(String) method. The BenchmarkAggregatorFrame.createAndDisplay(PlannerBenchmarkFactory) method has been removed. An example from a *.java file in OptaPlanner 7: PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); BenchmarkAggregatorFrame.createAndDisplay(benchmarkFactory); An example from a *.java file in OptaPlanner 8: BenchmarkAggregatorFrame.createAndDisplayFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); If you programmatically adjust the benchmark configuration, you can use BenchmarkAggregatorFrame.createAndDisplay(PlannerBenchmarkConfig) instead. Removed JavaScript expression support in configuration Minor Various elements of both the solver configuration and benchmark configuration no longer support nested JavaScript expressions. You must replace these with either auto-configuration or with integer constants. An example from the solverConfig.xml file in OptaPlanner 7: <solver> ... <moveThreadCount>availableProcessorCount - 1</moveThreadCount> ... </solver> An example from the `solverConfig.xml`file in OptaPlanner 8: <solver> ... <moveThreadCount>1</moveThreadCount> <!-- Alternatively, use "AUTO" or omit entirely. --> ... </solver> An example from the benchmarkConfig.xml file in OptaPlanner 7: <plannerBenchmark> ... <parallelBenchmarkCount>availableProcessorCount - 1</parallelBenchmarkCount> ... </plannerBenchmark> An example from the benchmarkConfig.xml file in OptaPlanner 8: <plannerBenchmark> ... <parallelBenchmarkCount>1</parallelBenchmarkCount> <!-- Alternatively, use "AUTO" or omit entirely. --> ... </plannerBenchmark> Removed the deprecated variable listeners Major , Public API The deprecated interface VariableListener from the package org.optaplanner.core.impl.domain.variable.listener has been removed, along with the deprecated interface StatefulVariableListener and the deprecated class VariableListenerAdapter in that same package. Use a VariableListener interface from the org.optaplanner.core.api.domain.variable package instead. An example of a VariableListener.java file in OptaPlanner 7: ... import org.optaplanner.core.impl.domain.variable.listener.VariableListenerAdapter; ... public class MyVariableListener extends VariableListenerAdapter<Object> { ... @Override void afterEntityRemoved(ScoreDirector scoreDirector, Object entity); ... } ... } An example from a VariableListener.java file in OptaPlanner 8: ... import org.optaplanner.core.api.domain.variable.VariableListener; ... public class MyVariableListener extends VariableListener<MySolution, Object> { ... @Override void afterEntityRemoved(ScoreDirector<MySolution> scoreDirector, Object entity); ... } ... } An example of a StatefulVariableListener.java file in OptaPlanner 7: ... import org.optaplanner.core.impl.domain.variable.listener.StatefulVariableListener; ... public class MyStatefulVariableListener implements StatefulVariableListener<Object> { ... @Override public void clearWorkingSolution(ScoreDirector scoreDirector) { ... } ... } An example from the StatefulVariableListener.java file in OptaPlanner 8: ... import org.optaplanner.core.api.domain.variable.VariableListener; ... public class MyStatefulVariableListener implements VariableListener<MySolution, Object> { ... @Override public void close() { ... } ... }
sudo dnf install java-11-openjdk-devel ScoreDirectorFactory<CloudBalance> scoreDirectorFactory = solverFactory.getScoreDirectorFactory(); try (ScoreDirector<CloudBalance> scoreDirector = scoreDirectorFactory.buildScoreDirector()) { scoreDirector.setWorkingSolution(solution); Score score = scoreDirector.calculateScore(); } ScoreManager<CloudBalance> scoreManager = ScoreManager.create(solverFactory); Score score = scoreManager.updateScore(solution); SolverFactory<MySolution> solverFactory = SolverFactory.createFromXmlResource(".../mySolverConfig.xml"); SolverConfig solverConfig = solverFactory.getSolverConfig(); Solver<MySolution> solver = solverFactory.buildSolver(); SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); Solver<MySolution> solver = solverConfig.buildSolver(); SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.create(benchmarkConfig); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); private SolverFactory<MySolution> base; public void userRequest(..., long userInput) { SolverFactory<MySolution> solverFactory = base.cloneSolverFactory(); solverFactory.getSolverConfig() .getTerminationConfig() .setMinutesSpentLimit(userInput); Solver<MySolution> solver = solverFactory.buildSolver(); } private SolverConfig base; public void userRequest(..., long userInput) { SolverConfig solverConfig = new SolverConfig(base); // Copy it solverConfig.getTerminationConfig() .setMinutesSpentLimit(userInput); SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); } SolverFactory<MySolution> solverFactory = SolverFactory.createEmpty(); SolverConfig solverConfig = solverFactory.getSolverConfig() Solver<MySolution> solver = solverFactory.buildSolver(); SolverConfig solverConfig = new SolverConfig(); SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); <?xml version="1.0" encoding="UTF-8"?> <solver> </solver> <?xml version="1.0" encoding="UTF-8"?> <solver xmlns="https://www.optaplanner.org/xsd/solver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd"> </solver> <pillar...MoveSelector> <pillarSelector> <subPillarEnabled>false</subPillarEnabled> </pillarSelector> </pillar...MoveSelector> <pillar...MoveSelector> <subPillarType>NONE</subPillarType> <pillarSelector> </pillarSelector> </pillar...MoveSelector> SolverFactory<VehicleRoutingSolution> solverFactory = SolverFactory.createFromXmlResource(...); Solver<VehicleRoutingSolution> solver = solverFactory.buildSolver(); uiScoreDirectorFactory = solver.getScoreDirectorFactory(); SolverFactory<VehicleRoutingSolution> solverFactory = SolverFactory.createFromXmlResource(...); ScoreManager<VehicleRoutingSolution> scoreManager = ScoreManager.create(solverFactory); solver = ...; scoreExplanation = solver.explainBestScore(); MySolution solution = ...; ScoreManager<MySolution> scoreManager = ...; scoreExplanation = scoreManager.explainScore(solution); solver = ...; solution = solver.getBestSolution(); score = solver.getBestScore(); timeMillisSpent = solver.getTimeMillisSpent(); solver = ...; solver.addEventListener(event -> { solution = event.getNewBestSolution(); score = event.getNewBestScore(); timeMillisSpent = event.getTimeMillisSpent(); }); <solver> <scanAnnotatedClasses/> </solver> <solver> <solutionClass>...</solutionClass> <entityClass>...</entityClass> </solver> import org.optaplanner.core.api.domain.solution.drools.ProblemFactCollectionProperty; import org.optaplanner.core.api.domain.solution.drools.ProblemFactProperty; import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty; import org.optaplanner.core.api.domain.solution.ProblemFactProperty; ValueSelectorConfig valueSelectorConfig = new ValueSelectorConfig(); valueSelectorConfig.setFilterClassList(Collections.singletonList(MySelectionFilterClass.class)); ValueSelectorConfig valueSelectorConfig = new ValueSelectorConfig(); valueSelectorConfig.setFilterClass(MySelectionFilterClass.class); <swapMoveSelector> <entitySelector> <filterClass>com.example.FilterA</filterClass> <filterClass>com.example.FilterB</filterClass> </entitySelector> </swapMoveSelector> package com.example; public class FilterA implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getValue() < 500; } } package com.example; public class FilterB implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getOrder() == Order.ASC; } } <swapMoveSelector> <entitySelector> <filterClass>com.example.SingleEntityFilter</filterClass> </entitySelector> </swapMoveSelector> package com.example; public class SingleEntityFilter implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getValue() < 500 && selection.getOrder() == Order.ASC; } } LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig() .withAcceptorConfig(new AcceptorConfig().withEntityTabuSize(5)); LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig() .withAcceptorConfig(new LocalSearchAcceptorConfig().withEntityTabuSize(5)); <partitionedSearch> <solutionPartitionerClass>com.example.MySolutionPartitioner</solutionPartitionerClass> <solutionPartitionerCustomProperties> <partCount>4</partCount> <!-- a custom property --> <minimumProcessListSize>300</minimumProcessListSize> <!-- a custom property --> </solutionPartitionerCustomProperties> </partitionedSearch> <partitionedSearch> <solutionPartitionerClass>com.example.MySolutionPartitioner</solutionPartitionerClass> <solutionPartitionerCustomProperties> <property name="partCount" value="4"/> <!-- a custom property --> <property name="minimumProcessListSize" value="300"/> <!-- a custom property --> </solutionPartitionerCustomProperties> </partitionedSearch> <swapMoveSelector> <variableNameInclude>variableA</variableNameInclude> <variableNameInclude>variableB</variableNameInclude> </swapMoveSelector> <swapMoveSelector> <variableNameIncludes> <variableNameInclude>variableA</variableNameInclude> <variableNameInclude>variableB</variableNameInclude> </variableNameIncludes> </swapMoveSelector> @PlanningSolution public class CloudBalance implements Solution<HardSoftScore> { private List<CloudComputer> computerList; private HardSoftScore score; @ValueRangeProvider(id = "computerRange") public List<CloudComputer> getComputerList() {...} public HardSoftScore getScore() {...} public void setScore(HardSoftScore score) {...} public Collection<? extends Object> getProblemFacts() { List<Object> facts = new ArrayList<Object>(); facts.addAll(computerList); return facts; } } @PlanningSolution public class CloudBalance { private List<CloudComputer> computerList; private HardSoftScore score; @ValueRangeProvider(id = "computerRange") @ProblemFactCollectionProperty public List<CloudComputer> getComputerList() {...} @PlanningScore public HardSoftScore getScore() {...} public void setScore(HardSoftScore score) {...} } @PlanningSolution public class CloudBalance implements Solution<HardSoftScore> { private CloudParametrization parametrization; private List<CloudBuilding> buildingList; @ValueRangeProvider(id = "computerRange") private List<CloudComputer> computerList; public Collection<? extends Object> getProblemFacts() { List<Object> facts = new ArrayList<Object>(); facts.add(parametrization); // not a Collection facts.addAll(buildingList); facts.addAll(computerList); return facts; } } @PlanningSolution public class CloudBalance { @ProblemFactProperty private CloudParametrization parametrization; @ProblemFactCollectionProperty private List<CloudBuilding> buildingList; @ValueRangeProvider(id = "computerRange") @ProblemFactCollectionProperty private List<CloudComputer> computerList; } public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() && event.isNewBestSolutionInitialized()) { } } public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() && event.getNewBestSolution().getScore().isSolutionInitialized()) { } } public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() // isFeasible() checks isSolutionInitialized() too && event.getNewBestSolution().getScore().isFeasible()) { } } <valueSelector> <variableName>room</variableName> </valueSelector> <valueSelector variableName="room"/> <solver> <partitionedSearch> <threadFactoryClass>...MyAppServerThreadFactory</threadFactoryClass> </partitionedSearch> </solver> <solver> <threadFactoryClass>...MyAppServerThreadFactory</threadFactoryClass> <partitionedSearch> </partitionedSearch> </solver> @PlanningSolution public class MyPlanningSolution { private SimpleDoubleScore score; } @PlanningSolution public class MyPlanningSolution { private SimpleLongScore score; } score = score.toInitializedScore(); score = score.withInitScore(0); NaturalScoreComparator comparator = new NaturalScoreComparator(); ConstraintMatchScoreComparator comparator2 = new ConstraintMatchScoreComparator(); Comparator<Score> comparator = Comparable::compareTo; Comparator<ConstraintMatch> comparator2 = Comparator.comparing(ConstraintMatch::getScore); @PlanningEntity(movableEntitySelectionFilter = MyMovableEntitySelectionFilter.class) @PlanningEntity(pinningFilter = MyPinningFilter.class) class MyValueRangeFactory extends ValueRangeFactory { } class MyValueRangeFactory { } ConstraintMatchTotal maximumCapacityMatchTotal = new ConstraintMatchTotal(...); ConstraintMatchTotal maximumCapacityMatchTotal = new DefaultConstraintMatchTotal(...); @Inject // or @Autowired ScoreManager<TimeTable> scoreManager; @Inject // or @Autowired ScoreManager<TimeTable, HardSoftScore> scoreManager; ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); HardSoftScore score = (HardSoftScore) explanation.getScore(); ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); HardSoftScore score = explanation.getScore(); ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); Map<String, ConstraintMatchTotal> constraintMatchTotalMap = scoreExplanation.getConstraintMatchTotalMap(); ConstraintMatchTotal constraintMatchTotal = constraintMatchTotalMap.get(contraintId); HardSoftScore totalScore = (HardSoftScore) constraintMatchTotal.getScore(); ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); Map<String, ConstraintMatchTotal<HardSoftScore>> constraintMatchTotalMap = scoreExplanation.getConstraintMatchTotalMap(); ConstraintMatchTotal<HardSoftScore> constraintMatchTotal = constraintMatchTotalMap.get(contraintId); HardSoftScore totalScore = constraintMatchTotal.getScore(); ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); Map<Object, Indictment> indictmentMap = scoreExplanation.getIndictmentMap(); Indictment indictment = indictmentMap.get(lesson); HardSoftScore totalScore = (HardSoftScore) indictment.getScore(); ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); Map<Object, Indictment<HardSoftScore>> indictmentMap = scoreExplanation.getIndictmentMap(); Indictment<HardSoftScore> indictment = indictmentMap.get(lesson); HardSoftScore totalScore = indictment.getScore(); public class MachineReassignmentIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<MachineReassignment> { @Override public Collection<ConstraintMatchTotal> getConstraintMatchTotals() { } @Override public Map<Object, Indictment> getIndictmentMap() { } } public class MachineReassignmentIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<MachineReassignment, HardSoftLongScore> { @Override public Collection<ConstraintMatchTotal<HardSoftLongScore>> getConstraintMatchTotals() { } @Override public Map<Object, Indictment<HardSoftLongScore>> getIndictmentMap() { } } public class DinnerPartySolutionInitializer extends AbstractCustomPhaseCommand<DinnerParty> { @Override public void changeWorkingSolution(ScoreDirector<DinnerParty> scoreDirector) { } } public class DinnerPartySolutionInitializer implements CustomPhaseCommand<DinnerParty> { @Override public void changeWorkingSolution(ScoreDirector<DinnerParty> scoreDirector) { } } import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator; public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance> { } import org.optaplanner.core.api.score.calculator.EasyScoreCalculator; public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance, HardSoftScore> { } import org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator; public class CloudBalancingIncrementalScoreCalculator extends AbstractIncrementalScoreCalculator<CloudBalance> { } import org.optaplanner.core.api.score.calculator.IncrementalScoreCalculator; public class CloudBalancingIncrementalScoreCalculator implements IncrementalScoreCalculator<CloudBalance, HardSoftScore> { } import org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator; import org.optaplanner.core.impl.score.director.incremental.ConstraintMatchAwareIncrementalScoreCalculator; public class CheapTimeConstraintMatchAwareIncrementalScoreCalculator extends AbstractIncrementalScoreCalculator<CheapTimeSolution> implements ConstraintMatchAwareIncrementalScoreCalculator<CheapTimeSolution> { } import org.optaplanner.core.api.score.calculator.ConstraintMatchAwareIncrementalScoreCalculator; public class CheapTimeConstraintMatchAwareIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<CheapTimeSolution, HardMediumSoftLongScore> { } SolverFactory<CloudBalance> solverFactory = SolverFactory.createFromXmlResource( ".../cloudBalancingSolverConfig.xml"); PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromSolverFactory(solverFactory); PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromSolverConfigXmlResource( ".../cloudBalancingSolverConfig.xml"); PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); PlannerBenchmarkConfig benchmarkConfig = benchmarkFactory.getPlannerBenchmarkConfig(); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.create(benchmarkConfig); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(); <?xml version="1.0" encoding="UTF-8"?> <plannerBenchmark> </plannerBenchmark> <?xml version="1.0" encoding="UTF-8"?> <plannerBenchmark xmlns="https://www.optaplanner.org/xsd/benchmark" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.optaplanner.org/xsd/benchmark https://www.optaplanner.org/xsd/benchmark/benchmark.xsd"> </plannerBenchmark> ProblemBenchmarksConfig problemBenchmarksConfig = new ProblemBenchmarksConfig(); problemBenchmarksConfig.setXStreamAnnotatedClassList(MySolution.class); package com.example; public class MySolutionFileIO extends XStreamSolutionFileIO<MySolution> { public MySolutionFileIO() { super(MySolution.class); } } ProblemBenchmarksConfig problemBenchmarksConfig = new ProblemBenchmarksConfig(); problemBenchmarksConfig.setSolutionFileIOClass(MySolutionFileIO.class); <plannerBenchmark> <solverBenchmark> <problemBenchmarks> <xStreamAnnotatedClass>com.example.MySolution</xStreamAnnotatedClass> </problemBenchmarks> </solverBenchmark> </plannerBenchmark> <plannerBenchmark> <solverBenchmark> <problemBenchmarks> <!-- See the "After in *.java" section to create the MySolutionFileIO. --> <solutionFileIOClass>com.example.MySolutionFileIO</solutionFileIOClass> </problemBenchmarks> </solverBenchmark> </plannerBenchmark> PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); BenchmarkAggregatorFrame.createAndDisplay(benchmarkFactory); BenchmarkAggregatorFrame.createAndDisplayFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); <solver> <moveThreadCount>availableProcessorCount - 1</moveThreadCount> </solver> <solver> <moveThreadCount>1</moveThreadCount> <!-- Alternatively, use "AUTO" or omit entirely. --> </solver> <plannerBenchmark> <parallelBenchmarkCount>availableProcessorCount - 1</parallelBenchmarkCount> </plannerBenchmark> <plannerBenchmark> <parallelBenchmarkCount>1</parallelBenchmarkCount> <!-- Alternatively, use "AUTO" or omit entirely. --> </plannerBenchmark> import org.optaplanner.core.impl.domain.variable.listener.VariableListenerAdapter; public class MyVariableListener extends VariableListenerAdapter<Object> { @Override void afterEntityRemoved(ScoreDirector scoreDirector, Object entity); } } import org.optaplanner.core.api.domain.variable.VariableListener; public class MyVariableListener extends VariableListener<MySolution, Object> { @Override void afterEntityRemoved(ScoreDirector<MySolution> scoreDirector, Object entity); } } import org.optaplanner.core.impl.domain.variable.listener.StatefulVariableListener; public class MyStatefulVariableListener implements StatefulVariableListener<Object> { @Override public void clearWorkingSolution(ScoreDirector scoreDirector) { } } import org.optaplanner.core.api.domain.variable.VariableListener; public class MyStatefulVariableListener implements VariableListener<MySolution, Object> { @Override public void close() { } }