/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.optaplanner.core.impl.constructionheuristic.decider; import org.optaplanner.core.api.score.Score; import org.optaplanner.core.impl.constructionheuristic.decider.forager.ConstructionHeuristicForager; import org.optaplanner.core.impl.constructionheuristic.placer.Placement; import org.optaplanner.core.impl.constructionheuristic.scope.ConstructionHeuristicMoveScope; import org.optaplanner.core.impl.constructionheuristic.scope.ConstructionHeuristicPhaseScope; import org.optaplanner.core.impl.constructionheuristic.scope.ConstructionHeuristicStepScope; import org.optaplanner.core.impl.heuristic.move.Move; import org.optaplanner.core.impl.score.director.ScoreDirector; import org.optaplanner.core.impl.solver.scope.DefaultSolverScope; import org.optaplanner.core.impl.solver.termination.Termination; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConstructionHeuristicDecider { protected final transient Logger logger = LoggerFactory.getLogger(getClass()); protected final String logIndentation; protected final Termination termination; protected final ConstructionHeuristicForager forager; protected boolean assertMoveScoreFromScratch = false; protected boolean assertExpectedUndoMoveScore = false; public ConstructionHeuristicDecider(String logIndentation, Termination termination, ConstructionHeuristicForager forager) { this.logIndentation = logIndentation; this.termination = termination; this.forager = forager; } public ConstructionHeuristicForager getForager() { return forager; } public void setAssertMoveScoreFromScratch(boolean assertMoveScoreFromScratch) { this.assertMoveScoreFromScratch = assertMoveScoreFromScratch; } public void setAssertExpectedUndoMoveScore(boolean assertExpectedUndoMoveScore) { this.assertExpectedUndoMoveScore = assertExpectedUndoMoveScore; } // ************************************************************************ // Worker methods // ************************************************************************ public void solvingStarted(DefaultSolverScope solverScope) { forager.solvingStarted(solverScope); } public void phaseStarted(ConstructionHeuristicPhaseScope phaseScope) { forager.phaseStarted(phaseScope); } public void stepStarted(ConstructionHeuristicStepScope stepScope) { forager.stepStarted(stepScope); } public void stepEnded(ConstructionHeuristicStepScope stepScope) { forager.stepEnded(stepScope); } public void phaseEnded(ConstructionHeuristicPhaseScope phaseScope) { forager.phaseEnded(phaseScope); } public void solvingEnded(DefaultSolverScope solverScope) { forager.solvingEnded(solverScope); } public void decideNextStep(ConstructionHeuristicStepScope stepScope, Placement placement) { int moveIndex = 0; for (Move move : placement) { ConstructionHeuristicMoveScope moveScope = new ConstructionHeuristicMoveScope(stepScope); moveScope.setMoveIndex(moveIndex); moveIndex++; moveScope.setMove(move); // Do not filter out pointless moves, because the original value of the entity(s) is irrelevant. // If the original value is null and the variable is nullable, the move to null must be done too. doMove(moveScope); if (forager.isQuitEarly()) { break; } stepScope.getPhaseScope().getSolverScope().checkYielding(); if (termination.isPhaseTerminated(stepScope.getPhaseScope())) { break; } } stepScope.setSelectedMoveCount((long) moveIndex); ConstructionHeuristicMoveScope pickedMoveScope = forager.pickMove(stepScope); if (pickedMoveScope != null) { Move step = pickedMoveScope.getMove(); stepScope.setStep(step); if (logger.isDebugEnabled()) { stepScope.setStepString(step.toString()); } stepScope.setUndoStep(pickedMoveScope.getUndoMove()); stepScope.setScore(pickedMoveScope.getScore()); } } private void doMove(ConstructionHeuristicMoveScope moveScope) { ScoreDirector scoreDirector = moveScope.getScoreDirector(); Move move = moveScope.getMove(); Move undoMove = move.doMove(scoreDirector); moveScope.setUndoMove(undoMove); processMove(moveScope); undoMove.doMove(scoreDirector); if (assertExpectedUndoMoveScore) { ConstructionHeuristicPhaseScope phaseScope = moveScope.getStepScope().getPhaseScope(); phaseScope.assertExpectedUndoMoveScore(move, undoMove, phaseScope.getLastCompletedStepScope().getScore()); } logger.trace("{} Move index ({}), score ({}), move ({}).", logIndentation, moveScope.getMoveIndex(), moveScope.getScore(), moveScope.getMove()); } private void processMove(ConstructionHeuristicMoveScope moveScope) { Score score = moveScope.getStepScope().getPhaseScope().calculateScore(); if (assertMoveScoreFromScratch) { moveScope.getStepScope().getPhaseScope().assertWorkingScoreFromScratch(score, moveScope.getMove()); } moveScope.setScore(score); forager.addMove(moveScope); } }