-
Notifications
You must be signed in to change notification settings - Fork 178
refactor: ScoreDirector is no longer public #2129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
triceo
wants to merge
3
commits into
TimefoldAI:main
Choose a base branch
from
triceo:scoredirector
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
43 changes: 43 additions & 0 deletions
43
core/src/main/java/ai/timefold/solver/core/api/domain/common/Lookup.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package ai.timefold.solver.core.api.domain.common; | ||
|
|
||
| import ai.timefold.solver.core.api.solver.change.ProblemChange; | ||
|
|
||
| import org.jspecify.annotations.Nullable; | ||
|
|
||
| /** | ||
| * Allows to transfer an entity or fact instance (often from another {@link Thread}) | ||
| * to another working solution. | ||
| */ | ||
| public interface Lookup { | ||
|
|
||
| /** | ||
| * Translates an entity or fact instance (often from another {@link Thread}) | ||
| * to another working solution. | ||
| * Useful for move rebasing and in a {@link ProblemChange} and for multi-threaded solving. | ||
| * <p> | ||
| * Matching uses {@link PlanningId}. | ||
| * | ||
| * @param problemFactOrPlanningEntity The fact or entity to rebase. | ||
| * @return null if problemFactOrPlanningEntity is null | ||
| * @throws IllegalArgumentException if there is no working object for the fact or entity, | ||
| * if it cannot be looked up, | ||
| * or if its class is not supported. | ||
| * @throws IllegalStateException if it cannot be looked up | ||
| * @param <T> the object type | ||
| */ | ||
| <T> @Nullable T lookUpWorkingObjectOrFail(@Nullable T problemFactOrPlanningEntity); | ||
|
|
||
| /** | ||
| * As defined by {@link #lookUpWorkingObjectOrFail(Object)}, | ||
| * but doesn't fail fast if no workingObject was ever added for the externalObject. | ||
| * It's recommended to use {@link #lookUpWorkingObjectOrFail(Object)} instead, | ||
| * especially in move rebasing code. | ||
| * | ||
| * @return null if externalObject is null, or if there is no workingObject for externalObject | ||
| * @throws IllegalArgumentException if it cannot be looked up or if the externalObject's class is not supported | ||
| * @throws IllegalStateException if it cannot be looked up | ||
| * @param <T> the object type | ||
| */ | ||
| <T> @Nullable T lookUpWorkingObject(@Nullable T externalObject); | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 0 additions & 74 deletions
74
core/src/main/java/ai/timefold/solver/core/api/score/director/ScoreDirector.java
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 11 additions & 23 deletions
34
core/src/main/java/ai/timefold/solver/core/api/solver/phase/PhaseCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,34 @@ | ||
| package ai.timefold.solver.core.api.solver.phase; | ||
|
|
||
| import java.util.function.BooleanSupplier; | ||
|
|
||
| import ai.timefold.solver.core.api.domain.solution.PlanningSolution; | ||
| import ai.timefold.solver.core.api.score.Score; | ||
| import ai.timefold.solver.core.api.score.director.ScoreDirector; | ||
| import ai.timefold.solver.core.api.solver.Solver; | ||
| import ai.timefold.solver.core.api.solver.change.ProblemChange; | ||
| import ai.timefold.solver.core.impl.phase.Phase; | ||
| import ai.timefold.solver.core.impl.score.director.InnerScoreDirector; | ||
| import ai.timefold.solver.core.preview.api.move.Move; | ||
|
|
||
| import org.jspecify.annotations.NullMarked; | ||
|
|
||
| /** | ||
| * Runs a custom algorithm as a {@link Phase} of the {@link Solver} that changes the planning variables. | ||
| * To change problem facts, use {@link Solver#addProblemChange(ProblemChange)} instead. | ||
| * <p> | ||
| * To add custom properties, configure custom properties and add public setters for them. | ||
| * To change problem facts and to add or remove entities, use {@link Solver#addProblemChange(ProblemChange)} instead. | ||
| * | ||
| * @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation | ||
| */ | ||
| @NullMarked | ||
| public interface PhaseCommand<Solution_> { | ||
|
|
||
| /** | ||
| * Changes {@link PlanningSolution working solution} of {@link ScoreDirector#getWorkingSolution()}. | ||
| * When the {@link PlanningSolution working solution} is modified, | ||
| * the {@link ScoreDirector} must be correctly notified | ||
| * (through {@link ScoreDirector#beforeVariableChanged(Object, String)} and | ||
| * {@link ScoreDirector#afterVariableChanged(Object, String)}), | ||
| * otherwise calculated {@link Score}s will be corrupted. | ||
| * Changes the current {@link PhaseCommandContext#getWorkingSolution() working solution}. | ||
| * The solver is notified of the changes through {@link PhaseCommandContext}, | ||
| * specifically through {@link PhaseCommandContext#execute(Move)}. | ||
| * Any other modifications to the working solution are strictly forbidden | ||
| * and will likely cause the solver to be in an inconsistent state and throw an exception later on. | ||
| * <p> | ||
| * Don't forget to call {@link ScoreDirector#triggerVariableListeners()} after each set of changes | ||
| * (especially before every {@link InnerScoreDirector#calculateScore()} call) | ||
| * to ensure all shadow variables are updated. | ||
| * Don't forget to check {@link PhaseCommandContext#isPhaseTerminated() termination status} frequently | ||
| * to allow the solver to gracefully terminate when necessary. | ||
| * | ||
| * @param scoreDirector the {@link ScoreDirector} that needs to get notified of the changes. | ||
| * @param isPhaseTerminated long-running command implementations should check this periodically | ||
| * and terminate early if it returns true. | ||
| * Otherwise the terminations configured by the user will have no effect, | ||
| * as the solver can only terminate itself when a command has ended. | ||
| * @param context the context of the command, providing access to the working solution and allowing move execution | ||
| */ | ||
| void changeWorkingSolution(ScoreDirector<Solution_> scoreDirector, BooleanSupplier isPhaseTerminated); | ||
| void changeWorkingSolution(PhaseCommandContext<Solution_> context); | ||
|
|
||
| } |
100 changes: 100 additions & 0 deletions
100
core/src/main/java/ai/timefold/solver/core/api/solver/phase/PhaseCommandContext.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| package ai.timefold.solver.core.api.solver.phase; | ||
|
|
||
| import java.util.function.Function; | ||
|
|
||
| import ai.timefold.solver.core.api.domain.common.Lookup; | ||
| import ai.timefold.solver.core.preview.api.domain.metamodel.PlanningSolutionMetaModel; | ||
| import ai.timefold.solver.core.preview.api.move.Move; | ||
|
|
||
| import org.jspecify.annotations.NullMarked; | ||
| import org.jspecify.annotations.Nullable; | ||
|
|
||
| /** | ||
| * The context of a command that is executed during a custom phase. | ||
| * It provides access to the working solution and allows executing moves. | ||
| * | ||
| * @param <Solution_> the type of the solution | ||
| * @see PhaseCommand | ||
| */ | ||
| @NullMarked | ||
| public interface PhaseCommandContext<Solution_> | ||
| extends Lookup { | ||
|
|
||
| /** | ||
| * Returns the meta-model of the {@link #getWorkingSolution() working solution}. | ||
| * | ||
| * @return the meta-model of the working solution | ||
| */ | ||
| PlanningSolutionMetaModel<Solution_> getSolutionMetaModel(); | ||
|
|
||
| /** | ||
| * Returns the current working solution. | ||
| * It must not be modified directly, | ||
| * but only through {@link #execute(Move)} or {@link #executeTemporarily(Move, Function)}. | ||
| * Direct modifications will cause the solver to be in an inconsistent state and likely throw an exception later on. | ||
| * | ||
| * @return the current working solution | ||
| */ | ||
| Solution_ getWorkingSolution(); | ||
|
|
||
| /** | ||
| * Long-running command implementations should check this periodically and terminate early if it returns true. | ||
| * Otherwise the terminations configured by the user will have no effect, | ||
| * as the solver can only terminate itself when a command has ended. | ||
| * | ||
| * @return true if the solver has requested the phase to terminate, | ||
| * for example because the time limit has been reached. | ||
| */ | ||
| boolean isPhaseTerminated(); | ||
|
|
||
| /** | ||
| * As defined by {@link #execute(Move, boolean)}, | ||
| * but with the guarantee of a fresh score. | ||
| */ | ||
| default void execute(Move<Solution_> move) { | ||
| execute(move, true); | ||
| } | ||
|
|
||
| /** | ||
| * Executes the given move and updates the working solution, | ||
| * optionally without recalculating the score for performance reasons. | ||
| * | ||
| * @param move the move to execute | ||
| * @param guaranteeFreshScore if true, the score of {@link #getWorkingSolution()} after this method returns | ||
| * is guaranteed to be up-to-date; | ||
| * otherwise it may be stale as the solver will skip recalculating it for performance reasons. | ||
| */ | ||
| void execute(Move<Solution_> move, boolean guaranteeFreshScore); | ||
|
|
||
| /** | ||
| * As defined by {@link #executeTemporarily(Move, Function, boolean)}, | ||
| * with the guarantee of a fresh score. | ||
| */ | ||
| default <Result_> @Nullable Result_ executeTemporarily(Move<Solution_> move, | ||
| Function<Solution_, @Nullable Result_> temporarySolutionConsumer) { | ||
| return executeTemporarily(move, temporarySolutionConsumer, true); | ||
| } | ||
|
|
||
| /** | ||
| * Executes the given move temporarily and returns the result of the given consumer. | ||
| * The working solution is reverted to its original state after the consumer has been executed, | ||
| * optionally without recalculating the score for performance reasons. | ||
| * | ||
| * @param move the move to execute temporarily | ||
| * @param temporarySolutionConsumer the consumer to execute with the temporarily modified solution; | ||
| * this solution must not be modified any further. | ||
| * @param guaranteeFreshScore if true, the score of {@link #getWorkingSolution()} after this method returns | ||
| * is guaranteed to be up-to-date; | ||
| * otherwise it may be stale as the solver will skip recalculating it for performance reasons. | ||
| * @return the result of the consumer | ||
| */ | ||
| <Result_> @Nullable Result_ executeTemporarily(Move<Solution_> move, | ||
| Function<Solution_, @Nullable Result_> temporarySolutionConsumer, boolean guaranteeFreshScore); | ||
|
|
||
| @Override | ||
| <T> @Nullable T lookUpWorkingObject(@Nullable T problemFactOrPlanningEntity); | ||
|
|
||
| @Override | ||
| <T> @Nullable T lookUpWorkingObjectOrFail(@Nullable T problemFactOrPlanningEntity); | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
...omain/lookup/ImmutableLookUpStrategy.java → ...omain/common/ImmutableLookupStrategy.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the
executecommands should return the score (that way, users don't need to go throughgetWorkingSolution).