Introduction
============

Drools Planner isn't always backwards compatible at this time.
This file describes how can you upgrade from earlier versions to the latest.

Starting from 5.1.0, every migration change has an indication
on how likely your code is going to be affected by this change:
- [MAJOR] Very likely affects your code.
- [MINOR] Probably does not affect your code (especially if you followed the examples), unless you have hacks.
- [RECOMMENDED] Not a backward incompatible change, but you probably want to do this.

From 5.0.0-m2 to 5.0.0
----------------------

No backwards incompatible changes.

From 5.0.0 to 5.0.1
-------------------

A score is no longer a double, now it's a Score instance,
because a SimpleScore is now just an int and a HardAndSoftScore is now 2 separated ints.


In the Solver interface, the return type of the getBestScore() method changed:
Before:
    double score = solver.getBestScore();
After:
    Score score = solver.getBestScore();


Simple scores are written "-999", and hard and soft scores are written "-999hard/-999soft".
You will see this in the examples GUI.
In the *ScoreConfig.xml, configuring a feasableScore also reflects this.
Before with simple score:
    <finish>
        <feasableScore>-123456789.0</feasableScore>
    </finish>
After:
    <finish>
        <feasableScore>-123456789</feasableScore>
    </finish>
Before with hard and soft score (Note that the hard part started from 1000000):
    <finish>
        <feasableScore>-123456789.0</feasableScore>
    </finish>
After:
    <finish>
        <feasableScore>-123hard/-456789soft</feasableScore>-->
    </finish>


In the *ScoreConfig.xml, you no longer configure a ScoreCalculator,
but now you configure a ScoreDefinition instead.

Before:
    <scoreCalculator>
        <scoreCalculatorType>SIMPLE</scoreCalculatorType>
    </scoreCalculator>
After:
    <scoreDefinition>
        <scoreDefinitionType>SIMPLE</scoreDefinitionType>
    </scoreDefinition>

Before:
    <scoreCalculator>
        <scoreCalculatorType>HARD_AND_SOFT_CONSTRAINTS</scoreCalculatorType>
    </scoreCalculator>
After:
    <scoreDefinition>
        <scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
    </scoreDefinition>

DYNAMIC_HARD_AND_SOFT_CONSTRAINTS was bugged and has been removed, but will be replaced
by shiftingPenalty support.
Before:
    <scoreCalculator>
        <scoreCalculatorType>DYNAMIC_HARD_AND_SOFT_CONSTRAINTS</scoreCalculatorType>
    </scoreCalculator>
After:
    <scoreDefinition>
        <scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
    </scoreDefinition>

From 5.0.1 to 5.1.0.M1
----------------------

In 5.1.0.m2, Drools Solver has been renamed to Drools Planner,
and it's best to do that first. See "From 5.1.0.m1 to 5.1.0.m2".


The method Solver.cancel() has been renamed to Solver.terminateEarly()
because it does not undo the solving but terminates it early and there's a best solution.
Before:
    solver.cancel();
After:
    solver.terminateEarly();

Likewise, Solver.isCancelled() has been renamed to Solver.isTerminatedEarly().
Before:
    solver.isCancelled();
After:
    solver.isTerminatedEarly();


The interface Finish has been renamed to Termination
because Termination seems the defacto standard name for it in the literature.
Before:
   ... extends Finish
After:
   ... extends Termination
Before in solver config xml's and benchmarker config xml's :
    <finish>
        ...
    </finish>
After:
    <termination>
        ...
    </termination>

Likewise FinishCompositionStyle has been renamed to TerminationCompositionStyle.
Before in solver config xml's and benchmarker config xml's :
        <finishCompositionStyle>...</finishCompositionStyle>
After:
        <terminationCompositionStyle>...</terminationCompositionStyle>

The Finish.isFinished(...) has been renamed to Termination.isTerminated().
Before:
   .isFinished(...)
After:
   .isTerminated(...)


The class FeasableScoreTermination has been renamed to ScoreAttainedTermination.
Its property feasableScore has been renamed to scoreAttained.
Before in solver config xml's and benchmarker config xml's :
    <termination>
        <feasableScore>...</feasableScore>
    </termination>
After:
    <termination>
        <scoreAttained>...</scoreAttained>
    </termination>


The interface Solution now has a Score property: Solution.getScore() and Solution.getScore()
Before:
    public class ... implements Solution {
        ...
    }
After if you use a SimpleScore:
    public class ... implements Solution {
        ...
        private SimpleScore score;
        ...
        public SimpleScore getScore() {
            return score;
        }
        public void setScore(Score score) {
            this.score = (SimpleScore) score;
        }
        ...
    }
After if you use a HardAndSoftScore:
    public class ... implements Solution {
        ...
        private HardAndSoftScore score;
        ...
        public HardAndSoftScore getScore() {
            return score;
        }
        public void setScore(Score score) {
            this.score = (HardAndSoftScore) score;
        }
        ...
    }

The score property of a Solution needs to be cloned:
Before:
    public X cloneSolution() {
        X clone = new X();
        ...
        return clone;
    }
After:
    public X cloneSolution() {
        X clone = new X();
        ...
        clone.score = score;
        return clone;
    }

The Solver interface no longer has a method Solver.getBestScore().
Before:
     solver.getBestScore()
After:
     solver.getBestSolution().getScore()


From 5.1.0.M1 to 5.1.0.M2
-------------------------

Drools Solver has been renamed to Drools Planner.

The maven dependency has been renamed to drools-planner-core.
Before in pom.xml:
    <dependency>
        <groupId>org.drools.solver</groupId>
        <artifactId>drools-solver-core</artifactId>
        ...
    </dependency>
After in pom.xml:
    <dependency>
        <groupId>org.drools.planner</groupId>
        <artifactId>drools-planner-core</artifactId>
        ...
    </dependency>
And resync your IDE (IntelliJ, Eclipse, Netbeans) from the pom.xml files.
If you're still using ANT, replace drools-solver-core-?.jar with drools-planner-core-?.jar
and adjust your ANT script and your IDE's classpath accordingly.

The package has been renamed to org.drools.planner
Before in *.java, *.drl:
    import org.drools.solver...
After in *.java, *.drl:
    import org.drools.planner...

Note that the Solver interface and several related classes have NOT been renamed to Planner (yet).


TerminationConfig's maximumHouresSpend renamed to maximumHoursSpend
Before:
     <maximumHouresSpend>2</maximumHouresSpend>
After:
     <maximumHoursSpend>2</maximumHoursSpend>


Accepter has been renamed to Acceptor
Before:
    <accepter>
        ...
    </accepter>
After:
    <acceptor>
        ...
    </acceptor>


The method DefaultDecider.setAssertUndoMoveIsUncorrupted() has been renamed.
Use the EnvironmentMode debug instead.
Before in *.java:
    (DefaultDecider ((DefaultLocalSearchSolver) solver).getDecider()).setVerifyUndoMoveIsUncorrupted(true);
Before in *.xml:
    <localSearchSolver>
        ...
    </localSearchSolver>
After in *.xml:
    <localSearchSolver>
        <environmentMode>DEBUG</environmentMode>
        ...
    </localSearchSolver>


True modify has been implemented. This is a great performance boost.
Before in *.java:
    workingMemory.modifyRetract(xHandle); // before changes are made
    x.set...;
    workingMemory.modifyInsert(xHandle, x); // after changes are made
After in *.java:
    x.set...;
    workingMemory.update(queenHandle, queen); // after changes are made


Environment mode DEBUG now checks more and therefor it is slower than before.


JBRULES-1804 has been fixed. The HACK to fix wierd truth maintenance behavior is now obsolete.
Delete any instances of that hack to make your rules easier to read and faster.
Before in *.drl:
        // HACK to fix wierd truth maintenance behavior in drools
        // because making weight part of the equals/hashcode doesn't cut it
        // Vote for https://jira.jboss.org/jira/browse/JBRULES-1804
        not IntConstraintOccurrence(
            ruleId == "...",
            constraintType == ConstraintType....,
            causes contains $..., causes contains $...,
            eval(weight != (...))
        );
    then ...
After in *.drl:
    then ...


A custom ConstraintOccurrence implementation should now use the weight in its equals/hashcode methods.
IntConstraintOccurrence and DoubleConstraintOccurrence have been changed as needed.


From 5.1.0.M2 to 5.1.0.CR1
--------------------------

Custom ScoreDefinition implementations needs to implement the Double translateScoreToGraphValue(S score) method.
After in *ScoreDefinition.java:
    public Double translateScoreToGraphValue(HardAndSoftScore score) {
        if (score.getHardScore() == 0) {
            return Double.valueOf(score.getSoftScore());
        } else {
            return null;
        }
    }

A benchmarker config no longer supports solvedSolutionVerbosity (only ALL was supported anyway).
Before in *BenchmarkConfig.xml:
   <solvedSolutionVerbosity>ALL</solvedSolutionVerbosity>

A benchmarker config now needs a benchmarkDirectory directory
and solvedSolutionFilesDirectory and solverStatisticFilesDirectory are no longer required.
Before in *BenchmarkConfig.xml:
    <solverBenchmarkSuite>
        <solvedSolutionFilesDirectory>local/data/nurserostering/solved</solvedSolutionFilesDirectory>
        ...
        <solverStatisticFilesDirectory>local/data/nurserostering/statistic</solverStatisticFilesDirectory>
        ...
After in *BenchmarkConfig.xml:
    <solverBenchmarkSuite>
        <benchmarkDirectory>local/data/nurserostering</benchmarkDirectory>
        ...

Benchmarker: the class MaxScoreSolverBenchmarkComparator has been renamed to WorstScoreSolverBenchmarkComparator.

A benchmarker no longer uses WorstScoreSolverBenchmarkComparator by default.
It now uses TotalScoreSolverBenchmarkComparator by default.

The benchmarker method writeResults(resultFile) has been removed.
The result is now always written at the end of the benchmark() method
in the benchmarkDirectory directory in a file called benchmarkResult.xml.
Before in *.java:
    solverBenchmarker.writeResults(...);


The method Score.substract(subtrahend) has been renamed to Score.subtract
Before in *Score.java:
    public ...Score substract(...Score subtrahend) {
After in *Score.java:
    public ...Score subtract(...Score subtrahend) {

Custom Score implementation: When rounding is needed, it should now be floored (as defined by Math.floor(double)).


A selector no longer supports absoluteSelection and relativeSelection, because it was inefficient.
Instead, the forager now supports minimalAcceptedSelection, which only counts doable, accepted moves
(instead of all the selected moves).
As a guideline, set your minimalAcceptedSelection to the sum of all your absoluteSelection and subtract 10%.
Before in *Config.xml:
    <selector>
        <selector>
            <moveFactoryClass>...ChangeMoveFactory</moveFactoryClass>
            <absoluteSelection>500</absoluteSelection>
        </selector>
        <selector>
            <moveFactoryClass>...SwitchMoveFactory</moveFactoryClass>
            <absoluteSelection>500</absoluteSelection>
        </selector>
    </selector>
    ...
    <forager>
        <foragerType>MAX_SCORE_OF_ALL</foragerType>
    </forager>
After in *Config.xml:
    <selector>
        <selector>
            <moveFactoryClass>...ChangeMoveFactory</moveFactoryClass>
        </selector>
        <selector>
            <moveFactoryClass>...SwitchMoveFactory</moveFactoryClass>
        </selector>
    </selector>
    ...
    <forager>
        <foragerType>MAX_SCORE_OF_ALL</foragerType>
        <minimalAcceptedSelection>900</minimalAcceptedSelection>
    </forager>
If you weighted some MoveFactory heavier than another, vote for https://jira.jboss.org/browse/JBRULES-2553.

If you use a custom selector: the Selector interface method
  List<Move> selectMoveList(StepScope stepScope)
has been replaced by the more efficient method
  Iterator<Move> moveIterator(StepScope stepScope)
Before in *Selector.java:
    public List<Move> selectMoveList(StepScope stepScope) {
        ...
        return moveList;
    }
After in *Selector.java:
    public Iterator<Move> moveIterator(StepScope stepScope) {
        ...
        return moveList.iterator();
    }

There's now a decent simulated annealing implementation.
In many use cases it clearly beats the tabu search implementation.
See the reference manual and the nurse rostering example for more info.

The ForagerType has been renamed to the PickEarlyType.
The ForagerType MAX_SCORE_OF_ALL is now the PickEarlyType NEVER. It is also the default.
Before in *Config.xml:
    <forager>
        <foragerType>MAX_SCORE_OF_ALL</foragerType>
        ...
    </forager>
After in *Config.xml:
    <forager>
        ...
    </forager>
The ForagerType FIRST_BEST_SCORE_IMPROVING is the PickEarlyType FIRST_BEST_SCORE_IMPROVING.
Before in *Config.xml:
    <forager>
        <foragerType>FIRST_BEST_SCORE_IMPROVING</foragerType>
        ...
    </forager>
After in *Config.xml:
    <forager>
        <pickEarlyType>FIRST_BEST_SCORE_IMPROVING</pickEarlyType>
        ...
    </forager>
The ForagerType FIRST_LAST_STEP_SCORE_IMPROVING is now the PickEarlyType FIRST_LAST_STEP_SCORE_IMPROVING.
Before in *Config.xml:
    <forager>
        <foragerType>FIRST_LAST_STEP_SCORE_IMPROVING</foragerType>
        ...
    </forager>
After in *Config.xml:
    <forager>
        <pickEarlyType>FIRST_LAST_STEP_SCORE_IMPROVING</pickEarlyType>
        ...
    </forager>
The ForagerType FIRST_RANDOMLY_ACCEPTED has been removed, use the PickEarlyType NEVER with minimalAcceptedSelection 1.
Before in *Config.xml:
    <forager>
        <foragerType>FIRST_RANDOMLY_ACCEPTED</foragerType>
    </forager>
After in *Config.xml:
    <forager>
        <pickEarlyType>NEVER</pickEarlyType>
        <minimalAcceptedSelection>1</minimalAcceptedSelection>
    </forager>


The benchmarker no longer sorts the solvers, because that was confusing to read.
Instead it outputs a table with a ranking column.
You can still set a custom solverBenchmarkComparator to influence that ranking.
Before in *BenchmarkConfig.xml:
    <sortSolverBenchmarks>true</sortSolverBenchmarks>


From 5.1.0 to 5.2.0.M1
----------------------

[RECOMMENDED] The example DRL's no longer use the optional character ';' at the end of lines in the LHS.
If you copied that practice from the examples, it's recommended to remove them from your DRL's too.


From 5.2.0.M1 to 5.2.0.M2
-------------------------

[MINOR] XmlSolverConfigurer.buildSolver() no longer returns a LocalSearchSolver, now it returns just a Solver.
Since LocalSearchSolver is just an empty interface which extends the Solver interface, the impact should be small.
Before in *.java:
    LocalSearchSolver solver = xmlSolverConfigurer.buildSolver();
After in *.java:
    Solver solver = xmlSolverConfigurer.buildSolver();


[MAJOR] EnvironmentMode has been moved to another package.
Before in *.java:
    import org.drools.planner.config.localsearch.EnvironmentMode;
After in *.java:
    import org.drools.planner.config.EnvironmentMode;


[MINOR] XmlSolverConfigurer's getConfig() method now returns an AbstractSolverConfig instead of a LocalSearchSolverConfig.
If you used anything LocalSearchSolverConfig specific, such as a TerminationConfig, then you have to cast it...
Before in *.java:
    configurer.getConfig().getTerminationConfig().setMaximumSecondsSpend(maximumSecondsSpend);
After in *.java:
    ((LocalSearchSolverConfig) configurer.getConfig()).getTerminationConfig()
            .setMaximumSecondsSpend(maximumSecondsSpend);


[MAJOR] The StartingSolutionInitializer methods no longer have a LocalSearchSolverScope argument,
but now have a AbstractSolverScope argument.
Before in *.java:
    public boolean isSolutionInitialized(LocalSearchSolverScope localSearchSolverScope) {
        ...
    }
    public void initializeSolution(LocalSearchSolverScope localSearchSolverScope) {
        ...
    }
After in *.java:
    public boolean isSolutionInitialized(AbstractSolverScope abstractSolverScope) {
        ...
    }
    public void initializeSolution(AbstractSolverScope abstractSolverScope) {
        ...
    }

[MINOR] StepScope has been renamed to LocalSearchStepScope.
This only impacts you if you use a custom Selector.
Before in *Selector.java:
    @Override
    public void ...(StepScope stepScope) {
        ...
    }
After in *Selector.java:
    @Override
    public void ...(LocalSearchStepScope localSearchStepScope) {
        ...
    }

[MINOR] The Score has a new method: double[] toDoubleArray()
If you use a custom Score implementation, you need to implement it:
After in *Score.java:
    public double[] toDoubleArray() {
        return new double[]{hardScore, softScore, ...};
    }

[MINOR] SelectorConfig, AcceptorConfig and ForagerConfig's build method now have a ScoreDefinition argument.
If you use any custom implementation for any of them, you need to adjust your method signature.
Before in *SelectorConfig.java:
    public Selector buildSelector() {
After in *SelectorConfig.java:
    public Selector buildSelector(ScoreDefinition scoreDefinition) {
Before in *AcceptorConfig.java:
    public Acceptor buildAcceptor() {
After in *AcceptorConfig.java:
    public Acceptor buildAcceptor(ScoreDefinition scoreDefinition) {
Before in *ForagerConfig.java:
    public Forager buildForager() {
After in *ForagerConfig.java:
    public Forager buildForager(ScoreDefinition scoreDefinition) {

[MAJOR] Simulated annealing now supports working with hard constraints too (JBRULES-2911)
The starting temperature (usually close the maximum score delta) is now a Score instead of a double.
Before in *Config.xml:
    <simulatedAnnealingStartingTemperature>20.0</simulatedAnnealingStartingTemperature>
After in *Config.xml (if you're using HardAndSoftScore):
    <simulatedAnnealingStartingTemperature>0hard/20soft</simulatedAnnealingStartingTemperature>
After in *Config.xml (if you're using SimpleScore):
    <simulatedAnnealingStartingTemperature>20</simulatedAnnealingStartingTemperature>

[MAJOR] Solution now has a generic type of Score: Solution<S extends Score> (JBRULES-2924)
Your Solution implementation itself should not be generic, but it should define it's Score type through implements.
Before in *.java if you use a SimpleScore:
    public class ... implements Solution {
        ...
        public void setScore(Score score) {
            this.score = (SimpleScore) score;
        }
        ...
    }
After in *.java if you use a SimpleScore:
    public class ... implements Solution<SimpleScore> {
        ...
        public void setScore(SimpleScore score) {
            this.score = score;
        }
        ...
    }
Before in *.java if you use a HardAndSoftScore:
    public class ... implements Solution {
        ...
        public void setScore(Score score) {
            this.score = (HardAndSoftScore) score;
        }
        ...
    }
After in *.java if you use a HardAndSoftScore:
    public class ... implements Solution<HardAndSoftScore> {
        ...
        public void setScore(HardAndSoftScore score) {
            this.score = score;
        }
        ...
    }

[RECOMMENDED] If you've followed the examples (which is normally a good thing),
check if your solutionEquals() and solutionHashCode() methods respects the hashcode/equals contract,
because some of the examples did not.
Before in *.java:
    public boolean solutionEquals(Object o) {
        ...
            return new EqualsBuilder()
                    .append(id, other.id)
                    .append(guest, other.guest)
                    .append(seat, other.seat)
                    .isEquals();
        ...
    }
    public int solutionHashCode() {
        return new HashCodeBuilder()
                .append(seat)
                .toHashCode();
    }
After in *.java:
    public boolean solutionEquals(Object o) {
        ...
            return new EqualsBuilder()
                    .append(id, other.id)
                    .append(guest, other.guest)
                    .append(seat, other.seat)
                    .isEquals();
        ...
    }
    public int solutionHashCode() {
        return new HashCodeBuilder()
                .append(id)
                .append(guest)
                .append(seat)
                .toHashCode();
    }

[MINOR] Your SolverEventListener will now a BestSolutionChangedEvent when the Solver starts too.
So when the StartingSolutionInitializer initializes, the best solution changed event won't be missed.


From 5.2.0.M2 to 5.2.0.CR1
--------------------------

[MAJOR] The Benchmarker configuration XML schema has changed.
The entities inheritedUnsolvedSolutionFile and inheritedLocalSearchSolver are now wrapped
in a inheritedSolverBenchmark entity and renamed to unsolvedSolutionFile and localSearchSolver.
Before in *BenchmarkConfig.xml:
    <inheritedUnsolvedSolutionFile>...</inheritedUnsolvedSolutionFile>
    <inheritedUnsolvedSolutionFile>...</inheritedUnsolvedSolutionFile>
    ...

    <inheritedLocalSearchSolver>
        <scoreDrl>...</scoreDrl>
        ...
    </inheritedLocalSearchSolver>
After in *BenchmarkConfig.xml:
    <inheritedSolverBenchmark>
        <unsolvedSolutionFile>...</unsolvedSolutionFile>
        <unsolvedSolutionFile>...</unsolvedSolutionFile>
        ...

        <localSearchSolver>
            <scoreDrl>...</scoreDrl>
            ...
        </localSearchSolver>
    </inheritedSolverBenchmark>

