Skip to content

Commit

Permalink
PLANNER-611 Move.doMove() must return undo move to allow CompositeMov…
Browse files Browse the repository at this point in the history
…e to return a correct undo move
  • Loading branch information
ge0ffrey committed Feb 28, 2017
1 parent 60c4543 commit 24bdaaa
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 120 deletions.
Expand Up @@ -122,9 +122,8 @@ public void decideNextStep(ConstructionHeuristicStepScope stepScope, Placement p
private void doMove(ConstructionHeuristicMoveScope moveScope) { private void doMove(ConstructionHeuristicMoveScope moveScope) {
ScoreDirector scoreDirector = moveScope.getScoreDirector(); ScoreDirector scoreDirector = moveScope.getScoreDirector();
Move move = moveScope.getMove(); Move move = moveScope.getMove();
Move undoMove = move.createUndoMove(scoreDirector); Move undoMove = move.doMove(scoreDirector);
moveScope.setUndoMove(undoMove); moveScope.setUndoMove(undoMove);
move.doMove(scoreDirector);
processMove(moveScope); processMove(moveScope);
undoMove.doMove(scoreDirector); undoMove.doMove(scoreDirector);
if (assertExpectedUndoMoveScore) { if (assertExpectedUndoMoveScore) {
Expand Down
Expand Up @@ -146,9 +146,8 @@ public void expandNode(ExhaustiveSearchStepScope<Solution_> stepScope) {
private void doMove(ExhaustiveSearchStepScope<Solution_> stepScope, ExhaustiveSearchNode moveNode) { private void doMove(ExhaustiveSearchStepScope<Solution_> stepScope, ExhaustiveSearchNode moveNode) {
InnerScoreDirector<Solution_> scoreDirector = stepScope.getScoreDirector(); InnerScoreDirector<Solution_> scoreDirector = stepScope.getScoreDirector();
Move<Solution_> move = moveNode.getMove(); Move<Solution_> move = moveNode.getMove();
Move<Solution_> undoMove = move.createUndoMove(scoreDirector); Move<Solution_> undoMove = move.doMove(scoreDirector);
moveNode.setUndoMove(undoMove); moveNode.setUndoMove(undoMove);
move.doMove(scoreDirector);
processMove(stepScope, moveNode); processMove(stepScope, moveNode);
undoMove.doMove(scoreDirector); undoMove.doMove(scoreDirector);
if (assertExpectedUndoMoveScore) { if (assertExpectedUndoMoveScore) {
Expand Down
Expand Up @@ -32,11 +32,21 @@ public String getSimpleMoveTypeDescription() {
} }


@Override @Override
public final void doMove(ScoreDirector<Solution_> scoreDirector) { public final AbstractMove<Solution_> doMove(ScoreDirector<Solution_> scoreDirector) {
AbstractMove<Solution_> undoMove = createUndoMove(scoreDirector);
doMoveOnGenuineVariables(scoreDirector); doMoveOnGenuineVariables(scoreDirector);
scoreDirector.triggerVariableListeners(); scoreDirector.triggerVariableListeners();
return undoMove;
} }


/**
* Called before the move is done, so the move can be evaluated and then be undone
* without resulting into a permanent change in the solution.
* @param scoreDirector the {@link ScoreDirector} not yet modified by the move.
* @return an undoMove which does the exact opposite of this move.
*/
protected abstract AbstractMove<Solution_> createUndoMove(ScoreDirector<Solution_> scoreDirector);

/** /**
* Like {@link #doMove(ScoreDirector)} but without the {@link ScoreDirector#triggerVariableListeners()} call * Like {@link #doMove(ScoreDirector)} but without the {@link ScoreDirector#triggerVariableListeners()} call
* (because {@link #doMove(ScoreDirector)} already does that). * (because {@link #doMove(ScoreDirector)} already does that).
Expand Down
Expand Up @@ -96,24 +96,17 @@ public boolean isMoveDoable(ScoreDirector<Solution_> scoreDirector) {
} }


@Override @Override
public CompositeMove<Solution_> createUndoMove(ScoreDirector<Solution_> scoreDirector) { public CompositeMove<Solution_> doMove(ScoreDirector<Solution_> scoreDirector) {
Move<Solution_>[] undoMoves = new Move[moves.length]; Move<Solution_>[] undoMoves = new Move[moves.length];
for (int i = 0; i < moves.length; i++) { for (int i = 0; i < moves.length; i++) {
// Note: this undoMove creation doesn't have the effect yet of a previous move in the moveList
Move<Solution_> undoMove = moves[i].createUndoMove(scoreDirector);
undoMoves[moves.length - 1 - i] = undoMove;
}
return new CompositeMove<>(undoMoves);
}

@Override
public void doMove(ScoreDirector<Solution_> scoreDirector) {
for (Move<Solution_> move : moves) {
// Calls scoreDirector.triggerVariableListeners() between moves // Calls scoreDirector.triggerVariableListeners() between moves
// because a later move can depend on the shadow variables changed by an earlier move // because a later move can depend on the shadow variables changed by an earlier move
move.doMove(scoreDirector); Move<Solution_> undoMove = moves[i].doMove(scoreDirector);
// Undo in reverse order and each undoMove is created after previous moves have been done
undoMoves[moves.length - 1 - i] = undoMove;
} }
// No need to call scoreDirector.triggerVariableListeners() because Move.doMove() already does it for every move. // No need to call scoreDirector.triggerVariableListeners() because Move.doMove() already does it for every move.
return new CompositeMove<>(undoMoves);
} }


// ************************************************************************ // ************************************************************************
Expand Down
Expand Up @@ -66,14 +66,6 @@ public interface Move<Solution_> {
*/ */
boolean isMoveDoable(ScoreDirector<Solution_> scoreDirector); boolean isMoveDoable(ScoreDirector<Solution_> scoreDirector);


/**
* Called before the move is done, so the move can be evaluated and then be undone
* without resulting into a permanent change in the solution.
* @param scoreDirector the {@link ScoreDirector} not yet modified by the move.
* @return an undoMove which does the exact opposite of this move.
*/
Move<Solution_> createUndoMove(ScoreDirector<Solution_> scoreDirector);

/** /**
* Does the move (which indirectly affects the {@link ScoreDirector#getWorkingSolution()}). * Does the move (which indirectly affects the {@link ScoreDirector#getWorkingSolution()}).
* When the {@link PlanningSolution working solution} is modified, the {@link ScoreDirector} must be correctly notified * When the {@link PlanningSolution working solution} is modified, the {@link ScoreDirector} must be correctly notified
Expand All @@ -82,9 +74,13 @@ public interface Move<Solution_> {
* otherwise later calculated {@link Score}s will be corrupted. * otherwise later calculated {@link Score}s will be corrupted.
* <p> * <p>
* This method must end with calling {@link ScoreDirector#triggerVariableListeners()} to ensure all shadow variables are updated. * This method must end with calling {@link ScoreDirector#triggerVariableListeners()} to ensure all shadow variables are updated.
* @param scoreDirector never null, the {@link ScoreDirector} that needs to get notified of the changes. * <p>
* This method must return an undo move, so the move can be evaluated and then be undone
* without resulting into a permanent change in the solution.
* @param scoreDirector never null, the {@link ScoreDirector} that needs to get notified of the changes
* @return an undoMove which does the exact opposite of this move
*/ */
void doMove(ScoreDirector<Solution_> scoreDirector); Move<Solution_> doMove(ScoreDirector<Solution_> scoreDirector);


// ************************************************************************ // ************************************************************************
// Introspection methods // Introspection methods
Expand Down
Expand Up @@ -143,9 +143,8 @@ public void decideNextStep(LocalSearchStepScope<Solution_> stepScope) {
private void doMove(LocalSearchMoveScope<Solution_> moveScope) { private void doMove(LocalSearchMoveScope<Solution_> moveScope) {
ScoreDirector<Solution_> scoreDirector = moveScope.getScoreDirector(); ScoreDirector<Solution_> scoreDirector = moveScope.getScoreDirector();
Move<Solution_> move = moveScope.getMove(); Move<Solution_> move = moveScope.getMove();
Move<Solution_> undoMove = move.createUndoMove(scoreDirector); Move<Solution_> undoMove = move.doMove(scoreDirector);
moveScope.setUndoMove(undoMove); moveScope.setUndoMove(undoMove);
move.doMove(scoreDirector);
processMove(moveScope); processMove(moveScope);
undoMove.doMove(scoreDirector); undoMove.doMove(scoreDirector);
if (assertExpectedUndoMoveScore) { if (assertExpectedUndoMoveScore) {
Expand Down
Expand Up @@ -46,7 +46,7 @@ public void createUndoMove() {
DummyMove b = new DummyMove("b"); DummyMove b = new DummyMove("b");
DummyMove c = new DummyMove("c"); DummyMove c = new DummyMove("c");
CompositeMove<TestdataSolution> move = new CompositeMove<>(a, b, c); CompositeMove<TestdataSolution> move = new CompositeMove<>(a, b, c);
CompositeMove<TestdataSolution> undoMove = move.createUndoMove(scoreDirector); CompositeMove<TestdataSolution> undoMove = move.doMove(scoreDirector);
assertAllCodesOfArray(move.getMoves(), "a", "b", "c"); assertAllCodesOfArray(move.getMoves(), "a", "b", "c");
assertAllCodesOfArray(undoMove.getMoves(), "undo c", "undo b", "undo a"); assertAllCodesOfArray(undoMove.getMoves(), "undo c", "undo b", "undo a");
} }
Expand Down Expand Up @@ -122,7 +122,7 @@ public void equals() {
assertTrue(move.equals(move)); assertTrue(move.equals(move));
} }


@Test @Ignore("PLANNER-611") // TODO https://issues.jboss.org/browse/PLANNER-611 @Test
public void interconnectedChildMoves() { public void interconnectedChildMoves() {
TestdataSolution solution = new TestdataSolution("s1"); TestdataSolution solution = new TestdataSolution("s1");
TestdataValue v1 = new TestdataValue("v1"); TestdataValue v1 = new TestdataValue("v1");
Expand All @@ -143,8 +143,7 @@ public void interconnectedChildMoves() {


ScoreDirector<TestdataSolution> scoreDirector ScoreDirector<TestdataSolution> scoreDirector
= mockScoreDirector(variableDescriptor.getEntityDescriptor().getSolutionDescriptor()); = mockScoreDirector(variableDescriptor.getEntityDescriptor().getSolutionDescriptor());
Move<TestdataSolution> undoMove = move.createUndoMove(scoreDirector); Move<TestdataSolution> undoMove = move.doMove(scoreDirector);
move.doMove(scoreDirector);


assertSame(v3, e1.getValue()); assertSame(v3, e1.getValue());
assertSame(v1, e2.getValue()); assertSame(v1, e2.getValue());
Expand Down

0 comments on commit 24bdaaa

Please sign in to comment.