### Basic MoveTester Setup
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/neighborhoods
Initialize MoveTester by providing solution and entity classes, then create a context with the working solution. This setup is for testing moves in isolation.
```java
// Timetable is the solution class, Lesson is a planning entity class.
var solutionMetaModel = PlanningSolutionMetaModel.of(Timetable.class, Lesson.class);
var tester = MoveTester.build(solutionMetaModel);
var context = tester.using(solution);
var move = ...; // Move you wish to test.
context.execute(move);
```
--------------------------------
### Clone Timefold Quickstarts Repository
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Use this command to clone the Timefold quickstarts Git repository, which contains the completed example application for the guide.
```shell
$ git clone https://github.com/TimefoldAI/timefold-quickstarts
```
--------------------------------
### Install Java with Sdkman
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Installs Java using Sdkman, a tool for managing Software Development Kits. Ensure JAVA_HOME is configured.
```shell
$ curl -s "https://get.sdkman.io" | bash
$ sdk install java
```
--------------------------------
### Basic Partitioned Search Configuration
Source: https://docs.timefold.ai/timefold-solver/1.x/enterprise-edition/enterprise-edition
Use this for the simplest partitioned search setup. Ensure your solution classes are annotated with @PlanningId.
```xml
...MyPartitioner
```
--------------------------------
### Original ConstraintProvider
Source: https://docs.timefold.ai/timefold-solver/1.x/enterprise-edition/enterprise-edition
An example of a `ConstraintProvider` class before automatic node sharing is applied. Each lambda is a distinct instance.
```java
public class MyConstraintProvider implements ConstraintProvider {
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
return new Constraint[] {
a(constraintFactory),
b(constraintFactory)
};
}
Constraint a(ConstraintFactory constraintFactory) {
return factory.forEach(Shift.class)
.filter(shift -> shift.getEmployee().getName().equals("Ann"))
.penalize(SimpleScore.ONE)
.asConstraint("a");
}
Constraint b(ConstraintFactory constraintFactory) {
return factory.forEach(Shift.class)
.filter(shift -> shift.getEmployee().getName().equals("Ann"))
.penalize(SimpleScore.ONE)
.asConstraint("b");
}
}
```
--------------------------------
### Benchmark Configuration with Solver Benchmark Blueprint
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/benchmarking-and-tweaking
Utilize a solverBenchmarkBluePrint for quick configuration and execution of benchmarks for typical solver configurations. This example uses the 'EVERY_CONSTRUCTION_HEURISTIC_TYPE_WITH_EVERY_LOCAL_SEARCH_TYPE' blueprint.
```xml
local/
org.acme.vehiclerouting.domain.VehicleRoutePlan
org.acme.vehiclerouting.domain.Vehicle
org.acme.vehiclerouting.domain.Visit
org.acme.vehiclerouting.solver.VehicleRoutingConstraintProvider
1
org.acme.vehiclerouting.persistence.VehicleRoutePlanSolutionFileIO
data/dataset01.json
data/dataset02.json
EVERY_CONSTRUCTION_HEURISTIC_TYPE_WITH_EVERY_LOCAL_SEARCH_TYPE
```
--------------------------------
### Before: Chained Planning Variable Example
Source: https://docs.timefold.ai/timefold-solver/1.x/upgrading-timefold-solver/migration-guides/chained-variables-to-planning-list-variable
Illustrates the 'before' state of a chained model where each Customer points to a Standstill (Vehicle or another Customer) as its previous stop.
```java
public class Vehicle implements Standstill {
private Location depot;
private int capacity;
// ...
}
@PlanningEntity
public class Customer implements Standstill {
private Location location;
private int demand;
@PlanningVariable(graphType = PlanningVariableGraphType.CHAINED, valueRangeProviderRefs = "standstillRange")
private Standstill previousStandstill;
// ...
}
```
--------------------------------
### Clone Timefold Solver Git Repository
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/shared/solutionsourcecode
Use this command to clone the Timefold Solver quickstarts repository. This is the recommended method for setting up the application.
```shell
$ git clone {quickstarts-clone-url}
```
--------------------------------
### Implement ConstraintProvider
Source: https://docs.timefold.ai/timefold-solver/1.x/constraints-and-score/score-calculation
Implement the ConstraintProvider interface to define constraints for the solver. This example shows how to define a single constraint.
```java
public class MyConstraintProvider implements ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory factory) {
return new Constraint[] {
penalizeEveryShift(factory)
};
}
private Constraint penalizeEveryShift(ConstraintFactory factory) {
return factory.forEach(Shift.class)
.penalize(HardSoftScore.ONE_SOFT)
.asConstraint("Penalize a shift");
}
}
```
--------------------------------
### Equivalent Building Blocks Example
Source: https://docs.timefold.ai/timefold-solver/1.x/enterprise-edition/enterprise-edition
Demonstrates two functionally equivalent building blocks that can share a node. Both use the same `forEach` and `filter` operations with the same predicate.
```java
Predicate predicate = shift -> shift.getEmployee().getName().equals("Ann");
var a = factory.forEach(Shift.class)
.filter(predicate);
var b = factory.forEach(Shift.class)
.filter(predicate);
```
--------------------------------
### Simple Constraint Stream Example
Source: https://docs.timefold.ai/timefold-solver/1.x/constraints-and-score/score-calculation
Shows the simplest possible constraint stream, which penalizes each initialized instance of Shift.
```java
private Constraint penalizeInitializedShifts(ConstraintFactory factory) {
return factory.forEach(Shift.class)
.penalize(HardSoftScore.ONE_SOFT)
.asConstraint("Initialized shift");
}
```
--------------------------------
### Chained Planning Entity Example (Java)
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/modeling-planning-problems
Demonstrates a Visit class implementing the Standstill interface and using a chained planning variable 'previousStandstill'. This variable links planning entities in a chain.
```java
@PlanningEntity
public class Visit ... implements Standstill {
...
public City getCity() {...}
@PlanningVariable(graphType = PlanningVariableGraphType.CHAINED)
public Standstill getPreviousStandstill() {
return previousStandstill;
}
public void setPreviousStandstill(Standstill previousStandstill) {
this.previousStandstill = previousStandstill;
}
}
```
--------------------------------
### Configure Simulated Annealing Starting Temperature
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/local-search
Set the simulatedAnnealingStartingTemperature to the maximum score delta a single move can cause. Use the Benchmarker to tweak this value.
```xml
...
2hard/100soft
1
```
--------------------------------
### Implement TimeslotChangeMoveProvider
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/neighborhoods
Example implementation of MoveProvider for a timeslot change move. It enumerates lessons and timeslots, samples a combination, and generates a change move, filtering out no-op changes.
```java
public class TimeslotChangeMoveProvider
implements MoveProvider {
private PlanningVariableMetaModel timeslotVariable;
public TimeslotChangeMoveProvider(PlanningVariableMetaModel timeslotVariable) {
this.timeslotVariable = Objects.requireNonNull(timeslotVariable);
}
@Override
public MoveStream build(MoveStreamFactory factory) {
var lessonEnumeration = factory.forEach(Lesson.class, false); // False means no null values.
var timeslotEnumeration = factory.forEach(Timeslot.class, false);
return factory.pick(lessonEnumeration)
.pick(timeslotEnumeration,
filtering((solutionView, lesson, newTimeslot) -> lesson.timeslot != newTimeslot)) // Avoid no-op.
.asMove((solutionView, lesson, newTimeslot) -> Moves.change(timeslotVariable, lesson, newTimeslot));
}
}
```
--------------------------------
### Example Info Log Output for Move Evaluation Speed
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/quarkus-vehicle-routing/quarkus-vehicle-routing-quickstart
Monitor the 'move evaluation speed' in the info log to assess the performance impact of constraints during the solving process.
```log
... Solving ended: ..., move evaluation speed (29455/sec), ...
```
--------------------------------
### Build and Run PlannerBenchmark from XML
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/benchmarking-and-tweaking
Instantiate a PlannerBenchmark using a factory created from an XML resource. Then, build the benchmark instance and execute it, displaying the report in a browser.
```java
PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource(
"org/acme/vehiclerouting/benchmarkConfig.xml");
PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark();
benchmark.benchmarkAndShowReportInBrowser();
```
--------------------------------
### Load, Solve, and Print Solution in Java
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Loads demo data, builds a solver, solves the problem, and prints the resulting timetable.
```java
// Load the problem
Timetable problem = generateDemoData();
// Solve the problem
Solver solver = solverFactory.buildSolver();
Timetable solution = solver.solve(problem);
// Visualize the solution
printTimetable(solution);
```
--------------------------------
### Vehicle Routing Constraint Verification in Kotlin
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/quarkus-vehicle-routing/quarkus-vehicle-routing-quickstart
Example of a unit test using `ConstraintVerifier` to test the `vehicleCapacity` constraint in a vehicle routing problem. This is the Kotlin equivalent of the Java example.
```kotlin
package org.acme.vehiclerouting.solver;
import java.time.Duration
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.util.Arrays
import jakarta.inject.Inject
import ai.timefold.solver.test.api.score.stream.ConstraintVerifier
import ai.timefold.solver.core.api.score.stream.ConstraintFactory
import org.acme.vehiclerouting.domain.Location
import org.acme.vehiclerouting.domain.Vehicle
import org.acme.vehiclerouting.domain.VehicleRoutePlan
import org.acme.vehiclerouting.domain.Visit
import org.acme.vehiclerouting.domain.geo.HaversineDrivingTimeCalculator
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import io.quarkus.test.junit.QuarkusTest
@QuarkusTest
internal class VehicleRoutingConstraintProviderTest {
@Inject
lateinit var constraintVerifier: ConstraintVerifier
@Test
fun vehicleCapacityPenalized() {
val tomorrow_07_00 = LocalDateTime.of(TOMORROW, LocalTime.of(7, 0))
val tomorrow_08_00 = LocalDateTime.of(TOMORROW, LocalTime.of(8, 0))
val tomorrow_10_00 = LocalDateTime.of(TOMORROW, LocalTime.of(10, 0))
val vehicleA = Vehicle("1", 100, LOCATION_1, tomorrow_07_00)
val visit1 = Visit("2", "John", LOCATION_2, 80, tomorrow_08_00, tomorrow_10_00, Duration.ofMinutes(30L))
vehicleA.visits!!.add(visit1)
```
--------------------------------
### Example Console Output: Timetable Schedule
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
This output displays a sample timetable schedule, showing room assignments for classes and their respective teachers and grades. Verify this output conforms to all hard constraints.
```text
...
INFO | | Room A | Room B | Room C |
INFO |------------|------------|------------|------------|
INFO | MON 08:30 | English | Math | |
INFO | | I. Jones | A. Turing | |
INFO | | 9th grade | 10th grade | |
INFO |------------|------------|------------|------------|
INFO | MON 09:30 | History | Physics | |
INFO | | I. Jones | M. Curie | |
INFO | | 9th grade | 10th grade |
...
```
--------------------------------
### Anchor Planning Entity Example (Java)
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/modeling-planning-problems
Example of a Domicile class acting as an anchor in a TSP problem. It implements the Standstill interface, which is common for anchors and planning entities in chained variable scenarios.
```java
public class Domicile ... implements Standstill {
...
public City getCity() {...}
}
```
--------------------------------
### Load, Solve, and Print Solution in Kotlin
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Loads demo data, builds a solver, solves the problem, and prints the resulting timetable.
```kotlin
// Load the problem
val problem = generateDemoData(DemoData.SMALL)
// Solve the problem
val solver = solverFactory.buildSolver()
val solution = solver.solve(problem)
// Visualize the solution
printTimetable(solution)
```
--------------------------------
### Example REST Service Response
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/quarkus-vehicle-routing/quarkus-vehicle-routing-quickstart
This is an example of the JSON output received from the REST service after processing the route plan. It details the assigned visits to each vehicle, arrival times, total demands, and driving times.
```json
HTTP/1.1 200
Content-Type: application/json
...
{"name":"demo","vehicles":[{"id":"1","capacity":15,"homeLocation":[40.605994321126936,-75.68106859680056],"departureTime":"2024-02-10T07:30:00","visits":[],"arrivalTime":"2024-02-10T15:34:11","totalDemand":3,"totalDrivingTimeSeconds":10826},{"id":"2","capacity":25,"homeLocation":[40.32196770776356,-75.69785667307953],"departureTime":"2024-02-10T07:30:00","visits":[],"arrivalTime":"2024-02-10T13:52:18","totalDemand":3,"totalDrivingTimeSeconds":7890}],"visits":[{"id":"1","name":"Dan Green","location":[40.76104493121754,-75.16056341466826],"demand":1,"minStartTime":"2024-02-10T13:00:00","maxEndTime":"2024-02-10T18:00:00","serviceDuration":1200.000000000,"vehicle":"1","previousVisit":"5","nextVisit":"4","arrivalTime":"2024-02-10T09:40:50","startServiceTime":"2024-02-10T13:00:00","departureTime":"2024-02-10T13:20:00","drivingTimeSecondsFromPreviousStandstill":4250},{"id":"2","name":"Ivy King","location":[40.13754381024318,-75.492526629236],"demand":1,"minStartTime":"2024-02-10T13:00:00","maxEndTime":"2024-02-10T18:00:00","serviceDuration":1200.000000000,"vehicle":"2","previousVisit":"3","nextVisit":null,"arrivalTime":"2024-02-10T09:19:12","startServiceTime":"2024-02-10T13:00:00","departureTime":"2024-02-10T13:20:00","drivingTimeSecondsFromPreviousStandstill":2329},{"id":"3","name":"Flo Li","location":[39.87122455090297,-75.64520072015769],"demand":2,"minStartTime":"2024-02-10T08:00:00","maxEndTime":"2024-02-10T12:00:00","serviceDuration":600.000000000,"vehicle":"2","previousVisit":null,"nextVisit":"2","arrivalTime":"2024-02-10T08:30:23","startServiceTime":"2024-02-10T08:30:23","departureTime":"2024-02-10T08:40:23","drivingTimeSecondsFromPreviousStandstill":3623},{"id":"4","name":"Flo Cole","location":[40.46124744193433,-75.18250987609025],"demand":1,"minStartTime":"2024-02-10T13:00:00","maxEndTime":"2024-02-10T18:00:00","serviceDuration":2400.000000000,"vehicle":"1","previousVisit":"1","nextVisit":null,"arrivalTime":"2024-02-10T14:00:04","startServiceTime":"2024-02-10T14:00:04","departureTime":"2024-02-10T14:40:04","drivingTimeSecondsFromPreviousStandstill":2404},{"id":"5","name":"Carl Green","location":[40.61352381171549,-75.83301278355529],"demand":1,"minStartTime":"2024-02-10T08:00:00","maxEndTime":"2024-02-10T12:00:00","serviceDuration":1800.000000000,"vehicle":"1","previousVisit":null,"nextVisit":"1","arrivalTime":"2024-02-10T07:45:25","startServiceTime":"2024-02-10T08:00:00","departureTime":"2024-02-10T08:30:00","drivingTimeSecondsFromPreviousStandstill":925}],"score":"0hard/-18716soft","totalDrivingTimeSeconds":18716}
```
--------------------------------
### Define custom interval equality with start and end
Source: https://docs.timefold.ai/timefold-solver/1.x/upgrading-timefold-solver/upgrade-to-latest-version
Defines a record `IntervalEqualByStartAndEnd` to ensure objects are equal only if both start and end properties match. This prevents issues with `flattenLast` when downstream filters depend on these properties.
```java
record IntervalEqualByStartAndEnd(int start, int end) {}
factory.forEach(Shift.class)
.map(shift -> new IntervalEqualByStartAndEnd(shift.getStart(), shift.getEnd()))
// "end" is considered by IntervalEqualByStartAndEnd,
// so no issue occurs
.filter(interval -> interval.end() > 2)
// ...
```
--------------------------------
### Configure Solver Factory in Java
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Sets up the SolverFactory with solution class, entity classes, constraint provider, and a termination limit.
```java
SolverFactory solverFactory = SolverFactory.create(
new SolverConfig()
.withSolutionClass(Timetable.class)
.withEntityClasses(Lesson.class)
.withConstraintProviderClass(TimetableConstraintProvider.class)
// The solver runs only for 5 seconds on this small dataset.
// It's recommended to run for at least 5 minutes ("5m") otherwise.
.withTerminationSpentLimit(Duration.ofSeconds(5)));
```
--------------------------------
### UniConstraintStream Example
Source: https://docs.timefold.ai/timefold-solver/1.x/constraints-and-score/score-calculation
Demonstrates a simple UniConstraintStream where the stream operates on a single type of object.
```java
private Constraint doNotAssignAnn(ConstraintFactory factory) {
return factory.forEach(Shift.class) // Returns UniStream.
...
}
```
--------------------------------
### Simple MoveIteratorFactory Configuration
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Use this simple configuration for basic MoveIteratorFactory setup. It can be nested within a unionMoveSelector.
```xml
...
```
--------------------------------
### Verify Constraint with a Full Solution
Source: https://docs.timefold.ai/timefold-solver/1.x/constraints-and-score/score-calculation
This Java code demonstrates verifying a constraint using a complete planning solution. It also shows how to explicitly enable shadow variable updates during verification.
```java
constraintVerifier.verifyThat(VehicleRoutingConstraintProvider::vehicleCapacity)
.givenSolution(solution)
.settingAllShadowVariables()
.penalizesBy(20);
```
--------------------------------
### Simple First Fit Construction Heuristic Configuration
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/construction-heuristics
Use this simple configuration to enable the First Fit construction heuristic. It automatically initializes planning entities.
```xml
FIRST_FIT
```
--------------------------------
### Run a Simple Timefold Solver Benchmark
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/benchmarking-and-tweaking
Create a PlannerBenchmarkFactory from your solver configuration XML, load datasets, and build a benchmark. The benchmark report is generated in 'local/benchmarkReport' and opened in the browser.
```java
PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromSolverConfigXmlResource(
"org/acme/vehiclerouting/solverConfig.xml");
VehicleRoutePlan dataset1 = ...;
VehicleRoutePlan dataset2 = ...;
VehicleRoutePlan dataset3 = ...;
PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark(dataset1, dataset2, dataset3);
benchmark.benchmarkAndShowReportInBrowser();
```
--------------------------------
### Get MoveTestContext from NeighborhoodTester
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/neighborhoods
Shows how to obtain a MoveTestContext directly from a NeighborhoodTester instance, which is useful for executing generated moves.
```java
var tester = NeighborhoodTester.build(new SwapMoveProvider(), solutionMetaModel);
var testerContext = tester.using(solution);
var moveTestContext = testerContext.getMoveTestContext();
```
--------------------------------
### Build Solver Instance with XML Configuration
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/configuration
Instantiate a SolverFactory with an XML configuration file from the classpath. The SolverFactory is then used to build the Solver instance. Ensure the XML file is accessible as a classpath resource.
```java
SolverFactory solverFactory = SolverFactory.createFromXmlResource(
"org/acme/schooltimetabling/solverConfig.xml");
Solver solver = solverFactory.buildSolver();
```
--------------------------------
### Construction Heuristic for Multiple Entity Classes (CatEntity)
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/construction-heuristics
Example of configuring a construction heuristic for a specific entity class, 'CatEntity'. This demonstrates how to apply distinct initialization logic for different entity types within the same problem.
```xml
...CatEntity
PHASE
...
```
--------------------------------
### Filter Long Periods
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Implement SelectionFilter to exclude values that do not meet specific criteria. This example filters for periods that are long.
```java
public class LongPeriodSelectionFilter implements SelectionFilter {
@Override
public boolean accept(ScoreDirector scoreDirector, Period period) {
return period();
}
}
```
--------------------------------
### Filter Long Lectures
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Implement SelectionFilter to exclude entities that do not meet certain criteria. This example filters out lectures that are not long.
```java
public class LongLectureSelectionFilter implements SelectionFilter {
@Override
public boolean accept(ScoreDirector scoreDirector, Lecture lecture) {
return lecture.isLong();
}
}
```
--------------------------------
### Example Timetable Output
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Displays a sample optimized school timetable, showing assignments of lessons to rooms and timeslots, along with teacher and student information. This output is generated after the Timefold solver has processed the scheduling problem.
```text
INFO Solving ended: time spent (5000), best score (0hard/9soft), ...
INFO
INFO | | Room A | Room B | Room C |
INFO |------------|------------|------------|------------|
INFO | MON 08:30 | English | Math | |
INFO | | I. Jones | A. Turing | |
INFO | | 9th grade | 10th grade | |
INFO |------------|------------|------------|------------|
INFO | MON 09:30 | History | Physics | |
INFO | | I. Jones | M. Curie | |
INFO | | 9th grade | 10th grade | |
INFO |------------|------------|------------|------------|
INFO | MON 10:30 | History | Physics | |
INFO | | I. Jones | M. Curie | |
INFO | | 10th grade | 9th grade | |
INFO |------------|------------|------------|------------|
...
INFO |------------|------------|------------|------------|
```
--------------------------------
### JAXB XML Output for HardSoftScore
Source: https://docs.timefold.ai/timefold-solver/1.x/integration/integration
This is an example of the pretty XML output generated for a HardSoftScore when using the appropriate JAXB adapter.
```xml
...
0hard/-200soft
```
--------------------------------
### Filter Course Swap Moves
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Implement SelectionFilter to prevent specific moves from being selected. This example filters out swaps between lectures of the same course.
```java
public class DifferentCourseSwapMoveFilter implements SelectionFilter {
@Override
public boolean accept(ScoreDirector scoreDirector, SwapMove move) {
Lecture leftLecture = (Lecture) move.getLeftEntity();
Lecture rightLecture = (Lecture) move.getRightEntity();
return !leftLecture.getCourse().equals(rightLecture.getCourse());
}
}
```
--------------------------------
### Create Lesson Instances
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Creates a list of Lesson objects for the timetable. Each lesson is initialized with a unique ID, subject, teacher, and student group.
```java
lessons.add(new Lesson(Long.toString(nextLessonId++), "Math", "A. Turing", "10th grade"));
lessons.add(new Lesson(Long.toString(nextLessonId++), "Physics", "M. Curie", "10th grade"));
lessons.add(new Lesson(Long.toString(nextLessonId++), "Chemistry", "M. Curie", "10th grade"));
lessons.add(new Lesson(Long.toString(nextLessonId++), "French", "M. Curie", "10th grade"));
lessons.add(new Lesson(Long.toString(nextLessonId++), "Geography", "C. Darwin", "10th grade"));
lessons.add(new Lesson(Long.toString(nextLessonId++), "History", "I. Jones", "10th grade"));
lessons.add(new Lesson(Long.toString(nextLessonId++), "English", "P. Cruz", "10th grade"));
lessons.add(new Lesson(Long.toString(nextLessonId), "Spanish", "P. Cruz", "10th grade"));
```
--------------------------------
### Cheapest Insertion: Simple Configuration
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/construction-heuristics
Simple configuration for the Cheapest Insertion construction heuristic.
```xml
CHEAPEST_INSERTION
```
--------------------------------
### Jackson JSON Output for HardSoftScore
Source: https://docs.timefold.ai/timefold-solver/1.x/integration/integration
This JSON example illustrates how a HardSoftScore is represented when using Timefold's Jackson serializers and deserializers.
```json
{
"score":"0hard/-200soft"
...
}
```
--------------------------------
### Example CustomerNearbyDistanceMeter Implementation
Source: https://docs.timefold.ai/timefold-solver/1.x/enterprise-edition/enterprise-edition
A concrete implementation of NearbyDistanceMeter for Customer objects, calculating distance to a LocationAware destination. This implementation is expected to be stateless.
```java
public class CustomerNearbyDistanceMeter implements NearbyDistanceMeter {
public double getNearbyDistance(Customer origin, LocationAware destination) {
return origin.getDistanceTo(destination);
}
}
```
--------------------------------
### Checking Move Doability
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Implements isMoveDoable to prevent moves that change nothing or are impossible. This example checks if the lesson is already in the target timeslot.
```java
@Override
public boolean isMoveDoable(ScoreDirector scoreDirector) {
return !Objects.equals(lesson.getTimeslot(), toTimeslot);
}
```
--------------------------------
### Initialize Constraint Provider
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/shared/school-timetabling/school-timetabling-constraints
Sets up the TimeTableConstraintProvider to define all hard and soft constraints for the solver. This is the entry point for constraint definition.
```kotlin
package org.acme.kotlin.schooltimetabling.solver
import ai.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore
import ai.timefold.solver.core.api.score.stream.Constraint
import ai.timefold.solver.core.api.score.stream.ConstraintFactory
import ai.timefold.solver.core.api.score.stream.ConstraintProvider
import ai.timefold.solver.core.api.score.stream.Joiners
import org.acme.kotlin.schooltimetabling.domain.Lesson
import org.acme.kotlin.schooltimetabling.solver.justifications.*
import java.time.Duration
class TimeTableConstraintProvider : ConstraintProvider {
override fun defineConstraints(constraintFactory: ConstraintFactory): Array {
return arrayOf(
// Hard constraints
roomConflict(constraintFactory),
teacherConflict(constraintFactory),
studentGroupConflict(constraintFactory),
// Soft constraints
teacherRoomStability(constraintFactory),
teacherTimeEfficiency(constraintFactory),
studentGroupSubjectVariety(constraintFactory)
)
}
fun roomConflict(constraintFactory: ConstraintFactory): Constraint {
// A room can accommodate at most one lesson at the same time.
return constraintFactory
// Select each pair of 2 different lessons ...
.forEachUniquePair(
Lesson::class.java,
// ... in the same timeslot ...
Joiners.equal(Lesson::timeslot),
// ... in the same room ...
Joiners.equal(Lesson::room)
)
// ... and penalize each pair with a hard weight.
.penalize(HardSoftScore.ONE_HARD)
.justifyWith { lesson1: Lesson, lesson2: Lesson, _ ->
RoomConflictJustification(lesson1.room, lesson1,lesson2)}
.asConstraint("Room conflict")
}
fun teacherConflict(constraintFactory: ConstraintFactory): Constraint {
// A teacher can teach at most one lesson at the same time.
return constraintFactory
.forEachUniquePair(
Lesson::class.java,
Joiners.equal(Lesson::timeslot),
Joiners.equal(Lesson::teacher)
)
.penalize(HardSoftScore.ONE_HARD)
.justifyWith { lesson1: Lesson, lesson2: Lesson, _ ->
TeacherConflictJustification(lesson1.teacher, lesson1, lesson2)}
.asConstraint("Teacher conflict")
}
fun studentGroupConflict(constraintFactory: ConstraintFactory): Constraint {
// A student can attend at most one lesson at the same time.
return constraintFactory
.forEachUniquePair(
Lesson::class.java,
Joiners.equal(Lesson::timeslot),
Joiners.equal(Lesson::studentGroup)
)
.penalize(HardSoftScore.ONE_HARD)
.justifyWith { lesson1: Lesson, lesson2: Lesson, _ ->
StudentGroupConflictJustification(lesson1.studentGroup, lesson1, lesson2)}
.asConstraint("Student group conflict")
}
fun teacherRoomStability(constraintFactory: ConstraintFactory): Constraint {
// A teacher prefers to teach in a single room.
return constraintFactory
.forEachUniquePair(
```
--------------------------------
### Configure Entity Selector with Comparator
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Configure an entitySelector to use a custom Comparator for sorting. This example uses VisitComparator and sorts in descending order.
```xml
PHASE
SORTED
...VisitComparator
DESCENDING
```
--------------------------------
### Build Planner Benchmark from Freemarker XML
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/benchmarking-and-tweaking
Instantiate and build a `PlannerBenchmark` object from a Freemarker XML resource using `PlannerBenchmarkFactory`. Ensure the resource path is correct.
```java
PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromFreemarkerXmlResource(
"org/acme/vehiclerouting/solverConfig.xml");
PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark();
```
--------------------------------
### Build Planner Benchmark with Multiple Datasets
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/benchmarking-and-tweaking
Load multiple datasets in advance and pass them to the buildPlannerBenchmark() method. This is an alternative to serializing datasets to local files when dealing with databases or other repositories.
```java
PlannerBenchmark plannerBenchmark = benchmarkFactory.buildPlannerBenchmark(dataset1, dataset2, dataset3);
```
--------------------------------
### Remove LookupStrategyType from @PlanningSolution
Source: https://docs.timefold.ai/timefold-solver/1.x/upgrading-timefold-solver/upgrade-to-latest-version
Before Timefold Solver 1.10.0, LookupStrategyType could be configured. This example shows how to remove it to prepare for future versions where it will be removed.
```java
@PlanningSolution(lookUpStrategyType = LookUpStrategyType.PLANNING_ID_OR_NONE)
public class Timetable {
...
}
```
```java
@PlanningSolution
public class Timetable {
...
}
```
--------------------------------
### Overriding SolverManager Bean in Java
Source: https://docs.timefold.ai/timefold-solver/1.x/integration/integration
Provides an example of creating a custom `SolverManager` bean in Java, overriding the default configuration provided by `TimefoldAutoConfiguration`.
```java
package org.acme.schooltimetabling.rest;
import ai.timefold.solver.core.api.solver.SolverFactory;
import ai.timefold.solver.core.api.solver.SolverManager;
import ai.timefold.solver.core.config.solver.SolverManagerConfig;
import ai.timefold.solver.spring.boot.autoconfigure.TimefoldAutoConfiguration;
import org.acme.schooltimetabling.domain.Timetable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
@Configuration
@Import(TimefoldAutoConfiguration.class)
public class BeanProducer {
@Bean
@Primary
public SolverManager overrideSolverManager(SolverFactory solverFactory) {
SolverManagerConfig solverManagerConfig = new SolverManagerConfig();
return SolverManager.create(solverFactory, solverManagerConfig);
}
}
```
--------------------------------
### Test All Constraints Together
Source: https://docs.timefold.ai/timefold-solver/1.x/constraints-and-score/score-calculation
Use this to test the entire `ConstraintProvider` instance with given facts. Ensure all planning entities and problem facts are listed in `given()`, or provide the entire planning solution.
```java
@Test
public void givenFactsMultipleConstraints() {
LocalDateTime tomorrow_07_00 = LocalDateTime.of(TOMORROW, LocalTime.of(7, 0));
LocalDateTime tomorrow_08_00 = LocalDateTime.of(TOMORROW, LocalTime.of(8, 0));
LocalDateTime tomorrow_10_00 = LocalDateTime.of(TOMORROW, LocalTime.of(10, 0));
Vehicle vehicleA = new Vehicle("1", 100, LOCATION_1, tomorrow_07_00);
Visit visit1 = new Visit("2", "John", LOCATION_2, 80, tomorrow_08_00, tomorrow_10_00, Duration.ofMinutes(30L));
vehicleA.getVisits().add(visit1);
Visit visit2 = new Visit("3", "Paul", LOCATION_3, 40, tomorrow_08_00, tomorrow_10_00, Duration.ofMinutes(30L));
vehicleA.getVisits().add(visit2);
constraintVerifier.verifyThat()
.given(vehicleA, visit1, visit2)
.scores(HardSoftScore.ofSoft(20));
}
```
```java
constraintVerifier.verifyThat()
.givenSolution(solution)
.settingAllShadowVariables()
.scores(HardSoftScore.ofSoft(20));
```
--------------------------------
### Filter Lessons Not Scheduled on Monday Morning
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/neighborhoods
This example demonstrates a basic filter in Constraint Streams to exclude lessons scheduled on Monday morning.
```java
var lessonStream = factory.forEach(Lesson.class)
.filter(lesson -> lesson.timeslot != MONDAY_MORNING)
...
```
--------------------------------
### Create and Display Benchmark Aggregator UI
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/benchmarking-and-tweaking
Launch the Benchmark Aggregator UI by providing a benchmark configuration XML resource to `BenchmarkAggregatorFrame.createAndDisplayFromXmlResource()`. This UI allows merging existing benchmark reports.
```java
public static void main(String[] args) {
BenchmarkAggregatorFrame.createAndDisplayFromXmlResource(
"org/acme/vehiclerouting/solverConfig.xml");
}
```
--------------------------------
### Allocate to Value from Queue: Simple Configuration
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/construction-heuristics
Simple configuration for the Allocate To Value From Queue construction heuristic.
```xml
ALLOCATE_TO_VALUE_FROM_QUEUE
```
--------------------------------
### Custom Move Iterator Factory Implementation
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Example implementation of MoveIteratorFactory for generating possible assignment moves. It provides both original and random move iterators.
```java
public class PossibleAssignmentsOnlyMoveIteratorFactory implements MoveIteratorFactory {
@Override
public long getSize(ScoreDirector scoreDirector) {
// In this case, we return the exact size, but an estimate can be used
// if it too expensive to calculate or unknown
long totalSize = 0L;
var solution = scoreDirector.getWorkingSolution();
for (MyEntity entity : solution.getEntities()) {
for (MyPlanningValue value : solution.getValues()) {
if (entity.canBeAssigned(value)) {
totalSize++;
}
}
}
return totalSize;
}
@Override
public Iterator createOriginalMoveIterator(ScoreDirector scoreDirector) {
// Only needed if selectionOrder is ORIGINAL or if it is cached
var solution = scoreDirector.getWorkingSolution();
var entities = solution.getEntities();
var values = solution.getValues();
// Assumes each entity has at least one assignable value
var firstEntityIndex = 0;
var firstValueIndex = 0;
while (!entities.get(firstEntityIndex).canBeAssigned(values.get(firstValueIndex))) {
firstValueIndex++;
}
return new Iterator<>() {
int nextEntityIndex = firstEntityIndex;
int nextValueIndex = firstValueIndex;
@Override
public boolean hasNext() {
return nextEntityIndex < entities.size();
}
@Override
public MyChangeMove next() {
var selectedEntity = entities.get(nextEntityIndex);
var selectedValue = values.get(nextValueIndex);
nextValueIndex++;
while (nextValueIndex < values.size() && !selectedEntity.canBeAssigned(values.get(nextValueIndex))) {
nextValueIndex++;
}
if (nextValueIndex >= values.size()) {
// value list exhausted, go to next entity
nextEntityIndex++;
if (nextEntityIndex < entities.size()) {
nextValueIndex = 0;
while (nextValueIndex < values.size() && !entities.get(nextEntityIndex).canBeAssigned(values.get(nextValueIndex))) {
// Assumes each entity has at least one assignable value
nextValueIndex++;
}
}
}
return new MyChangeMove(selectedEntity, selectedValue);
}
};
}
@Override
public Iterator createRandomMoveIterator(ScoreDirector scoreDirector,
Random workingRandom) {
// Not needed if selectionOrder is ORIGINAL or if it is cached
var solution = scoreDirector.getWorkingSolution();
var entities = solution.getEntities();
var values = solution.getValues();
return new Iterator<>() {
@Override
public boolean hasNext() {
return !entities.isEmpty();
}
@Override
public MyChangeMove next() {
var selectedEntity = entities.get(workingRandom.nextInt(entities.size()));
var selectedValue = values.get(workingRandom.nextInt(values.size()));
while (!selectedEntity.canBeAssigned(selectedValue)) {
// This assumes there at least one value that can be assigned to the selected entity
selectedValue = values.get(workingRandom.nextInt(values.size()));
}
return new MyChangeMove(selectedEntity, selectedValue);
}
};
}
}
```
--------------------------------
### Custom Comparator for Entity Sorting
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/overview
Implement a Comparator to define custom sorting logic for entities. This example sorts visits by service duration and then by ID.
```java
public class VisitComparator implements Comparator {
public int compare(Visit a, Visit b) {
return new CompareToBuilder()
.append(a.getServiceDuration(), b.getServiceDuration())
.append(a.getId(), b.getId())
.toComparison();
}
}
```
--------------------------------
### Prepare Test Data for Constraint Verification
Source: https://docs.timefold.ai/timefold-solver/1.x/constraints-and-score/score-calculation
This Java snippet demonstrates how to create and populate domain objects for testing. These objects represent the facts that the constraint will operate on.
```java
Vehicle vehicleA = new Vehicle("1", 100, LOCATION_1, tomorrow_07_00);
Visit visit1 = new Visit("2", "John", LOCATION_2, 80, tomorrow_08_00, tomorrow_10_00, Duration.ofMinutes(30L));
vehicleA.getVisits().add(visit1);
Visit visit2 = new Visit("3", "Paul", LOCATION_3, 40, tomorrow_08_00, tomorrow_10_00, Duration.ofMinutes(30L));
vehicleA.getVisits().add(visit2);
```
--------------------------------
### Configure Solver Config XML Files
Source: https://docs.timefold.ai/timefold-solver/1.x/integration/integration
Specify the solver configuration XML files for 'teacherSolver' and 'roomSolver' in the application.properties file. This links the solver names to their respective configurations.
```properties
timefold.solver.teacherSolver.solver-config-xml=teachersSolverConfig.xml (1)
timefold.solver.roomSolver.solver-config-xml=roomsSolverConfig.xml (2)
```
--------------------------------
### Configure Logback for Tenant-Specific Files
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/running-the-solver
Example Logback configuration using SiftingAppender to route logs to tenant-specific files based on the 'tenant.name' MDC key.
```xml
tenant.name
unknown
local/log/timefold-solver-${tenant.name}.log
...
```
--------------------------------
### Configure JAXB for BendableScore Marshalling
Source: https://docs.timefold.ai/timefold-solver/1.x/integration/integration
For bendable scores, use the BendableScoreJaxbAdapter to correctly marshal them to XML or JSON. This example demonstrates its usage in a @PlanningSolution class.
```java
@PlanningSolution
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD)
public class Schedule {
@PlanningScore
@XmlJavaTypeAdapter(BendableScoreJaxbAdapter.class)
private BendableScore score;
...
}
```
--------------------------------
### Matrix Benchmarking with Freemarker Template
Source: https://docs.timefold.ai/timefold-solver/1.x/using-timefold-solver/benchmarking-and-tweaking
Use a Freemarker template to define multiple solver configurations for matrix benchmarking, reducing XML verbosity. This example benchmarks different entityTabuSize and acceptedCountLimit values.
```xml
...
...
<#list [5, 7, 11, 13] as entityTabuSize>
<#list [500, 1000, 2000] as acceptedCountLimit>
Tabu Search entityTabuSize ${entityTabuSize} acceptedCountLimit ${acceptedCountLimit}
${entityTabuSize}
${acceptedCountLimit}
#list>
#list>
```
--------------------------------
### Configure Solver Factory in Kotlin
Source: https://docs.timefold.ai/timefold-solver/1.x/quickstart/hello-world/hello-world-quickstart
Sets up the SolverFactory with solution class, entity classes, constraint provider, and a termination limit.
```kotlin
val solverFactory = SolverFactory.create(
SolverConfig()
.withSolutionClass(Timetable::class.java)
.withEntityClasses(Lesson::class.java)
.withConstraintProviderClass(TimetableConstraintProvider::class.java)
// The solver runs only for 5 seconds on this small dataset.
// It's recommended to run for at least 5 minutes ("5m") otherwise.
.withTerminationSpentLimit(Duration.ofSeconds(5)))
```
--------------------------------
### Configure Block Distribution for Nearby Selection
Source: https://docs.timefold.ai/timefold-solver/1.x/enterprise-edition/enterprise-edition
Use BLOCK_DISTRIBUTION to select only the n nearest elements with equal probability. Example selects the 20 nearest.
```xml
20
```
--------------------------------
### Construction Heuristic for Multiple Entity Classes (DogEntity)
Source: https://docs.timefold.ai/timefold-solver/1.x/optimization-algorithms/construction-heuristics
Example of configuring a construction heuristic for a specific entity class, 'DogEntity'. This approach allows for tailored initialization strategies per entity type.
```xml
...DogEntity
PHASE
...
```