From 118fe4ad5e17e8470fc62f3e8996e384d2c44484 Mon Sep 17 00:00:00 2001 From: Geoffrey De Smet Date: Thu, 8 Sep 2016 16:28:56 +0200 Subject: [PATCH] PLANNER-491 Extract PartSolver + create ScoreDirector during Config.build instead of during outerSolverStarted --- ...MatchTotalBestScoreSubSingleStatistic.java | 2 +- ...MatchTotalStepScoreSubSingleStatistic.java | 2 +- .../core/config/solver/SolverConfig.java | 25 ++-- .../support/VariableListenerSupport.java | 6 +- .../DefaultPartitionedSearchPhase.java | 66 ++------- .../impl/partitionedsearch/PartSolver.java | 137 ++++++++++++++++++ .../score/director/AbstractScoreDirector.java | 11 +- .../score/director/InnerScoreDirector.java | 7 + .../core/impl/solver/AbstractSolver.java | 80 ++++++++++ .../core/impl/solver/DefaultSolver.java | 114 ++++----------- .../impl/solver/event/SolverEventSupport.java | 2 +- 11 files changed, 294 insertions(+), 158 deletions(-) create mode 100644 optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/PartSolver.java create mode 100644 optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/AbstractSolver.java diff --git a/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalbestscore/ConstraintMatchTotalBestScoreSubSingleStatistic.java b/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalbestscore/ConstraintMatchTotalBestScoreSubSingleStatistic.java index 17e8eb32c4..74e1bb75ad 100644 --- a/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalbestscore/ConstraintMatchTotalBestScoreSubSingleStatistic.java +++ b/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalbestscore/ConstraintMatchTotalBestScoreSubSingleStatistic.java @@ -80,7 +80,7 @@ public List getGraphFileList() { @Override public void open(Solver solver) { DefaultSolver defaultSolver = (DefaultSolver) solver; - defaultSolver.setConstraintMatchEnabledPreference(true); + defaultSolver.getSolverScope().getScoreDirector().overwriteConstraintMatchEnabledPreference(true); defaultSolver.addPhaseLifecycleListener(listener); } diff --git a/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalstepscore/ConstraintMatchTotalStepScoreSubSingleStatistic.java b/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalstepscore/ConstraintMatchTotalStepScoreSubSingleStatistic.java index c62a23566c..8c5f504c06 100644 --- a/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalstepscore/ConstraintMatchTotalStepScoreSubSingleStatistic.java +++ b/optaplanner-benchmark/src/main/java/org/optaplanner/benchmark/impl/statistic/subsingle/constraintmatchtotalstepscore/ConstraintMatchTotalStepScoreSubSingleStatistic.java @@ -79,7 +79,7 @@ public List getGraphFileList() { @Override public void open(Solver solver) { DefaultSolver defaultSolver = (DefaultSolver) solver; - defaultSolver.setConstraintMatchEnabledPreference(true); + defaultSolver.getSolverScope().getScoreDirector().overwriteConstraintMatchEnabledPreference(true); defaultSolver.addPhaseLifecycleListener(listener); } diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/config/solver/SolverConfig.java b/optaplanner-core/src/main/java/org/optaplanner/core/config/solver/SolverConfig.java index 4c990c38bf..295f52bed2 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/config/solver/SolverConfig.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/config/solver/SolverConfig.java @@ -44,6 +44,7 @@ import org.optaplanner.core.impl.solver.random.DefaultRandomFactory; import org.optaplanner.core.impl.solver.random.RandomFactory; import org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller; +import org.optaplanner.core.impl.solver.scope.DefaultSolverScope; import org.optaplanner.core.impl.solver.termination.Termination; import static org.apache.commons.lang3.ObjectUtils.*; @@ -208,32 +209,30 @@ public void offerRandomSeedFromSubSingleIndex(long subSingleIndex) { */ public Solver buildSolver(SolverConfigContext configContext) { configContext.validate(); - DefaultSolver solver = new DefaultSolver<>(); EnvironmentMode environmentMode_ = determineEnvironmentMode(); - solver.setEnvironmentMode(environmentMode_); boolean daemon_ = defaultIfNull(daemon, false); - BasicPlumbingTermination basicPlumbingTermination = new BasicPlumbingTermination(daemon_); - solver.setBasicPlumbingTermination(basicPlumbingTermination); - solver.setRandomFactory(buildRandomFactory(environmentMode_)); + RandomFactory randomFactory = buildRandomFactory(environmentMode_); SolutionDescriptor solutionDescriptor = buildSolutionDescriptor(configContext); ScoreDirectorFactoryConfig scoreDirectorFactoryConfig_ = scoreDirectorFactoryConfig == null ? new ScoreDirectorFactoryConfig() : scoreDirectorFactoryConfig; InnerScoreDirectorFactory scoreDirectorFactory = scoreDirectorFactoryConfig_.buildScoreDirectorFactory( configContext, environmentMode_, solutionDescriptor); - solver.setConstraintMatchEnabledPreference(environmentMode_.isAsserted()); - solver.setScoreDirectorFactory(scoreDirectorFactory); + boolean constraintMatchEnabledPreference = environmentMode_.isAsserted(); + DefaultSolverScope solverScope = new DefaultSolverScope<>(); + solverScope.setScoreDirector(scoreDirectorFactory.buildScoreDirector(constraintMatchEnabledPreference)); HeuristicConfigPolicy configPolicy = new HeuristicConfigPolicy(environmentMode_, scoreDirectorFactory); TerminationConfig terminationConfig_ = terminationConfig == null ? new TerminationConfig() : terminationConfig; + BasicPlumbingTermination basicPlumbingTermination = new BasicPlumbingTermination(daemon_); Termination termination = terminationConfig_.buildTermination(configPolicy, basicPlumbingTermination); - solver.setTermination(termination); BestSolutionRecaller bestSolutionRecaller = new BestSolutionRecallerConfig() .buildBestSolutionRecaller(environmentMode_); - solver.setBestSolutionRecaller(bestSolutionRecaller); - solver.setPhaseList(buildPhaseList(configPolicy, bestSolutionRecaller, termination)); + List> phaseList = buildPhaseList(configPolicy, bestSolutionRecaller, termination); + DefaultSolver solver = new DefaultSolver<>(environmentMode_, randomFactory, + basicPlumbingTermination, termination, bestSolutionRecaller, phaseList, solverScope); return solver; } @@ -283,7 +282,7 @@ public SolutionDescriptor buildSolutionDescriptor(SolverC } } - protected List buildPhaseList(HeuristicConfigPolicy configPolicy, + protected List> buildPhaseList(HeuristicConfigPolicy configPolicy, BestSolutionRecaller bestSolutionRecaller, Termination termination) { List phaseConfigList_ = phaseConfigList; @@ -292,10 +291,10 @@ protected List buildPhaseList(HeuristicConfigPolicy configPolicy, new ConstructionHeuristicPhaseConfig(), new LocalSearchPhaseConfig()); } - List phaseList = new ArrayList<>(phaseConfigList_.size()); + List> phaseList = new ArrayList<>(phaseConfigList_.size()); int phaseIndex = 0; for (PhaseConfig phaseConfig : phaseConfigList_) { - Phase phase = phaseConfig.buildPhase(phaseIndex, configPolicy, + Phase phase = phaseConfig.buildPhase(phaseIndex, configPolicy, bestSolutionRecaller, termination); phaseList.add(phase); phaseIndex++; diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/domain/variable/listener/support/VariableListenerSupport.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/domain/variable/listener/support/VariableListenerSupport.java index cbcf5db20f..ef0962b2a5 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/impl/domain/variable/listener/support/VariableListenerSupport.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/domain/variable/listener/support/VariableListenerSupport.java @@ -65,11 +65,9 @@ public void linkVariableListeners() { notificationQueuesAreEmpty = true; for (EntityDescriptor entityDescriptor : scoreDirector.getSolutionDescriptor().getEntityDescriptors()) { for (VariableDescriptor variableDescriptor : entityDescriptor.getDeclaredVariableDescriptors()) { - List variableNotifiableList = new ArrayList<>(); - sourceVariableToNotifiableMap.put(variableDescriptor, variableNotifiableList); + sourceVariableToNotifiableMap.put(variableDescriptor, new ArrayList<>()); } - List entityNotifiableList = new ArrayList<>(); - sourceEntityToNotifiableMap.put(entityDescriptor, entityNotifiableList); + sourceEntityToNotifiableMap.put(entityDescriptor, new ArrayList<>()); } for (EntityDescriptor entityDescriptor : scoreDirector.getSolutionDescriptor().getEntityDescriptors()) { for (ShadowVariableDescriptor shadowVariableDescriptor : entityDescriptor.getDeclaredShadowVariableDescriptors()) { diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/DefaultPartitionedSearchPhase.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/DefaultPartitionedSearchPhase.java index c78653101b..2f995e1f8a 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/DefaultPartitionedSearchPhase.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/DefaultPartitionedSearchPhase.java @@ -29,7 +29,6 @@ import org.optaplanner.core.impl.partitionedsearch.partitioner.SolutionPartitioner; import org.optaplanner.core.impl.phase.AbstractPhase; import org.optaplanner.core.impl.phase.Phase; -import org.optaplanner.core.impl.phase.event.PhaseLifecycleSupport; import org.optaplanner.core.impl.solver.ChildThreadType; import org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller; import org.optaplanner.core.impl.solver.scope.DefaultSolverScope; @@ -77,8 +76,8 @@ public void solve(DefaultSolverScope solverScope) { List partList = solutionPartitioner.splitWorkingSolution(solverScope.getScoreDirector()); List futureList = new ArrayList<>(partList.size()); for (Solution_ part : partList) { - PartPhaseRunner partPhaseRunner = new PartPhaseRunner(part, solverScope); - Future future = executorService.submit(partPhaseRunner); + PartSolver partSolver = buildPartSolver(solverScope); + Future future = executorService.submit(() -> partSolver.solve(part)); futureList.add(future); } for (Future future : futureList) { @@ -123,58 +122,21 @@ public void solve(DefaultSolverScope solverScope) { // phaseEnded(phaseScope); } - protected class PartPhaseRunner implements Runnable { - - protected final Solution_ part; - protected final PhaseLifecycleSupport partPhaseLifecycleSupport = new PhaseLifecycleSupport<>(); - protected final BestSolutionRecaller partBestSolutionRecaller; - protected final Termination partTermination; - protected final List> phaseList; - - protected final DefaultSolverScope partSolverScope; - - public PartPhaseRunner(Solution_ part, DefaultSolverScope solverScope) { - this.part = part; - phaseList = new ArrayList<>(phaseConfigList.size()); - partBestSolutionRecaller = new BestSolutionRecallerConfig() - .buildBestSolutionRecaller(configPolicy.getEnvironmentMode()); -// partBestSolutionRecaller.setSolverEventSupport(this); // TODO - partTermination = termination.createChildThreadTermination(solverScope, ChildThreadType.PART_THREAD); - int phaseIndex = 0; - for (PhaseConfig phaseConfig : phaseConfigList) { - Phase phase = phaseConfig.buildPhase(phaseIndex, configPolicy, partBestSolutionRecaller, partTermination); - phase.setSolverPhaseLifecycleSupport(partPhaseLifecycleSupport); - phaseList.add(phase); - phaseIndex++; - } - partSolverScope = solverScope.createChildThreadSolverScope(ChildThreadType.PART_THREAD); + public PartSolver buildPartSolver(DefaultSolverScope solverScope) { + Termination partTermination = termination.createChildThreadTermination(solverScope, ChildThreadType.PART_THREAD); + BestSolutionRecaller bestSolutionRecaller = new BestSolutionRecallerConfig() + .buildBestSolutionRecaller(configPolicy.getEnvironmentMode()); + List> phaseList = new ArrayList<>(phaseConfigList.size()); + int partPhaseIndex = 0; + for (PhaseConfig phaseConfig : phaseConfigList) { + phaseList.add(phaseConfig.buildPhase(partPhaseIndex, configPolicy, bestSolutionRecaller, partTermination)); + partPhaseIndex++; } - - @Override - public void run() { - partSolverScope.setBestSolution(part); - partSolverScope.setWorkingSolutionFromBestSolution(); - partBestSolutionRecaller.solvingStarted(partSolverScope); - phaseLifecycleSupport.fireSolvingStarted(partSolverScope); - for (Phase phase : phaseList) { - phase.solvingStarted(partSolverScope); - } - for (Phase phase : phaseList) { - phase.solve(partSolverScope); - } - for (Phase phase : phaseList) { - phase.solvingEnded(partSolverScope); - } - phaseLifecycleSupport.fireSolvingEnded(partSolverScope); - partBestSolutionRecaller.solvingEnded(partSolverScope); - partSolverScope.endingNow(); - partSolverScope.getScoreDirector().dispose(); - // TODO log? - } - + DefaultSolverScope partSolverScope = solverScope.createChildThreadSolverScope(ChildThreadType.PART_THREAD); + return new PartSolver<>(partTermination, bestSolutionRecaller, phaseList, partSolverScope); } -// private void doStep(PartitionedSearchStepScope stepScope) { + // private void doStep(PartitionedSearchStepScope stepScope) { // Move nextStep = stepScope.getStep(); // nextStep.doMove(stepScope.getScoreDirector()); // predictWorkingStepScore(stepScope, nextStep); diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/PartSolver.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/PartSolver.java new file mode 100644 index 0000000000..c87ffb8e7d --- /dev/null +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/partitionedsearch/PartSolver.java @@ -0,0 +1,137 @@ +/* + * Copyright 2016 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.partitionedsearch; + +import java.util.List; + +import org.optaplanner.core.api.domain.solution.PlanningSolution; +import org.optaplanner.core.api.score.Score; +import org.optaplanner.core.impl.phase.Phase; +import org.optaplanner.core.impl.score.director.ScoreDirectorFactory; +import org.optaplanner.core.impl.solver.AbstractSolver; +import org.optaplanner.core.impl.solver.ProblemFactChange; +import org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller; +import org.optaplanner.core.impl.solver.scope.DefaultSolverScope; +import org.optaplanner.core.impl.solver.termination.Termination; + +/** + * @param the solution type, the class with the {@link PlanningSolution} annotation + */ +public class PartSolver extends AbstractSolver { + + protected final Termination termination; + protected final BestSolutionRecaller bestSolutionRecaller; + protected final List> phaseList; + + protected final DefaultSolverScope solverScope; + + // ************************************************************************ + // Constructors and simple getters/setters + // ************************************************************************ + + public PartSolver(Termination termination, BestSolutionRecaller bestSolutionRecaller, + List> phaseList, DefaultSolverScope solverScope) { + this.termination = termination; + this.bestSolutionRecaller = bestSolutionRecaller; + bestSolutionRecaller.setSolverEventSupport(solverEventSupport); + this.phaseList = phaseList; + for (Phase phase : phaseList) { + phase.setSolverPhaseLifecycleSupport(phaseLifecycleSupport); + } + this.solverScope = solverScope; + } + + @Override + public Solution_ solve(Solution_ part) { + solverScope.setBestSolution(part); + solverScope.setWorkingSolutionFromBestSolution(); + solvingStarted(solverScope); + for (Phase phase : phaseList) { + phase.solve(solverScope); + } + solvingEnded(solverScope); + solverScope.endingNow(); + solverScope.getScoreDirector().dispose(); + // TODO log? + return solverScope.getBestSolution(); + } + + public void solvingStarted(DefaultSolverScope solverScope) { + bestSolutionRecaller.solvingStarted(solverScope); + phaseLifecycleSupport.fireSolvingStarted(solverScope); + for (Phase phase : phaseList) { + phase.solvingStarted(solverScope); + } + } + + public void solvingEnded(DefaultSolverScope solverScope) { + for (Phase phase : phaseList) { + phase.solvingEnded(solverScope); + } + phaseLifecycleSupport.fireSolvingEnded(solverScope); + bestSolutionRecaller.solvingEnded(solverScope); + } + + + + // TODO remove these + + @Override + public Solution_ getBestSolution() { + throw new UnsupportedOperationException(); + } + + @Override + public Score getBestScore() { + throw new UnsupportedOperationException(); + } + + @Override + public long getTimeMillisSpent() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isSolving() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean terminateEarly() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isTerminateEarly() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addProblemFactChange(ProblemFactChange problemFactChange) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEveryProblemFactChangeProcessed() { + throw new UnsupportedOperationException(); + } + + @Override + public ScoreDirectorFactory getScoreDirectorFactory() { + throw new UnsupportedOperationException(); + } +} diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/AbstractScoreDirector.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/AbstractScoreDirector.java index 5d88402990..ebf7faeefb 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/AbstractScoreDirector.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/AbstractScoreDirector.java @@ -60,7 +60,7 @@ public abstract class AbstractScoreDirector variableListenerSupport; protected Solution_ workingSolution; @@ -93,6 +93,15 @@ public ScoreDefinition getScoreDefinition() { return scoreDirectorFactory.getScoreDefinition(); } + public boolean isConstraintMatchEnabledPreference() { + return constraintMatchEnabledPreference; + } + + @Override + public void overwriteConstraintMatchEnabledPreference(boolean constraintMatchEnabledPreference) { + this.constraintMatchEnabledPreference = constraintMatchEnabledPreference; + } + @Override public Solution_ getWorkingSolution() { return workingSolution; diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/InnerScoreDirector.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/InnerScoreDirector.java index 8adaca809f..6323d1bfb9 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/InnerScoreDirector.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/score/director/InnerScoreDirector.java @@ -20,6 +20,7 @@ import org.optaplanner.core.api.domain.solution.PlanningSolution; import org.optaplanner.core.api.score.Score; +import org.optaplanner.core.api.score.constraint.ConstraintMatch; import org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor; import org.optaplanner.core.impl.domain.variable.listener.VariableListener; import org.optaplanner.core.impl.domain.variable.supply.SupplyManager; @@ -31,6 +32,12 @@ */ public interface InnerScoreDirector extends ScoreDirector { + /** + * @param constraintMatchEnabledPreference false if a {@link ScoreDirector} implementation + * should not do {@link ConstraintMatch} tracking even if it supports it. + */ + void overwriteConstraintMatchEnabledPreference(boolean constraintMatchEnabledPreference); + /** * @return used to check {@link #isWorkingEntityListDirty(long)} later on */ diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/AbstractSolver.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/AbstractSolver.java new file mode 100644 index 0000000000..af28a6ffcd --- /dev/null +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/AbstractSolver.java @@ -0,0 +1,80 @@ +/* + * Copyright 2016 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.solver; + +import org.optaplanner.core.api.domain.solution.PlanningSolution; +import org.optaplanner.core.api.solver.Solver; +import org.optaplanner.core.api.solver.event.SolverEventListener; +import org.optaplanner.core.impl.phase.Phase; +import org.optaplanner.core.impl.phase.event.PhaseLifecycleListener; +import org.optaplanner.core.impl.phase.event.PhaseLifecycleSupport; +import org.optaplanner.core.impl.phase.scope.AbstractPhaseScope; +import org.optaplanner.core.impl.phase.scope.AbstractStepScope; +import org.optaplanner.core.impl.solver.event.SolverEventSupport; +import org.optaplanner.core.impl.solver.scope.DefaultSolverScope; + +/** + * @param the solution type, the class with the {@link PlanningSolution} annotation + * @see Solver + * @see DefaultSolver + */ +public abstract class AbstractSolver implements Solver { + + protected final SolverEventSupport solverEventSupport = new SolverEventSupport<>(this); + protected final PhaseLifecycleSupport phaseLifecycleSupport = new PhaseLifecycleSupport<>(); + + // ************************************************************************ + // Constructors and simple getters/setters + // ************************************************************************ + + + // ************************************************************************ + // Event listeners + // ************************************************************************ + + @Override + public void addEventListener(SolverEventListener eventListener) { + solverEventSupport.addEventListener(eventListener); + } + + @Override + public void removeEventListener(SolverEventListener eventListener) { + solverEventSupport.removeEventListener(eventListener); + } + + /** + * Add a {@link PhaseLifecycleListener} that is notified + * of {@link PhaseLifecycleListener#solvingStarted(DefaultSolverScope)} solving} events + * and also of the {@link PhaseLifecycleListener#phaseStarted(AbstractPhaseScope) phase} + * and the {@link PhaseLifecycleListener#stepStarted(AbstractStepScope)} step} starting/ending events of all phases. + *

+ * To get notified for only 1 phase, use {@link Phase#addPhaseLifecycleListener(PhaseLifecycleListener)} instead. + * @param phaseLifecycleListener never null + */ + public void addPhaseLifecycleListener(PhaseLifecycleListener phaseLifecycleListener) { + phaseLifecycleSupport.addEventListener(phaseLifecycleListener); + } + + /** + * @param phaseLifecycleListener never null + * @see #addPhaseLifecycleListener(PhaseLifecycleListener) + */ + public void removePhaseLifecycleListener(PhaseLifecycleListener phaseLifecycleListener) { + phaseLifecycleSupport.removeEventListener(phaseLifecycleListener); + } + +} diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/DefaultSolver.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/DefaultSolver.java index 3e8e6b22c0..48ed874e28 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/DefaultSolver.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/DefaultSolver.java @@ -45,89 +45,65 @@ * @param the solution type, the class with the {@link PlanningSolution} annotation * @see Solver */ -public class DefaultSolver implements Solver { +public class DefaultSolver extends AbstractSolver { protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - protected SolverEventSupport solverEventSupport = new SolverEventSupport<>(this); - protected PhaseLifecycleSupport phaseLifecycleSupport = new PhaseLifecycleSupport<>(); - protected EnvironmentMode environmentMode; protected RandomFactory randomFactory; - protected boolean constraintMatchEnabledPreference = false; - protected InnerScoreDirectorFactory scoreDirectorFactory; protected BasicPlumbingTermination basicPlumbingTermination; // Note that the basicPlumbingTermination is a component of this termination - protected Termination termination; - protected BestSolutionRecaller bestSolutionRecaller; - protected List phaseList; + protected final Termination termination; + protected final BestSolutionRecaller bestSolutionRecaller; + protected final List> phaseList; - protected AtomicBoolean solving = new AtomicBoolean(false); + protected final AtomicBoolean solving = new AtomicBoolean(false); - protected DefaultSolverScope solverScope = new DefaultSolverScope<>(); + protected final DefaultSolverScope solverScope; - public EnvironmentMode getEnvironmentMode() { - return environmentMode; - } + // ************************************************************************ + // Constructors and simple getters/setters + // ************************************************************************ - public void setEnvironmentMode(EnvironmentMode environmentMode) { + public DefaultSolver(EnvironmentMode environmentMode, RandomFactory randomFactory, + BasicPlumbingTermination basicPlumbingTermination, Termination termination, + BestSolutionRecaller bestSolutionRecaller, List> phaseList, + DefaultSolverScope solverScope) { this.environmentMode = environmentMode; - } - - public RandomFactory getRandomFactory() { - return randomFactory; - } - - public void setRandomFactory(RandomFactory randomFactory) { this.randomFactory = randomFactory; + this.basicPlumbingTermination = basicPlumbingTermination; + this.termination = termination; + this.bestSolutionRecaller = bestSolutionRecaller; + bestSolutionRecaller.setSolverEventSupport(solverEventSupport); + this.phaseList = phaseList; + for (Phase phase : phaseList) { + phase.setSolverPhaseLifecycleSupport(phaseLifecycleSupport); + } + this.solverScope = solverScope; } - public boolean isConstraintMatchEnabledPreference() { - return constraintMatchEnabledPreference; + public EnvironmentMode getEnvironmentMode() { + return environmentMode; } - public void setConstraintMatchEnabledPreference(boolean constraintMatchEnabledPreference) { - this.constraintMatchEnabledPreference = constraintMatchEnabledPreference; + public RandomFactory getRandomFactory() { + return randomFactory; } @Override public InnerScoreDirectorFactory getScoreDirectorFactory() { - return scoreDirectorFactory; - } - - public void setScoreDirectorFactory(InnerScoreDirectorFactory scoreDirectorFactory) { - this.scoreDirectorFactory = scoreDirectorFactory; - } - - public void setBasicPlumbingTermination(BasicPlumbingTermination basicPlumbingTermination) { - this.basicPlumbingTermination = basicPlumbingTermination; - } - - public void setTermination(Termination termination) { - this.termination = termination; + return solverScope.getScoreDirector().getScoreDirectorFactory(); } public BestSolutionRecaller getBestSolutionRecaller() { return bestSolutionRecaller; } - public void setBestSolutionRecaller(BestSolutionRecaller bestSolutionRecaller) { - this.bestSolutionRecaller = bestSolutionRecaller; - this.bestSolutionRecaller.setSolverEventSupport(solverEventSupport); - } - - public List getPhaseList() { + public List> getPhaseList() { return phaseList; } - public void setPhaseList(List phaseList) { - this.phaseList = phaseList; - for (Phase phase : phaseList) { - phase.setSolverPhaseLifecycleSupport(phaseLifecycleSupport); - } - } - public DefaultSolverScope getSolverScope() { return solverScope; } @@ -208,7 +184,6 @@ public void outerSolvingStarted(DefaultSolverScope solverScope) { basicPlumbingTermination.resetTerminateEarly(); solverScope.setStartingSolverCount(0); solverScope.setWorkingRandom(randomFactory.createRandom()); - solverScope.setScoreDirector(scoreDirectorFactory.buildScoreDirector(constraintMatchEnabledPreference)); } public void solvingStarted(DefaultSolverScope solverScope) { @@ -231,7 +206,7 @@ public void solvingStarted(DefaultSolverScope solverScope) { } protected void runPhases() { - Iterator it = phaseList.iterator(); + Iterator> it = phaseList.iterator(); while (!termination.isSolverTerminated(solverScope) && it.hasNext()) { Phase phase = it.next(); phase.solve(solverScope); @@ -296,35 +271,4 @@ private Score doProblemFactChange(ProblemFactChange problemFactChange return score; } - @Override - public void addEventListener(SolverEventListener eventListener) { - solverEventSupport.addEventListener(eventListener); - } - - @Override - public void removeEventListener(SolverEventListener eventListener) { - solverEventSupport.removeEventListener(eventListener); - } - - /** - * Add a {@link PhaseLifecycleListener} that is notified - * of {@link PhaseLifecycleListener#solvingStarted(DefaultSolverScope)} solving} events - * and also of the {@link PhaseLifecycleListener#phaseStarted(AbstractPhaseScope) phase} - * and the {@link PhaseLifecycleListener#stepStarted(AbstractStepScope)} step} starting/ending events of all phases. - *

- * To get notified for only 1 phase, use {@link Phase#addPhaseLifecycleListener(PhaseLifecycleListener)} instead. - * @param phaseLifecycleListener never null - */ - public void addPhaseLifecycleListener(PhaseLifecycleListener phaseLifecycleListener) { - phaseLifecycleSupport.addEventListener(phaseLifecycleListener); - } - - /** - * @param phaseLifecycleListener never null - * @see #addPhaseLifecycleListener(PhaseLifecycleListener) - */ - public void removePhaseLifecycleListener(PhaseLifecycleListener phaseLifecycleListener) { - phaseLifecycleSupport.removeEventListener(phaseLifecycleListener); - } - } diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/event/SolverEventSupport.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/event/SolverEventSupport.java index ced47f9c1c..5e27de5840 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/event/SolverEventSupport.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/solver/event/SolverEventSupport.java @@ -34,7 +34,7 @@ public class SolverEventSupport extends AbstractEventSupport solver; - public SolverEventSupport(DefaultSolver solver) { + public SolverEventSupport(Solver solver) { this.solver = solver; }