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 ValueRange
If 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 Termination
s 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(…)