mvn clean org.openrewrite.maven:rewrite-maven-plugin:4.44.0:run -Drewrite.recipeArtifactCoordinates=org.optaplanner:optaplanner-migration:9.44.0.Final -Drewrite.activeRecipes=org.optaplanner.migration.ToLatest9
OptaPlanner’s public API classes are backwards compatible (per series), but users often also use impl classes (which are documented in the reference manual too). This upgrade recipe minimizes the pain to upgrade your code and to take advantage of the newest features in OptaPlanner.
Every upgrade note has an indication how likely your code will be affected by that change:
To upgrade from an older version, first apply the previous upgrade recipes. You will find the order of migration steps bellow:
The RHDM version differs from the OptaPlanner version:
| RHDM version | OptaPlanner version |
|---|---|
| 7.8 | 7.39 |
| 7.9 | 7.44 |
| 7.1 | 7.48 |
| 7.11 | 8.5 (and 7.52) |
| 7.12 | 8.11 (and 7.59) |
| 7.13 | 8.13 (and 7.67) |
Update your code in seconds, with optaplanner-migration
(an OpenRewrite recipe). Try it:
mvn clean org.openrewrite.maven:rewrite-maven-plugin:4.44.0:run -Drewrite.recipeArtifactCoordinates=org.optaplanner:optaplanner-migration:9.44.0.Final -Drewrite.activeRecipes=org.optaplanner.migration.ToLatest9
Note: The -Drewrite.recipeArtifactCoordinates might not work,
use the more verbose pom.xml approach instead.
It only does upgrade steps with an Automated badge.
As promised, starting from OptaPlanner 6.1.0.Final, there will be a public API,
which will be backwards compatible in later versions (such as 6.2, 6.3, etc.).
The public API are all classes in the package org.optaplanner.core.api (or subpackages thereof).
For more information, see the documentation, chapter "Status of OptaPlanner".
Bear with us: this should be the last time we require you to do a large number of migrations during upgrading.
Simulated Annealing now uses the time gradient of the current step instead of the time gradient of the last step. The impact of this change is negligible.
AbstractScore: methods changesOn AbstractScore, the methods parseLevelStrings(…) and buildScorePattern(…) have been changed from public to protected.
It’s highly unlikely that this affects your code.
@ValueRangeProvider that returns numbers: use ValueRangeIf you have @ValueRangeProvider that returns a collection of numbers (for example List<Integer> or List<BigDecimal>),
then you probably want to switch to a ValueRange, which uses less memory and offers additional opportunities.
Before in *.java:
@ValueRangeProvider(id = "delayRange")
public List<Integer> getDelayRange() {
List<Integer> = new ArrayList<Integer>(5000);
for (int i = 0; i < 5000; i++) {
delayRange.add(i);
}
return delayRange;
}
After in *.java:
@ValueRangeProvider(id = "delayRange")
public CountableValueRange<Integer> getDelayRange() {
return ValueRangeFactory.createIntValueRange(0, 5000);
}
@ValueRangeProvider: movedThe annotation @ValueRangeProvider has been moved into another package
Before in *.java:
import org.optaplanner.core.api.domain.value.ValueRangeProvider;
After in *.java:
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
Descriptor classes: movedThe *Descriptor classes have been moved into a descriptor package.
Selector: isContinuous() renamedSelector.isContinuous() has been renamed to isCountable and its boolean return value has been inverted.
It’s highly unlikely that your code uses isContinuous() because uncountable value ranges weren’t supported yet.
SolutionDescriptor: isInitialized(…) changedSolutionDescriptor.isInitialized(Solution) now requires a ScoreDirector parameter too
IMPROVING_STEP_PERCENTAGE removedThe deprecated statisticType IMPROVING_STEP_PERCENTAGE has been removed.
Before in *BenchmarkConfig.xml:
<problemBenchmarks>
...
<problemStatisticType>IMPROVING_STEP_PERCENTAGE</problemStatisticType>
</problemBenchmarks>
Benchmark classes renamedIf you have custom Benchmarker ranking:
SolverBenchmark has been renamed to SolverBenchmarkResult.
ProblemBenchmark has been renamed to ProblemBenchmarkResult.
SingleBenchmark has been renamed to SingleBenchmarkResult.
They also moved into the package result.
Before in *.java:
public int compare(SolverBenchmark a, SolverBenchmark b) {...}
After in *.java:
public int compare(SolverBenchmarkResult a, SolverBenchmarkResult b) {...}
Before in *.java:
public Comparable createRankingWeight(List<SolverBenchmark> solverBenchmarkList, SolverBenchmark solverBenchmark) {...}
After in *.java:
public Comparable createRankingWeight(List<SolverBenchmarkResult> solverBenchmarkResultList, SolverBenchmarkResult solverBenchmarkResult) {...}
If you explicitly specify Benchmarker rankings:
All solverBenchmarkRanking* properties have been renamed to solverRanking*.
Before in *BenchmarkConfig.xml:
<solverBenchmarkRankingType>TOTAL_SCORE</solverBenchmarkRankingType>
After in *BenchmarkConfig.xml:
<solverRankingType>TOTAL_SCORE</solverRankingType>
Before in *BenchmarkConfig.xml:
<solverBenchmarkRankingComparatorClass>...</solverBenchmarkRankingComparatorClass>
After in *BenchmarkConfig.xml:
<solverRankingComparatorClass>...</solverRankingComparatorClass>
Before in *BenchmarkConfig.xml:
<solverBenchmarkRankingWeightFactoryClass>...</solverBenchmarkRankingWeightFactoryClass>
After in *BenchmarkConfig.xml:
<solverRankingWeightFactoryClass>...</solverRankingWeightFactoryClass>
Before in *.java:
... implements SolverRankingWeightFactory
After in *.java:
... implements SolverBenchmarkRankingWeightFactory
optaplanner-benchmark refactoringThe internals of optaplanner-benchmark have been deeply refactored to support the new aggregator functionality.
The benchmark output report directory structure is slightly different: the CSV files have been renamed.
If you explicitly specify Benchmarker rankings or report locale:
The elements <benchmarkReportLocale>, <solverRankingType>, <solverRankingComparatorClass>
and <solverRankingWeightFactoryClass> have been moved inside the new element <benchmarkReport>.
Before in *BenchmarkConfig.xml:
<benchmarkReportLocale>...</benchmarkReportLocale>
After in *BenchmarkConfig.xml:
<benchmarkReport>
<locale>...</locale>
</benchmarkReport>
Before in *BenchmarkConfig.xml:
<solverRankingType>...</solverRankingType>
After in *BenchmarkConfig.xml:
<benchmarkReport>
<solverRankingType>...</solverRankingType>
</benchmarkReport>
<entitySelector>: <cacheType>PHASE</cacheType> obsoleteIf you explicitly configured all your <entitySelector> elements with <cacheType>PHASE</cacheType> for performance,
you now no longer have to do that, as OptaPlanner does the fast thing out of the box,
if and only if no other properties (such as filtering) were specified on that <entitySelector>.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<unionMoveSelector>
<changeMoveSelector>
<entitySelector>
<cacheType>PHASE</cacheType>
</entitySelector>
</changeMoveSelector>
<swapMoveSelector>
<entitySelector>
<cacheType>PHASE</cacheType>
</entitySelector>
</swapMoveSelector>
</unionMoveSelector>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<unionMoveSelector>
<changeMoveSelector/>
<swapMoveSelector/>
</unionMoveSelector>
The phrase time spend has been renamed to time spent. This includes the log output and the benchmark report.
<termination>: config changedAll child elements of <termination> have been renamed:
The element <maximumTimeMillisSpend> has been renamed to <millisecondsSpentLimit>
The element <maximumSecondsSpend> has been renamed to <secondsSpentLimit>
The element <maximumMinutesSpend> has been renamed to <minutesSpentLimit>
The element <maximumHoursSpend> has been renamed to <hoursSpentLimit>
The element <scoreAttained> has been renamed to <bestScoreLimit>
The element <maximumStepCount> has been renamed to <stepCountLimit>
The element <maximumUnimprovedStepCount> has been renamed to <unimprovedStepCountLimit>
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<termination>
<maximumTimeMillisSpend>...</maximumTimeMillisSpend>
<maximumSecondsSpend>...</maximumSecondsSpend>
<maximumMinutesSpend>...</maximumMinutesSpend>
<maximumHoursSpend>...</maximumHoursSpend>
<scoreAttained>...</scoreAttained>
<maximumStepCount>...</maximumStepCount>
<maximumUnimprovedStepCount>...</maximumUnimprovedStepCount>
</termination>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<termination>
<millisecondsSpentLimit>...</millisecondsSpentLimit>
<secondsSpentLimit>...</secondsSpentLimit>
<minutesSpentLimit>...</minutesSpentLimit>
<hoursSpentLimit>...</hoursSpentLimit>
<bestScoreLimit>...</bestScoreLimit>
<stepCountLimit>...</stepCountLimit>
<unimprovedStepCountLimit>...</unimprovedStepCountLimit>
</termination>
Solver and BestSolutionChangedEvent: getTimeMillisSpend() renamedIn Solver and BestSolutionChangedEvent, the method getTimeMillisSpend() has been renamed to getTimeMillisSpent().
Before in *.java:
... = solver.getTimeMillisSpend();
After in *.java:
... = solver.getTimeMillisSpent();
Before in *.java:
public void bestSolutionChanged(BestSolutionChangedEvent event) {
... = event.getTimeMillisSpend();
}
After in *.java:
public void bestSolutionChanged(BestSolutionChangedEvent event) {
... = event.getTimeMillisSpent();
}
<warmUp*> config renamedBenchmarker: the <warmUp*> elements have been renamed:
The element <warmUpTimeMillisSpend> has been renamed to <warmUpMillisecondsSpentLimit>
The element <warmUpSecondsSpend> has been renamed to <warmUpSecondsSpentLimit>
The element <warmUpMinutesSpend> has been renamed to <warmUpMinutesSpentLimit>
The element <warmUpHoursSpend> has been renamed to <warmUpHoursSpentLimit>
Before in *BenchmarkConfig.xml:
<plannerBenchmark>
<warmUpTimeMillisSpend>...</warmUpTimeMillisSpend>
<warmUpSecondsSpend>...</warmUpSecondsSpend>
<warmUpMinutesSpend>...</warmUpMinutesSpend>
<warmUpHoursSpend>...</warmUpHoursSpend>
...
</plannerBenchmark>
After in *BenchmarkConfig.xml:
<plannerBenchmark>
<warmUpMillisecondsSpentLimit>...</warmUpMillisecondsSpentLimit>
<warmUpSecondsSpentLimit>...</warmUpSecondsSpentLimit>
<warmUpMinutesSpentLimit>...</warmUpMinutesSpentLimit>
<warmUpHoursSpentLimit>...</warmUpHoursSpentLimit>
...
</plannerBenchmark>
addProblemFactChange(…) behaviour changedReal-time planning: addProblemFactChange(…) no longer causes solver Terminations to reset
(but it still causes phase terminations to reset).
BestSolutionChangedEvent and SolverEventListener: movedClasses BestSolutionChangedEvent and SolverEventListener moved from package impl.event to api.solver.event.
They are now part of the public api.
Before in *.java:
import org.optaplanner.core.impl.event.BestSolutionChangedEvent;
import org.optaplanner.core.impl.event.SolverEventListener;
After in *.java:
import org.optaplanner.core.api.solver.event.BestSolutionChangedEvent;
import org.optaplanner.core.api.solver.event.SolverEventListener;
config.termination: movedThe package config.termination has been moved to config.solver.termination.
Similarly, the package impl.termination has been moved to impl.solver.termination.
Before in *.java:
import org.optaplanner.core.config.termination....;
import org.optaplanner.core.impl.termination....;
After in *.java:
import org.optaplanner.core.config.solver.termination....;
import org.optaplanner.core.impl.solver.termination....;
RandomUtils: movedRandomUtils moved from package impl.util to impl.solver.random.
AbstractSolverPhaseScope and AbstractStepScope: movedAbstractSolverPhaseScope and AbstractStepScope moved to package impl.phase.scope.
impl.move: movedAll classes in the package impl.move have been moved to impl.heuristic.move.
None of them are future-proof enough at this time to be added the public API.
Prefer generic moves whenever possible.
Before in *.java:
import org.optaplanner.core.impl.move.Move;
import org.optaplanner.core.impl.move.CompositeMove;
import org.optaplanner.core.impl.move.NoChangeMove;
After in *.java:
import org.optaplanner.core.impl.heuristic.move.Move;
import org.optaplanner.core.impl.heuristic.move.CompositeMove;
import org.optaplanner.core.impl.heuristic.move.NoChangeMove;
PLANNING_ENTITY_TABU and PLANNING_VALUE_TABU: renamedThe <acceptorType> values PLANNING_ENTITY_TABU and PLANNING_VALUE_TABU are renamed to ENTITY_TABU and VALUE_TABU.
It’s very unlikely that you’re using either, because neither specifies the tabu size.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<acceptorType>PLANNING_ENTITY_TABU</acceptorType>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<acceptorType>ENTITY_TABU</acceptorType>
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<acceptorType>PLANNING_VALUE_TABU</acceptorType>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<acceptorType>VALUE_TABU</acceptorType>
BestSolutionRecaller: movedBestSolutionRecaller moved from package impl.bestsolution to impl.solver.recaller.
Before in *.java:
import org.optaplanner.core.impl.bestsolution.BestSolutionRecaller;
After in *.java:
import org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller;
PlanningEntityDescriptor: renamedPlanningEntityDescriptor has been renamed to EntityDescriptor.
PlanningVariableDescriptor: renamedPlanningVariableDescriptor has been renamed to GenuineVariableDescriptor.
PlanningVariableListener: renamedThe interface PlanningVariableListener has been renamed to VariableListener.
Before in *.java:
public class VehicleUpdatingVariableListener implements PlanningVariableListener<Customer> {
After in *.java:
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
AbstractPlanningVariableListener: renamedThe class AbstractPlanningVariableListener has been removed.
Before in *.java:
public class VehicleUpdatingVariableListener extends AbstractPlanningVariableListener<Customer> {
After in *.java:
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
solutionEquals() and solutionHashCode(): removedIf you’ve copied the solutionEquals() and solutionHashCode() from the examples,
it’s safe to remove it if you’re not using solutionTabu (which is often pointless to use).
Also remove the equals() and hashCode() method on your Solution implementation.
DEBUG logging: changedIn DEBUG logging, each step now mentions its phase type first:
CH is Construction Heuristic, LS is Local Search, ES is Exhaustive Search.
GreatDelugeAcceptor: removedGreatDelugeAcceptor, an experimental implementation, has been removed. Use Late Acceptance instead.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<greatDelugeWaterLevelUpperBoundRate>...</greatDelugeWaterLevelUpperBoundRate>
<greatDelugeWaterRisingRate>...</greatDelugeWaterRisingRate>
<initializingScoreTrend>Specify an <initializingScoreTrend> in the <scoreDirectorFactory>,
to increase performance of some algorithms (Construction Heuristics and Exhaustive Search).
See the documentation section on InitializingScoreTrend when to use ANY, ONLY_UP or ONLY_DOWN.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDirectorFactory>
<scoreDefinitionType>HARD_SOFT</scoreDefinitionType>
<scoreDrl>.../cloudBalancingScoreRules.drl</scoreDrl>
</scoreDirectorFactory>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDirectorFactory>
<scoreDefinitionType>HARD_SOFT</scoreDefinitionType>
<scoreDrl>.../cloudBalancingScoreRules.drl</scoreDrl>
<initializingScoreTrend>ONLY_DOWN</initializingScoreTrend>
</scoreDirectorFactory>
<pickEarlyType>: replacedReplace <pickEarlyType> FIRST_NON_DETERIORATING_SCORE with <initializingScoreTrend> ONLY_DOWN.
If the <initializingScoreTrend> is specified,
the <constructionHeuristic> will automatically use the most appropriate <pickEarlyType>.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDirectorFactory>
...
</scoreDirectorFactory>
...
<constructionHeuristic>
<constructionHeuristicType>FIRST_FIT_DECREASING</constructionHeuristicType>
<forager>
<pickEarlyType>FIRST_NON_DETERIORATING_SCORE</pickEarlyType>
</forager>
</constructionHeuristic>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDirectorFactory>
...
<initializingScoreTrend>ONLY_DOWN</initializingScoreTrend>
</scoreDirectorFactory>
...
<constructionHeuristic>
<constructionHeuristicType>FIRST_FIT_DECREASING</constructionHeuristicType>
</constructionHeuristic>
<bruteForce>: renamedThe solver phase <bruteForce> has been replaced by <exhaustiveSearch>’s BRUTE_FORCE type.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<bruteForce/>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<exhaustiveSearch>
<exhaustiveSearchType>BRUTE_FORCE</exhaustiveSearchType>
</exhaustiveSearch>
There is now a better alternative to Brute Force: Branch And Bound, see docs for more information.
ConstraintOccurrence classes: removedThe ConstraintOccurrence classes (which were deprecated) have been removed.
If you hadn’t switch them to the ConstraintMatch system yet,
scroll up to the section From 6.0.0.Alpha9 to 6.0.0.Beta1 for instructions.
Solver: setPlanningProblem(Solution) and solve() mergedSolver interface: the methods setPlanningProblem(Solution) and solve() have been merged
as the method solve(Solution).
Before in *.java:
solver.setPlanningProblem(planningProblem);
solver.solve();
After in *.java:
solver.solve(planningProblem);
Note: you still need to use solver.getBestSolution() to retrieve the best solution.
That is intentional due to real-time planning and to support pareto optimization in the future.
@ValueRangeProvider on an entity class: use <swapMoveSelector> as isIf you have a @ValueRangeProvider on an entity class (instead of the Solution class),
then it’s now safe to use the <swapMoveSelector> as is.
It’s no longer needed to filter out swaps which could put a value in an entity’s variable that’s not in its value range.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<swapMoveSelector>
<filterClass>...ValidSwapsOnlySwapMoveFilter</filterClass>
</swapMoveSelector>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<swapMoveSelector/>
ScoreDirector: split upThe interface ScoreDirector has been split up in ScoreDirector and InnerScoreDirector.
ScoreDirector now only has methods which might make the public API in a future version.
InnerScoreDirector extends ScoreDirector and it holds all methods which will never be made part of the public API.
Similarly, ScoreDirectorFactory has been split up in ScoreDirectorFactory and InnerScoreDirectorFactory.
If you’re doing programmatic configuration (instead of by XML), Config methods that accepted a property wrapped in a singleton list (due to XStream limitations), now no longer need the property wrapped in a list.
Before in *.java:
localSearchSolverPhaseConfig.setMoveSelectorConfigList(Collections.singletonList(moveSelectorConfig));
After in *.java:
localSearchSolverPhaseConfig.setMoveSelectorConfig(moveSelectorConfig);
XmlSolverFactory: removedThe class XmlSolverFactory (which was not part of the public API) has been removed
and replaced by static methods on SolverFactory (which are part of the public API).
Before in *.java:
SolverFactory solverFactory = new XmlSolverFactory("...solverConfig.xml");
After in *.java:
SolverFactory solverFactory = SolverFactory.createFromXmlResource("...solverConfig.xml");
Before in *.java:
SolverFactory solverFactory = new XmlSolverFactory().configure(inputStream);
After in *.java:
SolverFactory solverFactory = SolverFactory.createFromXmlInputStream(inputStream);
Before in *.java:
SolverFactory solverFactory = new XmlSolverFactory().configure(reader);
After in *.java:
SolverFactory solverFactory = SolverFactory.createFromXmlReader(reader);
Note: If you used the method addXstreamAnnotations(), take a look at the non-public API class XStreamXmlSolverFactory.
XmlPlannerBenchmarkFactory: removedBenchmarker: The class XmlPlannerBenchmarkFactory has been removed
and replaced by static methods on PlannerBenchmarkFactory.
Before in *.java:
PlannerBenchmarkFactory plannerBenchmarkFactory = new XmlPlannerBenchmarkFactory(...);
After in *.java:
PlannerBenchmarkFactory plannerBenchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource(...);
Note: If you used the method addXstreamAnnotations(), take a look at the non-public API class XStreamXmlPlannerBenchmarkFactory.
FreemarkerXmlPlannerBenchmarkFactory: removedBenchmarker: The class FreemarkerXmlPlannerBenchmarkFactory has been removed
and replaced by static methods on PlannerBenchmarkFactory.
Before in *.java:
PlannerBenchmarkFactory plannerBenchmarkFactory = new FreemarkerXmlPlannerBenchmarkFactory(...);
After in *.java:
PlannerBenchmarkFactory plannerBenchmarkFactory = PlannerBenchmarkFactory.createFromFreemarkerXmlResource(...);
<xstreamAnnotatedClass>: renamedBenchmarker configuration: the element <xstreamAnnotatedClass> has been renamed to <xStreamAnnotatedClass>.
Before in *BenchmarkConfig.xml:
<problemBenchmarks>
<xstreamAnnotatedClass>org.optaplanner.examples.nqueens.domain.NQueens</xstreamAnnotatedClass>
...
</problemBenchmarks>
After in *BenchmarkConfig.xml:
<problemBenchmarks>
<xStreamAnnotatedClass>org.optaplanner.examples.nqueens.domain.NQueens</xStreamAnnotatedClass>
...
</problemBenchmarks>
All classpath resources must lose their leading slash,
because OptaPlanner now expects them to adhere to ClassLoader.getResource(String) instead of Class.getResource(String).
SolverFactory.createFromXmlResource(String): changedThe SolverFactory.createFromXmlResource(String) parameter must lose its leading slash.
Before in *.java:
... = SolverFactory.createFromXmlResource(
"/org/optaplanner/examples/cloudbalancing/solver/cloudBalancingSolverConfig.xml");
After in *.java:
... = SolverFactory.createFromXmlResource(
"org/optaplanner/examples/cloudbalancing/solver/cloudBalancingSolverConfig.xml");
<scoreDrl>: changedAll elements <scoreDrl> must lose their leading slash.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDrl>/org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDrl>org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>
PlannerBenchmarkFactory.createFromXmlResource(String): changedThe PlannerBenchmarkFactory.createFromXmlResource(String) parameter must lose its leading slash.
Before in *.java:
... = PlannerBenchmarkFactory.createFromXmlResource(
"/org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfig.xml");
After in *.java:
... = PlannerBenchmarkFactory.createFromXmlResource(
"org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfig.xml");
PlannerBenchmarkFactory.createFromFreemarkerXmlResource(String): changedThe PlannerBenchmarkFactory.createFromFreemarkerXmlResource(String) parameter must lose its leading slash.
Before in *.java:
... = PlannerBenchmarkFactory.createFromFreemarkerXmlResource(
"/org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfigTemplate.xml.ftl");
After in *.java:
... = PlannerBenchmarkFactory.createFromFreemarkerXmlResource(
"org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfigTemplate.xml.ftl");
SimpleScoreCalculator: renamedThe interface SimpleScoreCalculator has been renamed to EasyScoreCalculator
to avoid confusion with SimpleScore and SimpleScore: it can return other Score types too.
The package name has changed too.
Before in *.java:
import org.optaplanner.core.impl.score.director.simple.SimpleScoreCalculator;
public class CloudBalancingEasyScoreCalculator implements SimpleScoreCalculator<CloudBalance> {
...
}
After in *.java:
import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator;
public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance> {
...
}
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<simpleScoreCalculatorClass>org.optaplanner.examples.cloudbalancing.optional.score.CloudBalancingEasyScoreCalculator<simpleScoreCalculatorClass>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<easyScoreCalculatorClass>org.optaplanner.examples.cloudbalancing.optional.score.CloudBalancingEasyScoreCalculator<easyScoreCalculatorClass>
ScoreDefinition: Score changedIf you have a custom ScoreDefinition: the Score interface has an extra method negate().
<bestScoreLimit>: behaviour changedIf you combine Simulated Annealing with <bestScoreLimit>:
The timeGradient (used only by Simulated Annealing) calculation has changed for BestScoreTermination.
On average, this should be for the better.
BestSolutionChangedEvent and SolverEventListener: generifiedBestSolutionChangedEvent and SolverEventListener now have a generic parameter which you can optionally use.
Before in *.java:
solver.addEventListener(new SolverEventListener() {
public void bestSolutionChanged(BestSolutionChangedEvent event) {
CloudBalance solution = (CloudBalance) event.getNewBestSolution();
}
});
After in *.java:
solver.addEventListener(new SolverEventListener<CloudBalance>() {
public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) {
CloudBalance solution = event.getNewBestSolution();
}
});
BestSolutionChangedEvent: isNewBestSolutionInitialized() and isEveryProblemFactChangeProcessed() addedBestSolutionChangedEvent now has the methods isNewBestSolutionInitialized() and isEveryProblemFactChangeProcessed().
In real-time planning, if you’re only interested in processing valid solutions, you’ll want to filter and check those.
Note: in 6.0, filtering BestSolutionChangedEvents for only valid solutions was cumbersome.
Note: often you’re interested in invalid, uninitialized solutions too, to show to the user you’ve processed his problem fact changes.
After in *.java:
public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) {
// Ignore invalid solutions
if (event.isEveryProblemFactChangeProcessed()
&& event.isNewBestSolutionInitialized()
&& event.getNewBestSolution().getScore().isFeasible()) {
...
}
}
<writeOutputSolutionEnabled>: output location changedA benchmark configuration with <writeOutputSolutionEnabled>true</…> now writes the solution files
in the single benchmark directory (instead of the problem benchmark directory)
and no longer alters the filename.
<subChainChangeMoveSelector> and <subChainSwapMoveSelector>: default parameters changed<subChainChangeMoveSelector> and <subChainSwapMoveSelector>’s <subChainSelector>s now default
to a <minimumSubChainSize> of 1 instead of 2.
This is to enable <subChainSwapMoveSelector> to swap a subchain of size 1 and a subchain of at least size 2 too.
<pillarSwapMoveSelector>: default parameters changed<pillarSwapMoveSelector>’s <pillarSelector> now selects subpillars too by default.
Normally, that’s an improvement.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<pillarSwapMoveSelector/>
After in *SolverConfig.xml and *BenchmarkConfig.xml (if you don’t want this new behaviour):
<pillarSwapMoveSelector>
<pillarSelector>
<subPillarEnabled>false</subPillarEnabled>
</pillarSelector>
</pillarSwapMoveSelector>
Note: <pillarChangeMoveSelector> is not supported too
SolverPhase: renamedSolverPhase has been renamed to Phase. SolverPhaseConfig has been renamed to PhaseConfig.
Before in *.java:
List<SolverPhaseConfig> solverPhaseConfigList = new ArrayList<SolverPhaseConfig>();
ConstructionHeuristicSolverPhaseConfig solverPhaseConfig = new ConstructionHeuristicSolverPhaseConfig();
...
solverPhaseConfigList.add(solverPhaseConfig);
...
solverConfig.setPhaseConfigList(phaseConfigList);
After in *.java:
List<PhaseConfig> phaseConfigList = new ArrayList<PhaseConfig>();
ConstructionHeuristicPhaseConfig phaseConfig = new ConstructionHeuristicPhaseConfig();
...
phaseConfigList.add(phaseConfig);
...
solverConfig.setPhaseConfigList(phaseConfigList);
CustomSolverPhaseCommand: renamedThe interface CustomSolverPhaseCommand has been renamed to CustomPhaseCommand.
The element <customSolverPhase> has been renamed to <customPhase>.
The element <customSolverPhaseCommandClass> has been renamed to <customPhaseCommandClass>.
Before in *.java:
public class ToOriginalMachineSolutionInitializer implements CustomSolverPhaseCommand {
...
}
After in *.java:
public class ToOriginalMachineSolutionInitializer implements CustomPhaseCommand {
...
}
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<customSolverPhase>
<customSolverPhaseCommandClass>...ToOriginalMachineSolutionInitializer</customSolverPhaseCommandClass>
</customSolverPhase>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<customPhase>
<customPhaseCommandClass>...ToOriginalMachineSolutionInitializer</customPhaseCommandClass>
</customPhase>
ScoreDefinition: getLevelCount() renamedThe method ScoreDefinition.getLevelCount() has been renamed to ScoreDefinition.getLevelsSize().
BendableScore: configuration changedBendableScore: the configuration has changed: …LevelCount has been renamed to …LevelsSize
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDirectorFactory>
<scoreDefinitionType>BENDABLE</scoreDefinitionType>
<bendableHardLevelCount>2</bendableHardLevelCount>
<bendableSoftLevelCount>3</bendableSoftLevelCount>
...
</scoreDirectorFactory>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<scoreDirectorFactory>
<scoreDefinitionType>BENDABLE</scoreDefinitionType>
<bendableHardLevelsSize>2</bendableHardLevelsSize>
<bendableSoftLevelsSize>3</bendableSoftLevelsSize>
...
</scoreDirectorFactory>
SolverRankingWeightFactory: movedThe interface SolverRankingWeightFactory has moved package (but almost nobody uses that).
Configuration by Java (instead of XML): Enums for the Config classes have been moved into the config package and any inner classes of those enums have been moved to the top level.
Before in *.java:
import org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.ScoreDefinitionType;
import org.optaplanner.core.config.solver.termination.TerminationConfig.TerminationCompositionStyle;
import org.optaplanner.core.impl.heuristic.selector.common.SelectionCacheType;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionSorterOrder;
import org.optaplanner.core.config.constructionheuristic.ConstructionHeuristicPhaseConfig.ConstructionHeuristicType;
import org.optaplanner.core.impl.constructionheuristic.decider.forager.ConstructionHeuristicPickEarlyType;
import org.optaplanner.core.impl.localsearch.decider.forager.PickEarlyType;
import org.optaplanner.core.config.localsearch.decider.acceptor.AcceptorConfig.AcceptorType;
import org.optaplanner.benchmark.impl.statistic.ProblemStatisticType;
import org.optaplanner.benchmark.api.ranking.SolverRankingType;
After in *.java:
import org.optaplanner.core.config.score.definition.ScoreDefinitionType;
import org.optaplanner.core.config.solver.termination.TerminationCompositionStyle;
import org.optaplanner.core.config.heuristic.selector.common.SelectionCacheType;
import org.optaplanner.core.config.heuristic.selector.common.decorator.SelectionSorterOrder;
import org.optaplanner.core.config.constructionheuristic.ConstructionHeuristicType;
import org.optaplanner.core.config.constructionheuristic.decider.forager.ConstructionHeuristicPickEarlyType;
import org.optaplanner.core.config.localsearch.decider.forager.LocalSearchPickEarlyType;
import org.optaplanner.core.config.localsearch.decider.acceptor.AcceptorType;
import org.optaplanner.benchmark.config.statistic.ProblemStatisticType;
import org.optaplanner.benchmark.config.ranking.SolverRankingType;
ForagerConfig: renamedForagerConfig has been renamed to LocalSearchForagerConfig
Solution: movedThe interface Solution has been promoted to the public API.
It has also moved package from impl.solution to api.domain.solution
Before in *.java:
import org.optaplanner.core.impl.solution.Solution;
After in *.java:
import org.optaplanner.core.api.domain.solution.Solution;
@PlanningVariable: chained refactoredThe @PlanningVariable property chained has been refactored to graphType.
This is to allow support for other graph types (such as TREE) in the future.
Before in *.java:
@PlanningVariable(chained = true, ...)
public Standstill getPreviousStandstill() {
return previousStandstill;
}
After in *.java:
@PlanningVariable(graphType = PlanningVariableGraphType.CHAINED, ...)
public Standstill getPreviousStandstill() {
return previousStandstill;
}
BEST_FIT: renamedThe constructionHeuristicType BEST_FIT has been renamed into WEAKEST_FIT.
The terminology "Best Fit" was not correct and did not allow for STRONGEST_FIT.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<constructionHeuristic>
<constructionHeuristicType>BEST_FIT</constructionHeuristicType>
</constructionHeuristic>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<constructionHeuristic>
<constructionHeuristicType>WEAKEST_FIT</constructionHeuristicType>
</constructionHeuristic>
BEST_FIT_DECREASING: renamedThe constructionHeuristicType BEST_FIT_DECREASING has been renamed into WEAKEST_FIT_DECREASING.
The terminology "Best Fit" was not correct and did not allow for STRONGEST_FIT_DECREASING.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<constructionHeuristic>
<constructionHeuristicType>BEST_FIT_DECREASING</constructionHeuristicType>
</constructionHeuristic>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<constructionHeuristic>
<constructionHeuristicType>WEAKEST_FIT_DECREASING</constructionHeuristicType>
</constructionHeuristic>
@PlanningVariable(mappedBy) renamedFor the shadow variable of a bi-directional relationship,
the declaration has changed from @PlanningVariable(mappedBy) to @InverseRelationShadowVariable(sourceVariableName).
Before in *.java:
@PlanningVariable(mappedBy = "previousStandstill")
Customer getNextCustomer();
void setNextCustomer(Customer nextCustomer);
After in *.java:
@InverseRelationShadowVariable(sourceVariableName = "previousStandstill")
Customer getNextCustomer();
void setNextCustomer(Customer nextCustomer);
VariableListener: usage changedVariableListener: the VariableListener is now declared on the shadow side, instead of the @PlanningVariable side.
This way, OptaPlanner recognizes the shadow variables, and all shadow variables are declared in a consistent matter.
Furthermore, it allows a shadow variable to based on other shadow variable.
Before in *.java:
@PlanningVariable(valueRangeProviderRefs = {"vehicleRange", "customerRange"},
graphType = PlanningVariableGraphType.CHAINED,
variableListenerClasses = {VehicleUpdatingVariableListener.class, ArrivalTimeUpdatingVariableListener.class})
public Standstill getPreviousStandstill() {
return previousStandstill;
}
public Vehicle getVehicle() {
return vehicle;
}
public Integer getArrivalTime() {
return arrivalTime;
}
After in *.java:
@PlanningVariable(...)
public Standstill getPreviousStandstill() {
return previousStandstill;
}
@CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class,
sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
public Vehicle getVehicle() {
return vehicle;
}
@CustomShadowVariable(variableListenerClass = ArrivalTimeUpdatingVariableListener.class,
sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
public Integer getArrivalTime() {
return arrivalTime;
}
Even classes that only have shadow variables (and extend a planning entity class), now need to be explicitly registered as planning entities. Previously, it was only required for inverse relationship shadow variables. Now it’s required for all shadow variables.
Before in *.java:
public class TimeWindowedCustomer extends Customer {
After in *.java:
@PlanningEntity
public class TimeWindowedCustomer extends Customer {
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<planningEntityClass>org.optaplanner.examples.vehiclerouting.domain.timewindowed.TimeWindowedCustomer</planningEntityClass>
<planningEntityClass>: ordering changedMultiple <planningEntityClass> elements now need to be ordered by superclasses (and superinterfaces) first,
instead of superclasses (and superinterfaces) last.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<planningEntityClass>...TimeWindowedCustomer</planningEntityClass>
<planningEntityClass>...Customer</planningEntityClass>
<planningEntityClass>...Standstill</planningEntityClass>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<planningEntityClass>...Standstill</planningEntityClass>
<planningEntityClass>...Customer</planningEntityClass>
<planningEntityClass>...TimeWindowedCustomer</planningEntityClass>
<planningEntityClass>: renamedThe element <planningEntityClass> has been renamed to <entityClass>.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<planningEntityClass>org.optaplanner.examples.cloudbalancing.domain.CloudProcess</planningEntityClass>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<entityClass>org.optaplanner.examples.cloudbalancing.domain.CloudProcess</entityClass>
XStreamScoreConverter and XStreamBendableScoreConverter: movedXStreamScoreConverter and XStreamBendableScoreConverter have moved package.
Before in *.java:
import org.optaplanner.persistence.xstream.XStreamScoreConverter;
After in *.java:
import org.optaplanner.persistence.xstream.api.score.XStreamScoreConverter;
Before in *.java:
import org.optaplanner.persistence.xstream.XStreamBendableScoreConverter;
After in *.java:
import org.optaplanner.persistence.xstream.api.score.XStreamBendableScoreConverter;
ProblemIO: renamedProblemIO has been renamed to SolutionFileIO and moved package (into the public API).
Before in *.java:
import org.optaplanner.core.impl.solution.ProblemIO;
public class MachineReassignmentFileIO implements ProblemIO {
...
}
After in *.java:
import org.optaplanner.persistence.common.api.domain.solution.SolutionFileIO;
public class MachineReassignmentFileIO implements SolutionFileIO {
...
}
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
<problemBenchmarks>
<problemIOClass>...MachineReassignmentProblemIO</problemIOClass>
...
</problemBenchmarks>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
<problemBenchmarks>
<solutionFileIOClass>...MachineReassignmentFileIO</solutionFileIOClass>
...
</problemBenchmarks>
Before in *.java:
import org.optaplanner.persistence.xstream.XStreamProblemIO;
After in *.java:
import org.optaplanner.persistence.xstream.impl.domain.solution.XStreamSolutionFileIO;
SolutionFileIO: getFileExtension() split upThe method SolutionFileIO.getFileExtension() has been split up in getInputFileExtension() and getOutputFileExtension();
It’s still highly recommended to use the same input and output file extension.
Before in *.java:
public String getFileExtension() {
return FILE_EXTENSION;
}
After in *.java:
public String getInputFileExtension() {
return FILE_EXTENSION;
}
public String getOutputFileExtension() {
return FILE_EXTENSION;
}
SolutionDescriptor: getEntityDescriptor(…) renamedSolutionDescriptor.getEntityDescriptor(…) has been renamed to SolutionDescriptor.findEntityDescriptorOrFail(…)