Skip to content

Commit

Permalink
chore: code review
Browse files Browse the repository at this point in the history
  • Loading branch information
triceo committed Aug 26, 2024
1 parent 652915f commit 644a474
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ protected DefaultConstructionHeuristicPhase(DefaultConstructionHeuristicPhaseBui
entityPlacer = builder.getEntityPlacer();
}

protected boolean isNested() {
return false;
}

public EntityPlacer<Solution_> getEntityPlacer() {
return entityPlacer;
}
Expand Down Expand Up @@ -102,9 +98,11 @@ private void doStep(ConstructionHeuristicStepScope<Solution_> stepScope) {
var step = stepScope.getStep();
step.doMoveOnly(stepScope.getScoreDirector());
predictWorkingStepScore(stepScope, step);
if (!isNested()) {
solver.getBestSolutionRecaller().processWorkingSolutionDuringConstructionHeuristicsStep(stepScope);
}
processWorkingSolutionDuringStep(stepScope);
}

protected void processWorkingSolutionDuringStep(ConstructionHeuristicStepScope<Solution_> stepScope) {
solver.getBestSolutionRecaller().processWorkingSolutionDuringConstructionHeuristicsStep(stepScope);
}

@Override
Expand Down Expand Up @@ -143,10 +141,7 @@ public void stepEnded(ConstructionHeuristicStepScope<Solution_> stepScope) {

public void phaseEnded(ConstructionHeuristicPhaseScope<Solution_> phaseScope) {
super.phaseEnded(phaseScope);
// Only update the best solution if it is not a ruin+recreate CH and the CH made any change.
if (!isNested() && !phaseScope.getStartingScore().equals(phaseScope.getBestScore())) {
solver.getBestSolutionRecaller().updateBestSolutionAndFire(phaseScope.getSolverScope());
}
updateBestSolutionAndFire(phaseScope);
entityPlacer.phaseEnded(phaseScope);
decider.phaseEnded(phaseScope);
phaseScope.endingNow();
Expand All @@ -162,6 +157,13 @@ public void phaseEnded(ConstructionHeuristicPhaseScope<Solution_> phaseScope) {
}
}

protected void updateBestSolutionAndFire(ConstructionHeuristicPhaseScope<Solution_> phaseScope) {
// Only update the best solution if the CH made any change.
if (!phaseScope.getStartingScore().equals(phaseScope.getBestScore())) {
solver.getBestSolutionRecaller().updateBestSolutionAndFire(phaseScope.getSolverScope());
}
}

@Override
public void solvingEnded(SolverScope<Solution_> solverScope) {
super.solvingEnded(solverScope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,23 @@
import ai.timefold.solver.core.config.heuristic.selector.move.composite.UnionMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.value.ValueSelectorConfig;
import ai.timefold.solver.core.config.solver.termination.TerminationConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.enterprise.TimefoldSolverEnterpriseService;
import ai.timefold.solver.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase.DefaultConstructionHeuristicPhaseBuilder;
import ai.timefold.solver.core.impl.constructionheuristic.decider.ConstructionHeuristicDecider;
import ai.timefold.solver.core.impl.constructionheuristic.decider.forager.ConstructionHeuristicForager;
import ai.timefold.solver.core.impl.constructionheuristic.decider.forager.ConstructionHeuristicForagerFactory;
import ai.timefold.solver.core.impl.constructionheuristic.placer.EntityPlacer;
import ai.timefold.solver.core.impl.constructionheuristic.placer.EntityPlacerFactory;
import ai.timefold.solver.core.impl.constructionheuristic.placer.PooledEntityPlacerFactory;
import ai.timefold.solver.core.impl.constructionheuristic.placer.QueuedEntityPlacerFactory;
import ai.timefold.solver.core.impl.constructionheuristic.placer.QueuedValuePlacerFactory;
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;
import ai.timefold.solver.core.impl.domain.variable.descriptor.ListVariableDescriptor;
import ai.timefold.solver.core.impl.heuristic.HeuristicConfigPolicy;
import ai.timefold.solver.core.impl.heuristic.selector.move.generic.RuinRecreateConstructionHeuristicDecider;
import ai.timefold.solver.core.impl.heuristic.selector.move.generic.RuinRecreateConstructionHeuristicPhase.RuinRecreateConstructionHeuristicPhaseBuilder;
import ai.timefold.solver.core.impl.phase.AbstractPhaseFactory;
import ai.timefold.solver.core.impl.solver.recaller.BestSolutionRecaller;
import ai.timefold.solver.core.impl.solver.termination.BasicPlumbingTermination;
import ai.timefold.solver.core.impl.solver.termination.PhaseToSolverTerminationBridge;
import ai.timefold.solver.core.impl.solver.termination.Termination;
import ai.timefold.solver.core.impl.solver.termination.TerminationFactory;

public class DefaultConstructionHeuristicPhaseFactory<Solution_>
extends AbstractPhaseFactory<Solution_, ConstructionHeuristicPhaseConfig> {
Expand All @@ -47,9 +42,9 @@ public DefaultConstructionHeuristicPhaseFactory(ConstructionHeuristicPhaseConfig
super(phaseConfig);
}

protected DefaultConstructionHeuristicPhaseBuilder<Solution_> getBaseBuilder(int phaseIndex,
public final DefaultConstructionHeuristicPhaseBuilder<Solution_> getBuilder(int phaseIndex,
boolean triggerFirstInitializedSolutionEvent, HeuristicConfigPolicy<Solution_> solverConfigPolicy,
Termination<Solution_> solverTermination, boolean isNested) {
Termination<Solution_> solverTermination) {
var constructionHeuristicType_ = Objects.requireNonNullElse(phaseConfig.getConstructionHeuristicType(),
ConstructionHeuristicType.ALLOCATE_ENTITY_FROM_QUEUE);
var entitySorterManner = Objects.requireNonNullElse(phaseConfig.getEntitySorterManner(),
Expand All @@ -67,15 +62,16 @@ protected DefaultConstructionHeuristicPhaseBuilder<Solution_> getBaseBuilder(int
.orElseGet(() -> buildDefaultEntityPlacerConfig(phaseConfigPolicy, constructionHeuristicType_));
var entityPlacer = EntityPlacerFactory.<Solution_> create(entityPlacerConfig_)
.buildEntityPlacer(phaseConfigPolicy);
return createBuilder(phaseConfigPolicy, solverTermination, phaseIndex, triggerFirstInitializedSolutionEvent,
entityPlacer);
}

if (isNested) { // Nested phases ignore terminations and always finish, as they are nested inside a move.
var phaseTermination = new PhaseToSolverTerminationBridge<>(new BasicPlumbingTermination<Solution_>(false));
return new RuinRecreateConstructionHeuristicPhaseBuilder<>(phaseTermination, entityPlacer,
buildRuinRecreateDecider(phaseConfigPolicy, phaseTermination));
}
protected DefaultConstructionHeuristicPhaseBuilder<Solution_> createBuilder(
HeuristicConfigPolicy<Solution_> phaseConfigPolicy, Termination<Solution_> solverTermination, int phaseIndex,
boolean triggerFirstInitializedSolutionEvent, EntityPlacer<Solution_> entityPlacer) {
var phaseTermination = buildPhaseTermination(phaseConfigPolicy, solverTermination);
var builder = new DefaultConstructionHeuristicPhaseBuilder<>(phaseIndex, triggerFirstInitializedSolutionEvent,
solverConfigPolicy.getLogIndentation(), phaseTermination, entityPlacer,
phaseConfigPolicy.getLogIndentation(), phaseTermination, entityPlacer,
buildDecider(phaseConfigPolicy, phaseTermination));
var environmentMode = phaseConfigPolicy.getEnvironmentMode();
if (environmentMode.isNonIntrusiveFullAsserted()) {
Expand All @@ -92,18 +88,10 @@ protected DefaultConstructionHeuristicPhaseBuilder<Solution_> getBaseBuilder(int
public ConstructionHeuristicPhase<Solution_> buildPhase(int phaseIndex, boolean triggerFirstInitializedSolutionEvent,
HeuristicConfigPolicy<Solution_> solverConfigPolicy, BestSolutionRecaller<Solution_> bestSolutionRecaller,
Termination<Solution_> solverTermination) {
return getBaseBuilder(phaseIndex, triggerFirstInitializedSolutionEvent, solverConfigPolicy, solverTermination, false)
return getBuilder(phaseIndex, triggerFirstInitializedSolutionEvent, solverConfigPolicy, solverTermination)
.build();
}

public RuinRecreateConstructionHeuristicPhaseBuilder<Solution_>
getRuinPhaseBuilder(HeuristicConfigPolicy<Solution_> solverConfigPolicy) {
var solverTermination = TerminationFactory.<Solution_> create(new TerminationConfig())
.buildTermination(solverConfigPolicy);
return (RuinRecreateConstructionHeuristicPhaseBuilder<Solution_>) getBaseBuilder(0, false, solverConfigPolicy,
solverTermination, true);
}

private Optional<EntityPlacerConfig<?>> getValidEntityPlacerConfig() {
EntityPlacerConfig<?> entityPlacerConfig = phaseConfig.getEntityPlacerConfig();
if (entityPlacerConfig == null) {
Expand Down Expand Up @@ -177,7 +165,7 @@ public static EntityPlacerConfig buildListVariableQueuedValuePlacerConfig(Heuris
.withMoveSelectorConfig(listChangeMoveSelectorConfig);
}

private ConstructionHeuristicDecider<Solution_> buildDecider(HeuristicConfigPolicy<Solution_> configPolicy,
protected ConstructionHeuristicDecider<Solution_> buildDecider(HeuristicConfigPolicy<Solution_> configPolicy,
Termination<Solution_> termination) {
var forager = buildForager(configPolicy);
var moveThreadCount = configPolicy.getMoveThreadCount();
Expand All @@ -189,17 +177,12 @@ private ConstructionHeuristicDecider<Solution_> buildDecider(HeuristicConfigPoli
return decider;
}

private ConstructionHeuristicForager<Solution_> buildForager(HeuristicConfigPolicy<Solution_> configPolicy) {
protected ConstructionHeuristicForager<Solution_> buildForager(HeuristicConfigPolicy<Solution_> configPolicy) {
var foragerConfig_ =
Objects.requireNonNullElseGet(phaseConfig.getForagerConfig(), ConstructionHeuristicForagerConfig::new);
return ConstructionHeuristicForagerFactory.<Solution_> create(foragerConfig_).buildForager(configPolicy);
}

private ConstructionHeuristicDecider<Solution_> buildRuinRecreateDecider(HeuristicConfigPolicy<Solution_> configPolicy,
Termination<Solution_> termination) {
return new RuinRecreateConstructionHeuristicDecider<>(termination, buildForager(configPolicy));
}

private EntityPlacerConfig<?> buildUnfoldedEntityPlacerConfig(HeuristicConfigPolicy<Solution_> phaseConfigPolicy,
ConstructionHeuristicType constructionHeuristicType) {
return switch (constructionHeuristicType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import ai.timefold.solver.core.impl.constructionheuristic.decider.forager.ConstructionHeuristicForager;
import ai.timefold.solver.core.impl.solver.termination.Termination;

public final class RuinRecreateConstructionHeuristicDecider<Solution_>
final class RuinRecreateConstructionHeuristicDecider<Solution_>
extends ConstructionHeuristicDecider<Solution_> {

public RuinRecreateConstructionHeuristicDecider(Termination<Solution_> termination,
RuinRecreateConstructionHeuristicDecider(Termination<Solution_> termination,
ConstructionHeuristicForager<Solution_> forager) {
super("", termination, forager);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,31 @@
package ai.timefold.solver.core.impl.heuristic.selector.move.generic;

import java.util.List;

import ai.timefold.solver.core.impl.constructionheuristic.ConstructionHeuristicPhase;
import ai.timefold.solver.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase;
import ai.timefold.solver.core.impl.constructionheuristic.decider.ConstructionHeuristicDecider;
import ai.timefold.solver.core.impl.constructionheuristic.placer.EntityPlacer;
import ai.timefold.solver.core.impl.solver.termination.Termination;
import ai.timefold.solver.core.impl.constructionheuristic.scope.ConstructionHeuristicPhaseScope;
import ai.timefold.solver.core.impl.constructionheuristic.scope.ConstructionHeuristicStepScope;

public final class RuinRecreateConstructionHeuristicPhase<Solution_>
final class RuinRecreateConstructionHeuristicPhase<Solution_>
extends DefaultConstructionHeuristicPhase<Solution_>
implements ConstructionHeuristicPhase<Solution_> {

public RuinRecreateConstructionHeuristicPhase(RuinRecreateConstructionHeuristicPhaseBuilder<Solution_> builder) {
RuinRecreateConstructionHeuristicPhase(RuinRecreateConstructionHeuristicPhaseBuilder<Solution_> builder) {
super(builder);
}

@Override
protected boolean isNested() {
return true;
protected void processWorkingSolutionDuringStep(ConstructionHeuristicStepScope<Solution_> stepScope) {
// Ruin and Recreate CH doesn't process the working solution, it is a nested phase.
}

public static final class RuinRecreateConstructionHeuristicPhaseBuilder<Solution_>
extends DefaultConstructionHeuristicPhaseBuilder<Solution_> {

private List<Object> elementsToRecreate;

public RuinRecreateConstructionHeuristicPhaseBuilder(Termination<Solution_> phaseTermination,
EntityPlacer<Solution_> entityPlacer, ConstructionHeuristicDecider<Solution_> decider) {
super(0, false, "", phaseTermination, entityPlacer, decider);
}

public RuinRecreateConstructionHeuristicPhaseBuilder<Solution_> withElementsToRecreate(List<Object> elements) {
this.elementsToRecreate = elements;
return this;
}

@Override
public EntityPlacer<Solution_> getEntityPlacer() {
if (elementsToRecreate == null || elementsToRecreate.isEmpty()) {
return super.getEntityPlacer();
}
return super.getEntityPlacer().rebuildWithFilter((scoreDirector, selection) -> {
for (var element : elementsToRecreate) {
if (selection == element) {
return true;
}
}
return false;
});
}
@Override
protected void updateBestSolutionAndFire(ConstructionHeuristicPhaseScope<Solution_> phaseScope) {
// Ruin and Recreate CH doesn't update the best solution, it is a nested phase.
}

@Override
public RuinRecreateConstructionHeuristicPhase<Solution_> build() {
return new RuinRecreateConstructionHeuristicPhase<>(this);
}
@Override
public String getPhaseTypeString() {
return "Ruin & Recreate Construction Heuristics";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package ai.timefold.solver.core.impl.heuristic.selector.move.generic;

import java.util.List;

import ai.timefold.solver.core.config.constructionheuristic.ConstructionHeuristicPhaseConfig;
import ai.timefold.solver.core.config.solver.termination.TerminationConfig;
import ai.timefold.solver.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase;
import ai.timefold.solver.core.impl.constructionheuristic.decider.ConstructionHeuristicDecider;
import ai.timefold.solver.core.impl.constructionheuristic.placer.EntityPlacer;
import ai.timefold.solver.core.impl.heuristic.HeuristicConfigPolicy;
import ai.timefold.solver.core.impl.solver.termination.Termination;
import ai.timefold.solver.core.impl.solver.termination.TerminationFactory;

public final class RuinRecreateConstructionHeuristicPhaseBuilder<Solution_>
extends DefaultConstructionHeuristicPhase.DefaultConstructionHeuristicPhaseBuilder<Solution_> {

public static <Solution_> RuinRecreateConstructionHeuristicPhaseBuilder<Solution_>
create(HeuristicConfigPolicy<Solution_> solverConfigPolicy) {
var constructionHeuristicConfig = new ConstructionHeuristicPhaseConfig();
return create(solverConfigPolicy, constructionHeuristicConfig);
}

public static <Solution_> RuinRecreateConstructionHeuristicPhaseBuilder<Solution_> create(
HeuristicConfigPolicy<Solution_> solverConfigPolicy, ConstructionHeuristicPhaseConfig constructionHeuristicConfig) {
var constructionHeuristicPhaseFactory =
new RuinRecreateConstructionHeuristicPhaseFactory<Solution_>(constructionHeuristicConfig);
return (RuinRecreateConstructionHeuristicPhaseBuilder<Solution_>) constructionHeuristicPhaseFactory.getBuilder(0, false,
solverConfigPolicy, TerminationFactory.<Solution_> create(new TerminationConfig())
.buildTermination(solverConfigPolicy));
}

private List<Object> elementsToRecreate;

RuinRecreateConstructionHeuristicPhaseBuilder(Termination<Solution_> phaseTermination,
EntityPlacer<Solution_> entityPlacer, ConstructionHeuristicDecider<Solution_> decider) {
super(0, false, "", phaseTermination, entityPlacer, decider);
}

public RuinRecreateConstructionHeuristicPhaseBuilder<Solution_> withElementsToRecreate(List<Object> elements) {
this.elementsToRecreate = elements;
return this;
}

@Override
public EntityPlacer<Solution_> getEntityPlacer() {
if (elementsToRecreate == null || elementsToRecreate.isEmpty()) {
return super.getEntityPlacer();
}
return super.getEntityPlacer().rebuildWithFilter((scoreDirector, selection) -> {
for (var element : elementsToRecreate) {
if (selection == element) {
return true;
}
}
return false;
});
}

@Override
public DefaultConstructionHeuristicPhase<Solution_> build() {
return new RuinRecreateConstructionHeuristicPhase<>(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ai.timefold.solver.core.impl.heuristic.selector.move.generic;

import ai.timefold.solver.core.config.constructionheuristic.ConstructionHeuristicPhaseConfig;
import ai.timefold.solver.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase.DefaultConstructionHeuristicPhaseBuilder;
import ai.timefold.solver.core.impl.constructionheuristic.DefaultConstructionHeuristicPhaseFactory;
import ai.timefold.solver.core.impl.constructionheuristic.decider.ConstructionHeuristicDecider;
import ai.timefold.solver.core.impl.constructionheuristic.placer.EntityPlacer;
import ai.timefold.solver.core.impl.heuristic.HeuristicConfigPolicy;
import ai.timefold.solver.core.impl.solver.termination.BasicPlumbingTermination;
import ai.timefold.solver.core.impl.solver.termination.PhaseToSolverTerminationBridge;
import ai.timefold.solver.core.impl.solver.termination.Termination;

final class RuinRecreateConstructionHeuristicPhaseFactory<Solution_>
extends DefaultConstructionHeuristicPhaseFactory<Solution_> {

RuinRecreateConstructionHeuristicPhaseFactory(ConstructionHeuristicPhaseConfig phaseConfig) {
super(phaseConfig);
}

@Override
protected DefaultConstructionHeuristicPhaseBuilder<Solution_> createBuilder(
HeuristicConfigPolicy<Solution_> phaseConfigPolicy,
Termination<Solution_> solverTermination, int phaseIndex, boolean triggerFirstInitializedSolutionEvent,
EntityPlacer<Solution_> entityPlacer) {
var phaseTermination = new PhaseToSolverTerminationBridge<>(new BasicPlumbingTermination<Solution_>(false));
return new RuinRecreateConstructionHeuristicPhaseBuilder<>(phaseTermination, entityPlacer,
buildDecider(phaseConfigPolicy, phaseTermination));

}

@Override
protected ConstructionHeuristicDecider<Solution_> buildDecider(HeuristicConfigPolicy<Solution_> configPolicy,
Termination<Solution_> termination) {
return new RuinRecreateConstructionHeuristicDecider<>(termination, buildForager(configPolicy));
}

}
Loading

0 comments on commit 644a474

Please sign in to comment.