Skip to content

Commit

Permalink
PLANNER-340 Exhaustive search by type BRANCH_AND_BOUND fails with sco…
Browse files Browse the repository at this point in the history
…re corruption in FULL_ASSERT mode + Exhaustive Search should not put the startingStepScore in the stepScope's score as that is presumed to be the score of the winning step.
  • Loading branch information
ge0ffrey committed May 22, 2015
1 parent 4f1c33e commit 0e9da20
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 22 deletions.
Expand Up @@ -105,7 +105,7 @@ private void doMove(ConstructionHeuristicMoveScope moveScope) {
undoMove.doMove(scoreDirector);
if (assertExpectedUndoMoveScore) {
ConstructionHeuristicPhaseScope phaseScope = moveScope.getStepScope().getPhaseScope();
phaseScope.assertExpectedUndoMoveScore(move, undoMove);
phaseScope.assertExpectedUndoMoveScore(move, undoMove, phaseScope.getLastCompletedStepScope().getScore());
}
logger.trace(" Move index ({}), score ({}), move ({}).",
moveScope.getMoveIndex(), moveScope.getScore(), moveScope.getMove());
Expand Down
Expand Up @@ -17,23 +17,20 @@
package org.optaplanner.core.impl.exhaustivesearch;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import org.optaplanner.core.api.score.Score;
import org.optaplanner.core.impl.domain.variable.descriptor.GenuineVariableDescriptor;
import org.optaplanner.core.impl.exhaustivesearch.decider.ExhaustiveSearchDecider;
import org.optaplanner.core.impl.exhaustivesearch.node.ExhaustiveSearchLayer;
import org.optaplanner.core.impl.exhaustivesearch.node.ExhaustiveSearchNode;
import org.optaplanner.core.impl.exhaustivesearch.node.bounder.ScoreBounder;
import org.optaplanner.core.impl.exhaustivesearch.scope.ExhaustiveSearchPhaseScope;
import org.optaplanner.core.impl.exhaustivesearch.scope.ExhaustiveSearchStepScope;
import org.optaplanner.core.impl.heuristic.move.Move;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionFilter;
import org.optaplanner.core.impl.heuristic.selector.entity.EntitySelector;
import org.optaplanner.core.impl.phase.AbstractPhase;
import org.optaplanner.core.impl.score.director.InnerScoreDirector;
Expand Down Expand Up @@ -214,17 +211,17 @@ protected void restoreWorkingSolution(ExhaustiveSearchStepScope stepScope) {
restoreMove.doMove(scoreDirector);
}
// there is no need to recalculate the score, but we still need to set it
phaseScope.getWorkingSolution().setScore(stepScope.getScore());
phaseScope.getWorkingSolution().setScore(stepScope.getStartingStepScore());
if (assertWorkingSolutionScoreFromScratch) {
// In BRUTE_FORCE the stepScore can be null because it was not calculated
if (stepScope.getScore() != null) {
phaseScope.assertWorkingScoreFromScratch(stepScope.getScore(), restoreMoveList);
if (stepScope.getStartingStepScore() != null) {
phaseScope.assertWorkingScoreFromScratch(stepScope.getStartingStepScore(), restoreMoveList);
}
}
if (assertExpectedWorkingSolutionScore) {
// In BRUTE_FORCE the stepScore can be null because it was not calculated
if (stepScope.getScore() != null) {
phaseScope.assertExpectedWorkingScore(stepScope.getScore(), restoreMoveList);
if (stepScope.getStartingStepScore() != null) {
phaseScope.assertExpectedWorkingScore(stepScope.getStartingStepScore(), restoreMoveList);
}
}
}
Expand Down
Expand Up @@ -142,9 +142,9 @@ private void doMove(ExhaustiveSearchStepScope stepScope, ExhaustiveSearchNode mo
undoMove.doMove(scoreDirector);
if (assertExpectedUndoMoveScore) {
ExhaustiveSearchPhaseScope phaseScope = stepScope.getPhaseScope();
// In BRUTE_FORCE the stepScore can be null because it was not calculated
if (phaseScope.getLastCompletedStepScope().getScore() != null) {
phaseScope.assertExpectedUndoMoveScore(move, undoMove);
// In BRUTE_FORCE a stepScore can be null because it was not calculated
if (stepScope.getStartingStepScore() != null) {
phaseScope.assertExpectedUndoMoveScore(move, undoMove, stepScope.getStartingStepScore());
}
}
logger.trace(" Move treeId ({}), score ({}), expandable ({}), move ({}).",
Expand Down
Expand Up @@ -16,6 +16,7 @@

package org.optaplanner.core.impl.exhaustivesearch.scope;

import org.optaplanner.core.api.score.Score;
import org.optaplanner.core.impl.exhaustivesearch.node.ExhaustiveSearchNode;
import org.optaplanner.core.impl.phase.scope.AbstractStepScope;

Expand Down Expand Up @@ -46,7 +47,10 @@ public ExhaustiveSearchNode getExpandingNode() {

public void setExpandingNode(ExhaustiveSearchNode expandingNode) {
this.expandingNode = expandingNode;
this.score = expandingNode.getScore();
}

public Score getStartingStepScore() {
return expandingNode.getScore();
}

public Long getSelectedMoveCount() {
Expand Down
Expand Up @@ -149,9 +149,8 @@ private void doMove(LocalSearchMoveScope moveScope) {
processMove(moveScope);
undoMove.doMove(scoreDirector);
if (assertExpectedUndoMoveScore) {
LocalSearchPhaseScope phaseScope = moveScope.getStepScope()
.getPhaseScope();
phaseScope.assertExpectedUndoMoveScore(move, undoMove);
LocalSearchPhaseScope phaseScope = moveScope.getStepScope().getPhaseScope();
phaseScope.assertExpectedUndoMoveScore(move, undoMove, phaseScope.getLastCompletedStepScope().getScore());
}
logger.trace(" Move index ({}), score ({}), accepted ({}), move ({}).",
moveScope.getMoveIndex(), moveScope.getScore(), moveScope.getAccepted(),
Expand Down
Expand Up @@ -132,13 +132,12 @@ public void assertWorkingScoreFromScratch(Score workingScore, Object completedAc
solverScope.assertWorkingScoreFromScratch(workingScore, completedAction);
}

public void assertExpectedUndoMoveScore(Move move, Move undoMove) {
public void assertExpectedUndoMoveScore(Move move, Move undoMove, Score beforeMoveScore) {
Score undoScore = calculateScore();
Score lastCompletedStepScore = getLastCompletedStepScope().getScore();
if (!undoScore.equals(lastCompletedStepScore)) {
if (!undoScore.equals(beforeMoveScore)) {
// First assert that are probably no corrupted score rules.
getScoreDirector().assertWorkingScoreFromScratch(undoScore, undoMove);
throw new IllegalStateException("UndoMove corruption: the lastCompletedStepScore (" + lastCompletedStepScore
throw new IllegalStateException("UndoMove corruption: the beforeMoveScore (" + beforeMoveScore
+ ") is not the undoScore (" + undoScore
+ ") which is the uncorruptedScore (" + undoScore + ") of the workingSolution.\n"
+ " 1) Enable EnvironmentMode " + EnvironmentMode.FULL_ASSERT
Expand All @@ -147,8 +146,7 @@ public void assertExpectedUndoMoveScore(Move move, Move undoMove) {
+ " The move (" + move + ") might have a corrupted undoMove (" + undoMove + ").\n"
+ " 3) Check your custom " + VariableListener.class.getSimpleName() + "s (if you have any)"
+ " for shadow variables that are used by the score constraints with a different score weight"
+ " between the lastCompletedStepScore (" + lastCompletedStepScore
+ ") and the undoScore (" + undoScore + ").");
+ " between the beforeMoveScore (" + beforeMoveScore + ") and the undoScore (" + undoScore + ").");
}
}

Expand Down

0 comments on commit 0e9da20

Please sign in to comment.