Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/src/modules/ROOT/pages/integration/integration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ The `SolverConfig` resource is constructed by reading the `application.propertie
Therefore, Domain entities (solution, entities, and constraint classes) and customized properties (`spent-limit`, etc.) for the
planning problem are identified and loaded into the solver configuration.

The available resouses can be injected as follows:
The available resources can be injected as follows:

[tabs]
====
Expand Down Expand Up @@ -293,13 +293,13 @@ Kotlin::
@Path("path")
class Resource {

private final var fastSolver: SolverManager<...>?
private final var regularSolver: SolverManager<...>?
private lateinit var fastSolver: SolverManager<...>?
private lateinit var regularSolver: SolverManager<...>?

@Inject
constructor(
@Named("fastSolver") fastSolver: SolverManager<Timetable, String>,
@Named("regularSolver") fastSolver: SolverManager<Timetable, String>
@Named("regularSolver") regularSolver: SolverManager<Timetable, String>
) {
this.fastSolver = fastSolver
this.regularSolver = regularSolver
Expand Down Expand Up @@ -405,8 +405,8 @@ class Teacher {
@Path("path")
class Resource {

private final var teacherToLessonScheduleSolverManager: SolverManager<TeacherToLessonSchedule, String>?
private final var lessonToRoomTimeslotSolverManager: SolverManager<Timetable, String>?
private lateinit var teacherToLessonScheduleSolverManager: SolverManager<TeacherToLessonSchedule, String>?
private lateinit var lessonToRoomTimeslotSolverManager: SolverManager<Timetable, String>?

@Inject
constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,9 @@ For example, don't change a gym lecture to a room which is not a gym room.
It's usually better to not use move filtering for such cases,
because it allows the metaheuristics to temporarily break hard constraints to escape local optima.
+
[NOTE]
====
Any built-in hard constraint must probably be filtered on every move type of every solver phase.
NOTE: Any built-in hard constraint must probably be filtered on every move type of every solver phase.
For example if it filters the change move of Local Search, it must also filter the swap move that swaps the room of a gym lecture with another lecture for which the other lecture's original room isn't a gym room.
Furthermore, it must also filter the change moves of the Construction Heuristics (which requires an advanced configuration).
====

If a move is unaccepted by the filter, it's not executed and the score isn't calculated.

Expand All @@ -459,21 +456,16 @@ public interface SelectionFilter<Solution_, T> {
----

Implement the `accept` method to return `false` on a discarded `selection` (see below).
Implementations are expected to be stateless,
as the solver may choose to reuse them in different contexts.

Filtered selection can happen on any Selector in the selector tree, including any ``MoveSelector``, `EntitySelector`
or ``ValueSelector``.
It works with any `cacheType` and ``selectionOrder``.

[NOTE]
====
Apply the filter on the lowest level possible.
In most cases, you'll need to know both the entity and the value involved so you'll have to apply it on the move selector.
====

[NOTE]
====
`SelectionFilter` implementations are expected to be stateless.
The solver may choose to reuse them in different contexts.
====

[#filteredMoveSelection]
===== Filtered move selection
Expand All @@ -482,12 +474,14 @@ Unaccepted moves will not be selected and will therefore never need to be undone

[source,java,options="nowrap"]
----
public class DifferentCourseSwapMoveFilter implements SelectionFilter<CourseSchedule, SwapMove> {
public class DifferentCourseSwapMoveFilter
implements SelectionFilter<CourseSchedule, SelectorBasedSwapMove<CourseSchedule, Lecture>> {

@Override
public boolean accept(ScoreDirector<CourseSchedule> scoreDirector, SwapMove move) {
Lecture leftLecture = (Lecture) move.getLeftEntity();
Lecture rightLecture = (Lecture) move.getRightEntity();
public boolean accept(ScoreDirector<CourseSchedule> scoreDirector,
SelectorBasedSwapMove<CourseSchedule, Lecture> move) {
var leftLecture = (Lecture) move.getLeftEntity();
var rightLecture = (Lecture) move.getRightEntity();
return !leftLecture.getCourse().equals(rightLecture.getCourse());
}

Expand Down Expand Up @@ -999,6 +993,7 @@ only set the distribution type (so without a `distributionSizeMaximum` parameter
<betaDistributionBeta>5</betaDistributionBeta>
</nearbySelection>
----

[#basicMoveSelectors]
== Move selectors for basic variables

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ from the `Timetable` planning solution class:
----
PlanningSolutionMetaModel<Timetable> solutionMetaModel = ...; // The solver will give this to you.
PlanningVariableMetaModel<Timetable, Lesson, Timeslot> timeslotVariable =
solutionMetaModel.entity(Lesson.class)
.genuineVariable("timeslot");
solutionMetaModel.genuineEntity(Lesson.class)
.basicVariable("timeslot", Timeslot.class);
----

If any of the entities or variables cannot be found,
Expand All @@ -189,8 +189,8 @@ The code above can often be simplified with Java's local type inference:
[source,java,options="nowrap"]
----
var solutionMetaModel = ...; // The solver will give this to you.
var timeslotVariable = solutionMetaModel.entity(Lesson.class)
.genuineVariable("timeslot", Timeslot.class);
var timeslotVariable = solutionMetaModel.genuineEntity(Lesson.class)
.basicVariable("timeslot", Timeslot.class);
----

NOTE: Long-time users of Timefold Solver may be familiar with the concept of variable descriptors.
Expand Down Expand Up @@ -343,7 +343,7 @@ void testChangeMove() {
var newRoom = timetable.getRooms().get(1);

var solutionMetaModel = PlanningSolutionMetaModel.of(Timetable.class, Lesson.class);
var variableMetaModel = solutionMetaModel.entity(Lesson.class)
var variableMetaModel = solutionMetaModel.genuineEntity(Lesson.class)
.basicVariable("room", Room.class);

var move = Moves.change(variableMetaModel, lesson, newRoom);
Expand Down Expand Up @@ -374,7 +374,7 @@ void testMoveThenUndo() {
var newRoom = timetable.getRooms().get(1);

var solutionMetaModel = PlanningSolutionMetaModel.of(Timetable.class, Lesson.class);
var variableMetaModel = solutionMetaModel.entity(Lesson.class)
var variableMetaModel = solutionMetaModel.genuineEntity(Lesson.class)
.basicVariable("room", Room.class);

var move = Moves.change(variableMetaModel, lesson, newRoom);
Expand Down Expand Up @@ -765,8 +765,8 @@ public class MyNeighborhoodProvider implements NeighborhoodProvider<MySolution>
@Override
public Neighborhood defineNeighborhood(NeighborhoodBuilder<MySolution> builder) {
var timeslotVariable = builder.getSolutionMetaModel()
.entity(Lesson.class)
.variable("timeslot", Timeslot.class);
.genuineEntity(Lesson.class)
.basicVariable("timeslot", Timeslot.class);
return builder.add(new TimeslotChangeMoveProvider(timeslotVariable))
.build();
}
Expand Down
Loading