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

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

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:LATEST:run -Drewrite.recipeArtifactCoordinates=org.optaplanner:optaplanner-migration:8.35.0.Final -Drewrite.activeRecipes=org.optaplanner.migration.ToLatest

    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.1.0.Final to 6.2.0.Beta1

Custom ScoreDefinition: ScoreHolder.register*ConstraintMatch refactored

If you have a custom ScoreDefinition: the methods ScoreHolder.register*ConstraintMatch have been refactored.

Before in *.java:

public void addConstraintMatch(RuleContext kcontext, final int weight) {
    ...
    registerIntConstraintMatch(kcontext, 0, weight, new Runnable() {
        public void run() {
            ...
        }
    });
}

After in *.java:

public void addConstraintMatch(RuleContext kcontext, final int weight) {
    ...
    registerIntConstraintMatch(kcontext, 0, weight, new IntConstraintUndoListener() {
        public void undo() {
            ...
        }
    });
}

Custom Move: extract AbstractMove

If you have a custom Move implementation, now extract AbstractMove

Before in *.java:

public class CloudComputerChangeMove implements Move {...}

After in *.java:

public class CloudComputerChangeMove extends AbstractMove {...}

Custom Move: new method getSimpleMoveTypeDescription()

The interface Move has a new method getSimpleMoveTypeDescription(). Extend AbstractMove so to avoid having to implement it.

@ValueRangeProvider on an entity class: use pillar selectors as is

If you have a @ValueRangeProvider on an entity class (instead of the Solution class), then it’s now safe to use the <pillarChangeMoveSelector> and <pillarSwapMoveSelector> as is. It’s no longer needed to filter out swaps or changes which could put a value in an entity’s variable that’s not in its value range.

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

  <pillarChangeMoveSelector>
    <filterClass>...ValidChangesOnlyPillarChangeMoveFilter</filterClass>
  </pillarChangeMoveSelector>
  <pillarSwapMoveSelector>
    <filterClass>...ValidSwapsOnlyPillarSwapMoveFilter</filterClass>
  </pillarSwapMoveSelector>

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

  <pillarChangeMoveSelector/>
  <pillarSwapMoveSelector/>

ConstraintMatchTotal natural comparison changed

ConstraintMatchTotal are now naturally compared by scoreLevel, then constraintPackage, then constraintName (instead of by constraintPackage, then constraintName, then scoreLevel) for readability.

IncrementalScoreCalculator: method buildScoreCorruptionAnalysis(…​) replaced

The optional method IncrementalScoreCalculator.buildScoreCorruptionAnalysis(IncrementalScoreCalculator) has been removed. Instead, to get a pretty score corruption analysis, implement the new interface ConstraintMatchAwareIncrementalScoreCalculator. This also enable your GUI to explain the score with an IncrementalScoreCalculator. See the example code in MachineReassignmentIncrementalScoreCalculator.getConstraintMatchTotals().

From 6.2.0.Beta1 to 6.2.0.Beta2

<deciderScoreComparatorFactory> removed

The element <deciderScoreComparatorFactory> (which was deprecated, not documented, broken and clearly marked as not backwards compatible) has been removed. Instead, use strategic oscillation.

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

  <localSearch>
...
<forager>
  ...
  <deciderScoreComparatorFactory>
    ...
  </deciderScoreComparatorFactory>
</forager>
  </localSearch>

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

  <localSearch>
...
<forager>
  ...
  <finalistPodiumType>STRATEGIC_OSCILLATION</finalistPodiumType>
</forager>
  </localSearch>

ScoreBounder methods changed

The ScoreBounder methods calculateOptimisticBound() and calculatePessimisticBound() no longer have an uninitializedVariableCount parameter. Instead, if all the variables for a branch and bound algorithm are initialized, those methods are no longer called to determine the bounds (because the bound is the working score). If the uninitializedVariableCount is still needed for some reason, use the ScoreDirector to calculate it accurately.

ScoreDirector.getConstraintMatchTotals() behaviour changed

Before calling ScoreDirector.getConstraintMatchTotals(), it’s no longer expected to call ScoreDirector.calculateScore() first.

From 6.2.0.CR1 to 6.2.0.CR2

CompositeMove now uses a Move array

CompositeMove now uses a Move array instead of a List<Move> for performance reasons.

Before in *.java:

... = CompositeMove.buildMove(Arrays.asList(moveA, moveB, ...));

After in *.java:

... = CompositeMove.buildMove(moveA, moveB, ...);

Before in *.java:

... = new CompositeMove(moveList); // Not recommended

After in *.java:

... = new CompositeMove(moves); // Not recommended

InverseRelationShadowVariableListener renamed

InverseRelationShadowVariableListener renamed to SingletonInverseVariableListener. It and InverseRelationShadowVariableDescriptor moved to the package …​impl.domain.variable.inverserelation.

From 6.2.0.CR3 to 6.2.0.CR4

New anchor shadow variable support

There is now out-of-the-box support for a shadow variable representing the anchor of a chained variable. For example, in a VRP each Customer (= entity) needs to know to which Vehicle (= anchor) it belongs. This declarative support allows built-in selectors to reuse that knowledge without duplicating the calculation.

Before in *.java:

@PlanningEntity
public class Customer implements Standstill {
    @PlanningVariable(...)
    public Standstill getPreviousStandstill() {...}
    @CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class,
            sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
    public Vehicle getVehicle() {...}
}
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
    ...
}

After in *.java:

@PlanningEntity
public class Customer implements Standstill {
    @PlanningVariable(...)
    public Standstill getPreviousStandstill() {...}
    @AnchorShadowVariable(sourceVariableName = "previousStandstill")
    public Vehicle getVehicle() {...}
}

From 6.2.0.CR4 to 6.2.0.Final

<twoOptMoveSelector> replaced

The undocumented, experimental <twoOptMoveSelector> has been replaced by <tailChainSwapMoveSelector>, which is documented.

VRP: Nearby Selection

To scale VRP cases, Nearby Selection is critical. It is now finally completely supported and documented.

Latest release
  • 8.35.0.Final released
    Fri 3 March 2023
Upcoming events
    Add event / Archive
Latest blog posts
  • 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
  • OptaPlanner deprecates score DRL
    Thu 26 May 2022
    Lukáš Petrovický
  • Real-time planning meets SolverManager
    Mon 7 March 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