### 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} ``` -------------------------------- ### 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 ... ```