## Chapter 5. Score calculation

5.1. Score terminology
5.1.1. What is a score?
5.1.2. Score constraint signum (positive or negative)
5.1.3. Score constraint weight
5.1.4. Score level
5.1.5. Pareto scoring (AKA multi-objective optimization scoring)
5.1.6. Combining score techniques
5.1.7. Score interface
5.1.8. Avoid floating point numbers in score calculation
5.2. Choose a Score definition
5.2.1. SimpleScore
5.2.2. HardSoftScore (recommended)
5.2.3. HardMediumSoftScore
5.2.4. BendableScore
5.2.5. Implementing a custom Score
5.3. Calculate the Score
5.3.1. Score calculation types
5.3.2. Easy Java score calculation
5.3.3. Incremental Java score calculation
5.3.4. Drools score calculation
5.3.5. InitializingScoreTrend
5.3.6. Invalid score detection
5.4. Score calculation performance tricks
5.4.1. Overview
5.4.2. Average calculation count per second
5.4.3. Incremental score calculation (with delta's)
5.4.4. Avoid calling remote services during score calculation
5.4.5. Pointless constraints
5.4.6. Build-in hard constraint
5.4.7. Other performance tricks
5.4.8. Score trap
5.4.9. stepLimit benchmark
5.4.10. Fairness score constraints
5.5. Explaining the score: using score calculation outside the Solver

## 5.3. Calculate the Score

### 5.3.2. Easy Java score calculation

An easy way to implement your score calculation in Java.

Just implement one method of the interface EasyScoreCalculator:

public interface EasyScoreCalculator<Sol extends Solution> {

Score calculateScore(Sol solution);

}

For example in n queens:

public class NQueensEasyScoreCalculator implements EasyScoreCalculator<NQueens> {

public SimpleScore calculateScore(NQueens nQueens) {
int n = nQueens.getN();
List<Queen> queenList = nQueens.getQueenList();

int score = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
Queen leftQueen = queenList.get(i);
Queen rightQueen = queenList.get(j);
if (leftQueen.getRow() != null && rightQueen.getRow() != null) {
if (leftQueen.getRowIndex() == rightQueen.getRowIndex()) {
score--;
}
if (leftQueen.getAscendingDiagonalIndex() == rightQueen.getAscendingDiagonalIndex()) {
score--;
}
if (leftQueen.getDescendingDiagonalIndex() == rightQueen.getDescendingDiagonalIndex()) {
score--;
}
}
}
}
return SimpleScore.valueOf(score);
}
}

Configure it in your solver configuration:

<scoreDirectorFactory>
<scoreDefinitionType>...</scoreDefinitionType>
<easyScoreCalculatorClass>org.optaplanner.examples.nqueens.solver.score.NQueensEasyScoreCalculator</easyScoreCalculatorClass>
</scoreDirectorFactory>

Alternatively, build a EasyScoreCalculator instance at runtime and set it with the programmatic API:

solverFactory.getSolverConfig().getScoreDirectorFactoryConfig.setEasyScoreCalculator(easyScoreCalculator);

### 5.3.5. InitializingScoreTrend

The InitializingScoreTrend specifies how the Score will change as more and more variables are initialized (while the already variables don't change). Some optimization algorithms (such Construction Heuristics and Exhaustive Search) run faster if they have such information.

For for the Score (or each score level separately), specify a trend:

• ANY (default): Initializing an extra variable can change the score positively or negatively. Gives no performance gain.

• ONLY_UP (rare): Initializing an extra variable can only change the score positively. Implies that:

• There are only positive constraints

• Initializing the next variable can unmatch a positive constraint matched by a previous initialized variable.

• ONLY_DOWN: Initializing an extra variable can only change the score negatively. Implies that:

• There are only negative constraints

• Initializing the next variable can unmatch a negative constraint matched by a previous initialized variable.

Most use cases only have negative constraints. Many of those have an InitializingScoreTrend that only goes down:

<scoreDirectorFactory>
<scoreDefinitionType>HARD_SOFT</scoreDefinitionType>
<scoreDrl>.../cloudBalancingScoreRules.drl</scoreDrl>
<initializingScoreTrend>ONLY_DOWN</initializingScoreTrend>
</scoreDirectorFactory>

Alternatively, you can also specify the trend for each score level separately:

<scoreDirectorFactory>
<scoreDefinitionType>HARD_SOFT</scoreDefinitionType>
<scoreDrl>.../cloudBalancingScoreRules.drl</scoreDrl>
<initializingScoreTrend>ONLY_DOWN/ONLY_DOWN</initializingScoreTrend>
</scoreDirectorFactory>

### 5.3.6. Invalid score detection

Put the environmentMode in FULL_ASSERT (or FAST_ASSERT) to detect corruption in the incremental score calculation. For more information, see the section about environmentMode. However, that will not verify that your score calculator implements your score constraints as your business actually desires.

A piece of incremental score calculator code can be difficult to write and to review. Assert its correctness by using a different implementation (for example a EasyScoreCalculator) to do the assertions triggered by the environmentMode. Just configure the different implementation as a assertionScoreDirectorFactory:

<environmentMode>FAST_ASSERT</environmentMode>
...
<scoreDirectorFactory>
<scoreDefinitionType>...</scoreDefinitionType>
<scoreDrl>org/optaplanner/examples/nqueens/solver/nQueensScoreRules.drl</scoreDrl>
<assertionScoreDirectorFactory>
<easyScoreCalculatorClass>org.optaplanner.examples.nqueens.solver.score.NQueensEasyScoreCalculator</easyScoreCalculatorClass>
</assertionScoreDirectorFactory>
</scoreDirectorFactory>

This way, the scoreDrl will be validated by the EasyScoreCalculator.