Skip to content

Commit

Permalink
Split up PhaseLifecycleSupport of DefaultSolver and AbstractPhase + j…
Browse files Browse the repository at this point in the history
…avadoc difference clearly (thanks to JiriL's PR to bring this design flaw into the light)
  • Loading branch information
ge0ffrey committed Jun 6, 2016
1 parent 7de5cf9 commit 0bc85a8
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 17 deletions.
Expand Up @@ -28,6 +28,7 @@
import org.optaplanner.core.impl.phase.scope.AbstractPhaseScope;
import org.optaplanner.core.impl.phase.scope.AbstractStepScope;
import org.optaplanner.core.impl.score.director.InnerScoreDirector;
import org.optaplanner.core.impl.solver.DefaultSolver;
import org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller;
import org.optaplanner.core.impl.solver.scope.DefaultSolverScope;
import org.optaplanner.core.impl.solver.termination.Termination;
Expand All @@ -47,12 +48,15 @@ public abstract class AbstractPhase<Solution_> implements Phase<Solution_> {
protected Termination termination;
protected BestSolutionRecaller<Solution_> bestSolutionRecaller;

/** Used for {@link DefaultSolver#addPhaseLifecycleListener(PhaseLifecycleListener)}. */
protected PhaseLifecycleSupport<Solution_> solverPhaseLifecycleSupport;
/** Used for {@link #addPhaseLifecycleListener(PhaseLifecycleListener)}. */
protected PhaseLifecycleSupport<Solution_> phaseLifecycleSupport = new PhaseLifecycleSupport<>();

protected boolean assertStepScoreFromScratch = false;
protected boolean assertExpectedStepScore = false;
protected boolean assertShadowVariablesAreNotStaleAfterStep = false;

protected PhaseLifecycleSupport<Solution_> phaseLifecycleSupport = new PhaseLifecycleSupport<>();

public Termination getTermination() {
return termination;
}
Expand All @@ -73,6 +77,11 @@ public void setBestSolutionRecaller(BestSolutionRecaller<Solution_> bestSolution
this.bestSolutionRecaller = bestSolutionRecaller;
}

@Override
public void setSolverPhaseLifecycleSupport(PhaseLifecycleSupport<Solution_> solverPhaseLifecycleSupport) {
this.solverPhaseLifecycleSupport = solverPhaseLifecycleSupport;
}

public boolean isAssertStepScoreFromScratch() {
return assertStepScoreFromScratch;
}
Expand Down Expand Up @@ -106,27 +115,33 @@ public void setAssertShadowVariablesAreNotStaleAfterStep(boolean assertShadowVar
@Override
public void solvingStarted(DefaultSolverScope<Solution_> solverScope) {
// bestSolutionRecaller.solvingStarted(...) is called by DefaultSolver
// solverPhaseLifecycleSupport.solvingStarted(...) is called by DefaultSolver
termination.solvingStarted(solverScope);
phaseLifecycleSupport.fireSolvingStarted(solverScope);
}

@Override
public void solvingEnded(DefaultSolverScope<Solution_> solverScope) {
// bestSolutionRecaller.solvingEnded(...) is called by DefaultSolver
// solverPhaseLifecycleSupport.solvingEnded(...) is called by DefaultSolver
termination.solvingEnded(solverScope);
phaseLifecycleSupport.fireSolvingEnded(solverScope);
}

@Override
public void phaseStarted(AbstractPhaseScope<Solution_> phaseScope) {
phaseScope.startingNow();
phaseScope.reset();
bestSolutionRecaller.phaseStarted(phaseScope);
solverPhaseLifecycleSupport.firePhaseStarted(phaseScope);
termination.phaseStarted(phaseScope);
phaseLifecycleSupport.firePhaseStarted(phaseScope);
}

@Override
public void stepStarted(AbstractStepScope<Solution_> stepScope) {
bestSolutionRecaller.stepStarted(stepScope);
solverPhaseLifecycleSupport.fireStepStarted(stepScope);
termination.stepStarted(stepScope);
phaseLifecycleSupport.fireStepStarted(stepScope);
}
Expand All @@ -149,13 +164,15 @@ protected void predictWorkingStepScore(AbstractStepScope<Solution_> stepScope, O
@Override
public void stepEnded(AbstractStepScope<Solution_> stepScope) {
bestSolutionRecaller.stepEnded(stepScope);
solverPhaseLifecycleSupport.fireStepEnded(stepScope);
termination.stepEnded(stepScope);
phaseLifecycleSupport.fireStepEnded(stepScope);
}

@Override
public void phaseEnded(AbstractPhaseScope<Solution_> phaseScope) {
bestSolutionRecaller.phaseEnded(phaseScope);
solverPhaseLifecycleSupport.firePhaseEnded(phaseScope);
termination.phaseEnded(phaseScope);
phaseLifecycleSupport.firePhaseEnded(phaseScope);
}
Expand Down
Expand Up @@ -18,7 +18,12 @@

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.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.DefaultSolver;
import org.optaplanner.core.impl.solver.scope.DefaultSolverScope;

/**
Expand All @@ -28,10 +33,29 @@
*/
public interface Phase<Solution_> extends PhaseLifecycleListener<Solution_> {

void solve(DefaultSolverScope<Solution_> solverScope);
/**
* Used to make {@link DefaultSolver#addPhaseLifecycleListener(PhaseLifecycleListener)} work.
* @param solverPhaseLifecycleSupport never null
*/
void setSolverPhaseLifecycleSupport(PhaseLifecycleSupport<Solution_> solverPhaseLifecycleSupport);

/**
* Add a {@link PhaseLifecycleListener} that is only notified
* of the {@link PhaseLifecycleListener#phaseStarted(AbstractPhaseScope) phase}
* and the {@link PhaseLifecycleListener#stepStarted(AbstractStepScope)} step} starting/ending events from this phase
* (and the {@link PhaseLifecycleListener#solvingStarted(DefaultSolverScope)} solving} events too of course).
* <p>
* To get notified for all phases, use {@link DefaultSolver#addPhaseLifecycleListener(PhaseLifecycleListener)} instead.
* @param phaseLifecycleListener never null
*/
void addPhaseLifecycleListener(PhaseLifecycleListener<Solution_> phaseLifecycleListener);

/**
* @param phaseLifecycleListener never null
* @see #addPhaseLifecycleListener(PhaseLifecycleListener)
*/
void removePhaseLifecycleListener(PhaseLifecycleListener<Solution_> phaseLifecycleListener);

void solve(DefaultSolverScope<Solution_> solverScope);

}
Expand Up @@ -29,6 +29,8 @@
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.score.director.InnerScoreDirectorFactory;
import org.optaplanner.core.impl.solver.event.SolverEventSupport;
import org.optaplanner.core.impl.solver.random.RandomFactory;
Expand Down Expand Up @@ -121,6 +123,9 @@ public List<Phase> getPhaseList() {

public void setPhaseList(List<Phase> phaseList) {
this.phaseList = phaseList;
for (Phase<Solution_> phase : phaseList) {
phase.setSolverPhaseLifecycleSupport(phaseLifecycleSupport);
}
}

public DefaultSolverScope<Solution_> getSolverScope() {
Expand Down Expand Up @@ -211,12 +216,12 @@ public void solvingStarted(DefaultSolverScope<Solution_> solverScope) {
solverScope.getScoreDirector().resetCalculationCount();
solverScope.setWorkingSolutionFromBestSolution();
bestSolutionRecaller.solvingStarted(solverScope);
for (Phase phase : phaseList) {
phaseLifecycleSupport.fireSolvingStarted(solverScope);
for (Phase<Solution_> phase : phaseList) {
phase.solvingStarted(solverScope);
}
int startingSolverCount = solverScope.getStartingSolverCount() + 1;
solverScope.setStartingSolverCount(startingSolverCount);
phaseLifecycleSupport.fireSolvingStarted(solverScope);
logger.info("Solving {}: time spent ({}), best score ({}), environment mode ({}), random ({}).",
(startingSolverCount == 1 ? "started" : "restarted"),
solverScope.calculateTimeMillisSpentUpToNow(),
Expand All @@ -228,7 +233,7 @@ public void solvingStarted(DefaultSolverScope<Solution_> solverScope) {
protected void runPhases() {
Iterator<Phase> it = phaseList.iterator();
while (!termination.isSolverTerminated(solverScope) && it.hasNext()) {
Phase phase = it.next();
Phase<Solution_> phase = it.next();
phase.solve(solverScope);
if (it.hasNext()) {
solverScope.setWorkingSolutionFromBestSolution();
Expand All @@ -238,12 +243,12 @@ protected void runPhases() {
}

public void solvingEnded(DefaultSolverScope<Solution_> solverScope) {
for (Phase phase : phaseList) {
for (Phase<Solution_> phase : phaseList) {
phase.solvingEnded(solverScope);
}
phaseLifecycleSupport.fireSolvingEnded(solverScope);
bestSolutionRecaller.solvingEnded(solverScope);
solverScope.endingNow();
phaseLifecycleSupport.fireSolvingEnded(solverScope);
}

public void outerSolvingEnded(DefaultSolverScope<Solution_> solverScope) {
Expand Down Expand Up @@ -300,18 +305,25 @@ public void removeEventListener(SolverEventListener<Solution_> 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.
* <p>
* To get notified for only 1 phase, use {@link Phase#addPhaseLifecycleListener(PhaseLifecycleListener)} instead.
* @param phaseLifecycleListener never null
*/
public void addPhaseLifecycleListener(PhaseLifecycleListener<Solution_> phaseLifecycleListener) {
phaseLifecycleSupport.addEventListener(phaseLifecycleListener);
for (Phase phase : phaseList) {
phase.addPhaseLifecycleListener(phaseLifecycleListener);
}
}

/**
* @param phaseLifecycleListener never null
* @see #addPhaseLifecycleListener(PhaseLifecycleListener)
*/
public void removePhaseLifecycleListener(PhaseLifecycleListener<Solution_> phaseLifecycleListener) {
phaseLifecycleSupport.removeEventListener(phaseLifecycleListener);
for (Phase phase : phaseList) {
phase.removePhaseLifecycleListener(phaseLifecycleListener);
}
}

}
Expand Up @@ -63,16 +63,15 @@ public void verifyEventCounts() {
// step count = number of uninitialized entities (CH) + LS step count limit
final int stepCount = entitiesCount + PlannerTestUtils.TERMINATION_STEP_COUNT_LIMIT;
final int phaseCount = solverFactory.getSolverConfig().getPhaseConfigList().size();
final int solvingCount = 1;
PlannerAssert.verifyPhaseLifecycle(listener, solvingCount, phaseCount, stepCount);
PlannerAssert.verifyPhaseLifecycle(listener, 1, phaseCount, stepCount);

// forget previous invocations
Mockito.<PhaseLifecycleListener<?>>reset(listener);

// uninitialize 1 entity and solve again
solvedSolution.getEntityList().get(0).setValue(null);
solver.solve(solvedSolution);
PlannerAssert.verifyPhaseLifecycle(listener, solvingCount, phaseCount, 1 + PlannerTestUtils.TERMINATION_STEP_COUNT_LIMIT);
PlannerAssert.verifyPhaseLifecycle(listener, 1, phaseCount, 1 + PlannerTestUtils.TERMINATION_STEP_COUNT_LIMIT);

// forget previous invocations
Mockito.<PhaseLifecycleListener<?>>reset(listener);
Expand All @@ -82,4 +81,5 @@ public void verifyEventCounts() {
solver.solve(solution);
PlannerAssert.verifyPhaseLifecycle(listener, 0, 0, 0);
}

}

0 comments on commit 0bc85a8

Please sign in to comment.