@Override
 public void stepEnded(AbstractStepScope stepScope) {
   if (stepScope.isBestSolutionCloningDelayed()) {
     return;
   }
   AbstractSolverPhaseScope phaseScope = stepScope.getPhaseScope();
   int uninitializedVariableCount = stepScope.getUninitializedVariableCount();
   Score score = stepScope.getScore();
   DefaultSolverScope solverScope = phaseScope.getSolverScope();
   int bestUninitializedVariableCount = solverScope.getBestUninitializedVariableCount();
   Score bestScore = solverScope.getBestScore();
   boolean bestScoreImproved;
   if (uninitializedVariableCount == bestUninitializedVariableCount) {
     bestScoreImproved = score.compareTo(bestScore) > 0;
   } else {
     bestScoreImproved = uninitializedVariableCount < bestUninitializedVariableCount;
   }
   stepScope.setBestScoreImproved(bestScoreImproved);
   if (bestScoreImproved) {
     phaseScope.setBestSolutionStepIndex(stepScope.getStepIndex());
     Solution newBestSolution = stepScope.createOrGetClonedSolution();
     updateBestSolution(solverScope, newBestSolution, uninitializedVariableCount);
   } else if (assertBestScoreIsUnmodified) {
     solverScope.assertScoreFromScratch(solverScope.getBestSolution());
   }
 }
 private void checkProblemFactChanges() {
   BlockingQueue<ProblemFactChange> problemFactChangeQueue =
       basicPlumbingTermination.getProblemFactChangeQueue();
   if (!problemFactChangeQueue.isEmpty()) {
     solverScope.setRestartSolver(true);
     solverScope.setWorkingSolutionFromBestSolution();
     Score score = null;
     int count = 0;
     ProblemFactChange problemFactChange = problemFactChangeQueue.poll();
     while (problemFactChange != null) {
       score = doProblemFactChange(problemFactChange);
       count++;
       problemFactChange = problemFactChangeQueue.poll();
     }
     Solution newBestSolution = solverScope.getScoreDirector().cloneWorkingSolution();
     // TODO BestSolutionRecaller.solverStarted() already calls countUninitializedVariables()
     int newBestUninitializedVariableCount =
         solverScope.getSolutionDescriptor().countUninitializedVariables(newBestSolution);
     bestSolutionRecaller.updateBestSolution(
         solverScope, newBestSolution, newBestUninitializedVariableCount);
     logger.info(
         "Done {} ProblemFactChange(s): new score ({}) possibly uninitialized. Restarting solver.",
         count,
         score);
   }
 }
 public final void solve() {
   solving.set(true);
   basicPlumbingTermination.resetTerminateEarly();
   solverScope.setRestartSolver(true);
   while (solverScope.isRestartSolver()) {
     solverScope.setRestartSolver(false);
     solvingStarted(solverScope);
     runSolverPhases();
     solvingEnded(solverScope);
     checkProblemFactChanges();
   }
   // Must be kept open for doProblemFactChange
   solverScope.getScoreDirector().dispose();
   solving.set(false);
 }
 public void constructCache(DefaultSolverScope solverScope) {
   cachedMoveList =
       moveListFactory.createMoveList(solverScope.getScoreDirector().getWorkingSolution());
   logger.trace(
       "    Created cachedMoveList with size ({}) in moveSelector({}).",
       cachedMoveList.size(),
       this);
 }
 public void solvingEnded(DefaultSolverScope solverScope) {
   for (SolverPhase solverPhase : solverPhaseList) {
     solverPhase.solvingEnded(solverScope);
   }
   bestSolutionRecaller.solvingEnded(solverScope);
   long timeMillisSpend = solverScope.calculateTimeMillisSpend();
   if (timeMillisSpend == 0L) {
     // Avoid divide by zero exception on a fast CPU
     timeMillisSpend = 1L;
   }
   long averageCalculateCountPerSecond = solverScope.getCalculateCount() * 1000L / timeMillisSpend;
   logger.info(
       "Solving ended: time spend ({}), best score ({}), average calculate count per second ({}).",
       timeMillisSpend,
       solverScope.getBestScoreWithUninitializedPrefix(),
       averageCalculateCountPerSecond);
 }
 protected void runSolverPhases() {
   Iterator<SolverPhase> it = solverPhaseList.iterator();
   while (!termination.isSolverTerminated(solverScope) && it.hasNext()) {
     SolverPhase solverPhase = it.next();
     solverPhase.solve(solverScope);
     if (it.hasNext()) {
       solverScope.setWorkingSolutionFromBestSolution();
     }
   }
   // TODO support doing round-robin of phases (only non-construction heuristics)
 }
 public void processWorkingSolutionDuringMove(
     int uninitializedVariableCount, Score score, AbstractStepScope stepScope) {
   AbstractSolverPhaseScope phaseScope = stepScope.getPhaseScope();
   DefaultSolverScope solverScope = phaseScope.getSolverScope();
   int bestUninitializedVariableCount = solverScope.getBestUninitializedVariableCount();
   Score bestScore = solverScope.getBestScore();
   boolean bestScoreImproved;
   if (uninitializedVariableCount == bestUninitializedVariableCount) {
     bestScoreImproved = score.compareTo(bestScore) > 0;
   } else {
     bestScoreImproved = uninitializedVariableCount < bestUninitializedVariableCount;
   }
   // The method processWorkingSolutionDuringMove() is called 0..* times
   // bestScoreImproved is initialized on false before the first call here
   if (bestScoreImproved) {
     stepScope.setBestScoreImproved(bestScoreImproved);
   }
   if (bestScoreImproved) {
     phaseScope.setBestSolutionStepIndex(stepScope.getStepIndex());
     Solution newBestSolution = solverScope.getScoreDirector().cloneWorkingSolution();
     updateBestSolution(solverScope, newBestSolution, uninitializedVariableCount);
   } else if (assertBestScoreIsUnmodified) {
     solverScope.assertScoreFromScratch(solverScope.getBestSolution());
   }
 }
 public void constructCache(DefaultSolverScope solverScope) {
   cachedEntityMap = new TreeMap<Double, Object>();
   ScoreDirector scoreDirector = solverScope.getScoreDirector();
   double probabilityWeightOffset = 0L;
   // TODO Fail-faster if a non FromSolutionPropertyValueSelector is used
   for (Object value : childValueSelector) {
     double probabilityWeight =
         probabilityWeightFactory.createProbabilityWeight(scoreDirector, value);
     cachedEntityMap.put(probabilityWeightOffset, value);
     probabilityWeightOffset += probabilityWeight;
   }
   probabilityWeightTotal = probabilityWeightOffset;
 }
 @Override
 public void solvingStarted(DefaultSolverScope solverScope) {
   super.solvingStarted(solverScope);
   if (anyChained) {
     SupplyManager supplyManager = solverScope.getScoreDirector().getSupplyManager();
     for (GenuineVariableDescriptor variableDescriptor : variableDescriptors) {
       if (variableDescriptor.isChained()) {
         // TODO supply is demanded just to make sure it's there when it's demand again later.
         // Instead it should be remembered for later
         SingletonInverseVariableSupply inverseVariableSupply =
             supplyManager.demand(new SingletonInverseVariableDemand(variableDescriptor));
       }
     }
   }
 }
 @Override
 public void solvingStarted(DefaultSolverScope solverScope) {
   // Starting bestSolution is already set by Solver.setPlanningProblem()
   int uninitializedVariableCount =
       solverScope.getScoreDirector().countWorkingSolutionUninitializedVariables();
   solverScope.setBestUninitializedVariableCount(uninitializedVariableCount);
   Score score = solverScope.calculateScore();
   solverScope.setBestScore(score);
   solverScope.setBestSolutionTimeMillis(System.currentTimeMillis());
   // The original bestSolution might be the final bestSolution and should have an accurate Score
   solverScope.getBestSolution().setScore(score);
   if (uninitializedVariableCount == 0) {
     solverScope.setStartingInitializedScore(score);
   } else {
     solverScope.setStartingInitializedScore(null);
   }
 }
 public void updateBestSolution(
     DefaultSolverScope solverScope, Solution solution, int uninitializedVariableCount) {
   if (uninitializedVariableCount == 0) {
     if (!solverScope.isBestSolutionInitialized()) {
       solverScope.setStartingInitializedScore(solution.getScore());
     }
   }
   solverScope.setBestUninitializedVariableCount(uninitializedVariableCount);
   solverScope.setBestSolution(solution);
   solverScope.setBestScore(solution.getScore());
   solverScope.setBestSolutionTimeMillis(System.currentTimeMillis());
   solverEventSupport.fireBestSolutionChanged(solution);
 }
 public void solvingStarted(DefaultSolverScope solverScope) {
   if (solverScope.getBestSolution() == null) {
     throw new IllegalStateException(
         "The planningProblem must not be null." + " Use Solver.setPlanningProblem(Solution).");
   }
   solverScope.setStartingSystemTimeMillis(System.currentTimeMillis());
   solverScope.setScoreDirector(scoreDirectorFactory.buildScoreDirector());
   solverScope.setWorkingRandom(randomFactory.createRandom());
   solverScope.setWorkingSolutionFromBestSolution();
   bestSolutionRecaller.solvingStarted(solverScope);
   for (SolverPhase solverPhase : solverPhaseList) {
     solverPhase.solvingStarted(solverScope);
   }
   logger.info(
       "Solving started: time spend ({}), score ({}), new best score ({}), random ({}).",
       solverScope.calculateTimeMillisSpend(),
       solverScope.getStartingInitializedScore(),
       solverScope.getBestScore(),
       (randomFactory != null ? randomFactory : "not fixed"));
 }
 public void setPlanningProblem(Solution planningProblem) {
   solverScope.setBestSolution(planningProblem);
 }
 // TODO this shouldn't change after the solve is done
 public long getTimeMillisSpend() {
   return solverScope.calculateTimeMillisSpend();
 }
 private Score doProblemFactChange(ProblemFactChange problemFactChange) {
   problemFactChange.doChange(solverScope.getScoreDirector());
   Score score = solverScope.calculateScore();
   logger.debug("    Done ProblemFactChange: new score ({}).", score);
   return score;
 }
 public Solution getBestSolution() {
   return solverScope.getBestSolution();
 }
 public SolutionDescriptor getSolutionDescriptor() {
   return solverScope.getSolutionDescriptor();
 }