OptaPlanner logo
  • Download
  • Learn
    • Documentation
    • Videos

    • Use cases
    • Compatibility
    • Testimonials and case studies
  • Get help
  • Blog
  • Source
  • Team
  • Services
  • Star
  • T
  • L
  • F
  • YT
Fork me on GitHub

Upgrade recipe 6.1

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.

Legend

Every upgrade note has an indication how likely your code will be affected by that change:

  • Major Likely to affect your code.
  • Minor Unlikely to affect your code (especially if you followed the examples), unless you have hacks.
  • Impl detail Will not affect your code, unless you have very deep hacks.
  • Recommended Not a backward incompatible change, but you probably want to do this.
  • Readme Read this to better understand why the subsequent major changes were made.
  • Automated Can be applied automatically using our migration tooling.

Upgrade from an older version

To upgrade from an older version, first apply the previous upgrade recipes. You will find the order of migration steps bellow:

Note for Red Hat Decision Manager customers

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)

Automatic upgrade to the latest version

Update your code in seconds, with optaplanner-migration (an OpenRewrite recipe). Try it:

  1. Stash any local changes.
  2. Run this command in your project directory:
    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.

  3. Check the local changes and commit them.

It only does upgrade steps with an Automated badge.

From 6.0.0.Final to 6.1.0.Beta1

Backwards Compatible Public API

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 behaviour change

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 changes

On 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: moved

The 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: moved

The *Descriptor classes have been moved into a descriptor package.

Selector: isContinuous() renamed

Selector.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(…​) changed

SolutionDescriptor.isInitialized(Solution) now requires a ScoreDirector parameter too

IMPROVING_STEP_PERCENTAGE removed

The deprecated statisticType IMPROVING_STEP_PERCENTAGE has been removed.

Before in *BenchmarkConfig.xml:

<problemBenchmarks>
  ...
  <problemStatisticType>IMPROVING_STEP_PERCENTAGE</problemStatisticType>
</problemBenchmarks>

Custom Benchmarker ranking: Benchmark classes renamed

If 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) {...}

Non-default Benchmarker rank: config change

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 refactoring

The internals of optaplanner-benchmark have been deeply refactored to support the new aggregator functionality.

Benchmarker: output report directory structure changed

The benchmark output report directory structure is slightly different: the CSV files have been renamed.

Non-default Benchmarker ranking or report locale: config change

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

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

time spend typo fixed

The phrase time spend has been renamed to time spent. This includes the log output and the benchmark report.

<termination>: config changed

All 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() renamed

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

Benchmarker: <warmUp*> config renamed

Benchmarker: 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>

Real-time planning: addProblemFactChange(…​) behaviour changed

Real-time planning: addProblemFactChange(…​) no longer causes solver Terminations to reset (but it still causes phase terminations to reset).

BestSolutionChangedEvent and SolverEventListener: moved

Classes 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;

Package config.termination: moved

The 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: moved

RandomUtils moved from package impl.util to impl.solver.random.

AbstractSolverPhaseScope and AbstractStepScope: moved

AbstractSolverPhaseScope and AbstractStepScope moved to package impl.phase.scope.

Package impl.move: moved

All 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: renamed

The <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: moved

BestSolutionRecaller 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;

From 6.1.0.Beta1 to 6.1.0.Beta2

PlanningEntityDescriptor: renamed

PlanningEntityDescriptor has been renamed to EntityDescriptor.

PlanningVariableDescriptor: renamed

PlanningVariableDescriptor has been renamed to GenuineVariableDescriptor.

PlanningVariableListener: renamed

The 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: renamed

The 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(): removed

If 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: changed

In DEBUG logging, each step now mentions its phase type first: CH is Construction Heuristic, LS is Local Search, ES is Exhaustive Search.

GreatDelugeAcceptor: removed

GreatDelugeAcceptor, an experimental implementation, has been removed. Use Late Acceptance instead.

Before in *SolverConfig.xml and *BenchmarkConfig.xml:

  <greatDelugeWaterLevelUpperBoundRate>...</greatDelugeWaterLevelUpperBoundRate>
  <greatDelugeWaterRisingRate>...</greatDelugeWaterRisingRate>

Specify an <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>: replaced

Replace <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>: renamed

The 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: removed

The 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() merged

Solver 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.

From 6.1.0.Beta2 to 6.1.0.Beta3

@ValueRangeProvider on an entity class: use <swapMoveSelector> as is

If 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 up

The 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.

Programmatic configuration: usage changed

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: removed

The 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: removed

Benchmarker: 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: removed

Benchmarker: 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>: renamed

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

Classpath resources configuration changed

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): changed

The 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>: changed

All 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): changed

The 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): changed

The 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: renamed

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

From 6.1.0.Beta3 to 6.1.0.Beta4

Custom ScoreDefinition: Score changed

If you have a custom ScoreDefinition: the Score interface has an extra method negate().

Simulated Annealing with <bestScoreLimit>: behaviour changed

If 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: generified

BestSolutionChangedEvent 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() added

BestSolutionChangedEvent 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 changed

A 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: renamed

SolverPhase 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: renamed

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

From 6.1.0.Beta4 to 6.1.0.CR1

ScoreDefinition: getLevelCount() renamed

The method ScoreDefinition.getLevelCount() has been renamed to ScoreDefinition.getLevelsSize().

BendableScore: configuration changed

BendableScore: 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: moved

The interface SolverRankingWeightFactory has moved package (but almost nobody uses that).

Programmatic configuration: classes moved

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: renamed

ForagerConfig has been renamed to LocalSearchForagerConfig

Solution: moved

The 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 refactored

The @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: renamed

The 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: renamed

The 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) renamed

For 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 changed

VariableListener: 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;
}

Shadow entities

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 changed

Multiple <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>: renamed

The 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: moved

XStreamScoreConverter 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: renamed

ProblemIO 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 up

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

From 6.1.0.CR1 to 6.1.0.CR2

SolutionDescriptor: getEntityDescriptor(…​) renamed

SolutionDescriptor.getEntityDescriptor(…​) has been renamed to SolutionDescriptor.findEntityDescriptorOrFail(…​)

Latest release
  • 9.44.0.Final released
    Wed 6 September 2023
Upcoming events
    Add event / Archive
Latest blog posts
  • Scaling Up Vehicle Routing Problem with planning list variable and Nearby Selector
    Thu 27 April 2023
    Anna Dupliak
  • OptaPlanner 9 has been released
    Mon 24 April 2023
    Radovan Synek
  • OptaPlanner 9 is coming
    Tue 21 February 2023
    Lukáš Petrovický
  • Farewell - a new lead
    Tue 15 November 2022
    Geoffrey De Smet
  • Run OptaPlanner workloads on OpenShift, part II
    Wed 9 November 2022
    Radovan Synek
  • Bavet - A faster score engine for OptaPlanner
    Tue 6 September 2022
    Geoffrey De Smet
  • Run OptaPlanner workloads on OpenShift, part I.
    Thu 9 June 2022
    Radovan Synek
  • Blog archive
Latest videos
  • The Vehicle Routing Problem
    Fri 23 September 2022
    Geoffrey De Smet
  • Introduction to OptaPlanner AI constraint solver
    Thu 25 August 2022
    Anna Dupliak
  • On schedule: Artificial Intelligence plans that meet expectations
    Sat 23 July 2022
    Geoffrey De Smet
  • Host your OptaPlanner app on OpenShift (Kubernetes)
    Mon 7 February 2022
    Geoffrey De Smet
  • OptaPlanner - A fast, easy-to-use, open source AI constraint solver for software developers
    Mon 31 January 2022
  • Order picking planning with OptaPlanner
    Fri 31 December 2021
    Anna Dupliak
  • AI lesson scheduling on Quarkus with OptaPlanner
    Thu 18 November 2021
    Geoffrey De Smet
  • Video archive

OptaPlanner is open. All dependencies of this project are available under the Apache Software License 2.0 or a compatible license. OptaPlanner is trademarked.

This website was built with JBake and is open source.

Community

  • Blog
  • Get Help
  • Team
  • Governance
  • Academic research

Code

  • Build from source
  • Issue tracker
  • Release notes
  • Upgrade recipes
  • Logo and branding
CC by 3.0 | Privacy Policy
Sponsored by Red Hat