@Override
    public void solve(DefaultSolverScope<Solution_> solverScope) {
        PartitionedSearchPhaseScope<Solution_> phaseScope = new PartitionedSearchPhaseScope<>(solverScope);
        List<Solution_> partList = solutionPartitioner.splitWorkingSolution(
                solverScope.getScoreDirector(), runnablePartThreadLimit);
        int partCount = partList.size();
        phaseScope.setPartCount(partCount);
        phaseStarted(phaseScope);
        ExecutorService executor = createThreadPoolExecutor(partCount);
        ChildThreadPlumbingTermination childThreadPlumbingTermination = new ChildThreadPlumbingTermination();
        PartitionQueue<Solution_> partitionQueue = new PartitionQueue<>(partCount);
        Semaphore runnablePartThreadSemaphore
                = runnablePartThreadLimit == null ? null : new Semaphore(runnablePartThreadLimit, true);
        try {
            for (ListIterator<Solution_> it = partList.listIterator(); it.hasNext();) {
                int partIndex = it.nextIndex();
                Solution_ part = it.next();
                PartitionSolver<Solution_> partitionSolver = buildPartitionSolver(
                        childThreadPlumbingTermination, runnablePartThreadSemaphore, solverScope);
                partitionSolver.addEventListener(event -> {
                    InnerScoreDirector<Solution_> childScoreDirector = partitionSolver.solverScope.getScoreDirector();
                    PartitionChangeMove<Solution_> move = PartitionChangeMove.createMove(childScoreDirector, partIndex);
                    InnerScoreDirector<Solution_> parentScoreDirector = solverScope.getScoreDirector();
                    move = move.rebase(parentScoreDirector);
                    partitionQueue.addMove(partIndex, move);
                });
                executor.submit(() -> {
                    try {
                        partitionSolver.solve(part);
                        long partCalculationCount = partitionSolver.getScoreCalculationCount();
                        partitionQueue.addFinish(partIndex, partCalculationCount);
                    } catch (Throwable throwable) {
                        // Any Exception or even Error that happens here (on a partition thread) must be stored
                        // in the partitionQueue in order to be propagated to the solver thread.
                        logger.trace("{}            Part thread ({}) exception that will be propagated to the solver thread.",
                                logIndentation, partIndex, throwable);
                        partitionQueue.addExceptionThrown(partIndex, throwable);
                    }
                });
            }
            for (PartitionChangeMove<Solution_> step : partitionQueue) {
                PartitionedSearchStepScope<Solution_> stepScope = new PartitionedSearchStepScope<>(phaseScope);
                stepStarted(stepScope);
                stepScope.setStep(step);
                if (logger.isDebugEnabled()) {
                    stepScope.setStepString(step.toString());
                }
                doStep(stepScope);
                stepEnded(stepScope);
                phaseScope.setLastCompletedStepScope(stepScope);
            }
            phaseScope.addChildThreadsScoreCalculationCount(partitionQueue.getPartsCalculationCount());
        } finally {
            // In case one of the partition threads threw an Exception, it is propagated here
            // but the other partition threads are not aware of the failure and may continue solving for a long time,
            // so we need to ask them to terminate. In case no exception was thrown, this does nothing.
            childThreadPlumbingTermination.terminateChildren();
            ThreadUtils.shutdownAwaitOrKill(executor, logIndentation, "Partitioned Search");
        }
        phaseEnded(phaseScope);
    }
@Override
    public void solve(DefaultSolverScope<Solution_> solverScope) {
        PartitionedSearchPhaseScope<Solution_> phaseScope = new PartitionedSearchPhaseScope<>(solverScope);
        List<Solution_> partList = solutionPartitioner.splitWorkingSolution(
                solverScope.getScoreDirector(), runnablePartThreadLimit);
        int partCount = partList.size();
        phaseScope.setPartCount(partCount);
        phaseStarted(phaseScope);
        ExecutorService executor = createThreadPoolExecutor(partCount);
        ChildThreadPlumbingTermination childThreadPlumbingTermination = new ChildThreadPlumbingTermination();
        PartitionQueue<Solution_> partitionQueue = new PartitionQueue<>(partCount);
        Semaphore runnablePartThreadSemaphore
                = runnablePartThreadLimit == null ? null : new Semaphore(runnablePartThreadLimit, true);
        try {
            for (ListIterator<Solution_> it = partList.listIterator(); it.hasNext();) {
                int partIndex = it.nextIndex();
                Solution_ part = it.next();
                PartitionSolver<Solution_> partitionSolver = buildPartitionSolver(
                        childThreadPlumbingTermination, runnablePartThreadSemaphore, solverScope);
                partitionSolver.addEventListener(event -> {
                    InnerScoreDirector<Solution_> childScoreDirector = partitionSolver.solverScope.getScoreDirector();
                    PartitionChangeMove<Solution_> move = PartitionChangeMove.createMove(childScoreDirector, partIndex);
                    InnerScoreDirector<Solution_> parentScoreDirector = solverScope.getScoreDirector();
                    move = move.rebase(parentScoreDirector);
                    partitionQueue.addMove(partIndex, move);
                });
                executor.submit(() -> {
                    try {
                        partitionSolver.solve(part);
                        long partCalculationCount = partitionSolver.getScoreCalculationCount();
                        partitionQueue.addFinish(partIndex, partCalculationCount);
                    } catch (Throwable throwable) {
                        
                        
                        logger.trace("{}            Part thread ({}) exception that will be propagated to the solver thread.",
                                logIndentation, partIndex, throwable);
                        partitionQueue.addExceptionThrown(partIndex, throwable);
                    }
                });
            }
            for (PartitionChangeMove<Solution_> step : partitionQueue) {
                PartitionedSearchStepScope<Solution_> stepScope = new PartitionedSearchStepScope<>(phaseScope);
                stepStarted(stepScope);
                stepScope.setStep(step);
                if (logger.isDebugEnabled()) {
                    stepScope.setStepString(step.toString());
                }
                doStep(stepScope);
                stepEnded(stepScope);
                phaseScope.setLastCompletedStepScope(stepScope);
            }
            phaseScope.addChildThreadsScoreCalculationCount(partitionQueue.getPartsCalculationCount());
        } finally {
            
            
            
            childThreadPlumbingTermination.terminateChildren();
            ThreadUtils.shutdownAwaitOrKill(executor, logIndentation, "Partitioned Search");
        }
        phaseEnded(phaseScope);
    }
@ Override public void solve ( DefaultSolverScope < Solution_ > solverScope ) { PartitionedSearchPhaseScope < Solution_ > phaseScope = new PartitionedSearchPhaseScope <> ( solverScope ) ; List < Solution_ > partList = solutionPartitioner . splitWorkingSolution ( solverScope . getScoreDirector ( ) , runnablePartThreadLimit ) ; int partCount = partList . size ( ) ; phaseScope . setPartCount ( partCount ) ; phaseStarted ( phaseScope ) ; ExecutorService executor = createThreadPoolExecutor ( partCount ) ; ChildThreadPlumbingTermination childThreadPlumbingTermination = new ChildThreadPlumbingTermination ( ) ; PartitionQueue < Solution_ > partitionQueue = new PartitionQueue <> ( partCount ) ; Semaphore runnablePartThreadSemaphore = runnablePartThreadLimit == null ? null : new Semaphore ( runnablePartThreadLimit , true ) ; try { for ( ListIterator < Solution_ > it = partList . listIterator ( ) ; it . hasNext ( ) ; ) { int partIndex = it . nextIndex ( ) ; Solution_ part = it . next ( ) ; PartitionSolver < Solution_ > partitionSolver = buildPartitionSolver ( childThreadPlumbingTermination , runnablePartThreadSemaphore , solverScope ) ; partitionSolver . addEventListener ( event -> { InnerScoreDirector < Solution_ > childScoreDirector = partitionSolver . solverScope . getScoreDirector ( ) ; PartitionChangeMove < Solution_ > move = PartitionChangeMove . createMove ( childScoreDirector , partIndex ) ; InnerScoreDirector < Solution_ > parentScoreDirector = solverScope . getScoreDirector ( ) ; move = move . rebase ( parentScoreDirector ) ; partitionQueue . addMove ( partIndex , move ) ; } ) ; executor . submit ( ( ) -> { try { partitionSolver . solve ( part ) ; long partCalculationCount = partitionSolver . getScoreCalculationCount ( ) ; partitionQueue . addFinish ( partIndex , partCalculationCount ) ; } catch ( Throwable throwable ) { // Any Exception or even Error that happens here (on a partition thread) must be stored // in the partitionQueue in order to be propagated to the solver thread. logger . trace ( "{}            Part thread ({}) exception that will be propagated to the solver thread." , logIndentation , partIndex , throwable ) ; partitionQueue . addExceptionThrown ( partIndex , throwable ) ; } } ) ; } for ( PartitionChangeMove < Solution_ > step : partitionQueue ) { PartitionedSearchStepScope < Solution_ > stepScope = new PartitionedSearchStepScope <> ( phaseScope ) ; stepStarted ( stepScope ) ; stepScope . setStep ( step ) ; if ( logger . isDebugEnabled ( ) ) { stepScope . setStepString ( step . toString ( ) ) ; } doStep ( stepScope ) ; stepEnded ( stepScope ) ; phaseScope . setLastCompletedStepScope ( stepScope ) ; } phaseScope . addChildThreadsScoreCalculationCount ( partitionQueue . getPartsCalculationCount ( ) ) ; } finally { // In case one of the partition threads threw an Exception, it is propagated here // but the other partition threads are not aware of the failure and may continue solving for a long time, // so we need to ask them to terminate. In case no exception was thrown, this does nothing. childThreadPlumbingTermination . terminateChildren ( ) ; ThreadUtils . shutdownAwaitOrKill ( executor , logIndentation , "Partitioned Search" ) ; } phaseEnded ( phaseScope ) ; }
************************************************************************
************************************************************************