Skip to content
This repository was archived by the owner on Oct 6, 2025. It is now read-only.

Repository files navigation

Timefold Logo

Planning optimization made easy.
timefold.ai

PyPIPython supportLicense

Timefold Solver is an AI constraint solver you can use to optimize the Vehicle Routing Problem, Employee Rostering, Maintenance Scheduling, Task Assignment, School Timetabling, Cloud Optimization, Conference Scheduling, Job Shop Scheduling and many more planning problems.

Using Timefold Solver in Python is significantly slower than using Timefold Solver for Java or Kotlin.

Get started with Timefold Solver in Python

  • Clone Timefold Solver for Python repository: git clone https://github.com/TimefoldAI/timefold-solver-python.git

  • Navigate to the quickstarts directory and choose a quickstart: cd timefold-solver-python/quickstarts/hello-world

Requirements

Build from source

  1. Install the repo
    $ pip install git+https://github.com/TimefoldAI/timefold-solver-python.git

Source code overview

Domain

In Timefold Solver, the domain has three parts:

  • Problem Facts, which do not change.
  • Planning Entities, which have one or more planning variables.
  • Planning Solution, which define the facts and entities of the problem.

Problem Facts

Problem facts can be any Python class, which are used to describe unchanging facts in your problem:

fromdataclassesimportdataclassfromdatetimeimporttime@dataclassclassTimeslot:
id: intday_of_week: strstart_time: timeend_time: time

Planning Entities

To declare Planning Entities, use the @planning_entity decorator along with annotations:

fromdataclassesimportdataclass, fieldfromtypingimportAnnotatedfromtimefold.solver.domainimportplanning_entity, PlanningId, PlanningVariable@planning_entity@dataclassclassLesson:
id: Annotated[int, PlanningId]
subject: strteacher: strstudent_group: strtimeslot: Annotated[Timeslot, PlanningVariable] =field(default=None)
room: Annotated[Room, PlanningVariable] =field(default=None)
  • The PlanningVariable annotation is used to mark what fields the solver is allowed to change.

  • The PlanningId annotation is used to uniquely identify an entity object of a particular class. The same Planning Id can be used on entities of different classes, but the ids of all entities in the same class must be different.

Planning Solution

To declare the Planning Solution, use the @planning_solution decorator:

fromdataclassesimportdataclass, fieldfromtypingimportAnnotatedfromtimefold.solver.domainimport (planning_solution, ProblemFactCollectionProperty, ValueRangeProvider,
PlanningEntityCollectionProperty, PlanningScore)
fromtimefold.solver.scoreimportHardSoftScore@planning_solution@dataclassclassTimeTable:
timeslots: Annotated[list[Timeslot], ProblemFactCollectionProperty, ValueRangeProvider]
rooms: Annotated[list[Room], ProblemFactCollectionProperty, ValueRangeProvider]
lessons: Annotated[list[Lesson], PlanningEntityCollectionProperty]
score: Annotated[HardSoftScore, PlanningScore] =field(default=None)
  • The ValueRangeProvider annotation is used to denote a field that contains possible planning values for a PlanningVariable.

  • TheProblemFactCollection annotation is used to denote a field that contains problem facts. This allows these facts to be queried in your constraints.

  • The PlanningEntityCollection annotation is used to denote a field that contains planning entities. The planning variables of these entities will be modified during solving.

  • The PlanningScore annotation is used to denote the field that holds the score of the current solution. The solver will set this field during solving.

Constraints

You define your constraints by using the ConstraintFactory:

fromdomainimportLessonfromtimefold.solver.scoreimport (Joiners, HardSoftScore, ConstraintFactory,
Constraint, constraint_provider)
@constraint_providerdefdefine_constraints(constraint_factory: ConstraintFactory) ->list[Constraint]:
return [
# Hard constraintsroom_conflict(constraint_factory),
# Other constraints here...
]
defroom_conflict(constraint_factory: ConstraintFactory) ->Constraint:
# A room can accommodate at most one lesson at the same time.return (
constraint_factory.for_each_unique_pair(Lesson,
# ... in the same timeslot ...Joiners.equal(lambdalesson: lesson.timeslot),
# ... in the same room ...Joiners.equal(lambdalesson: lesson.room))
.penalize(HardSoftScore.ONE_HARD)
.as_constraint("Room conflict")
)

Also see Timefold Solver Documentation on Constraint Streams.

Solve

fromtimefold.solverimportSolverFactoryfromtimefold.solver.configimportSolverConfig, TerminationConfig, ScoreDirectorFactoryConfig, Durationfromconstraintsimportdefine_constraintsfromdomainimportTimeTable, Lesson, generate_problemsolver_config=SolverConfig(
solution_class=TimeTable,
entity_class_list=[Lesson],
score_director_factory_config=ScoreDirectorFactoryConfig(
constraint_provider_function=define_constraints
),
termination_config=TerminationConfig(
spent_limit=Duration(seconds=30)
)
)
solver=SolverFactory.create(solver_config).build_solver()
solution=solver.solve(generate_problem())

solution will be a TimeTable instance with planning variables set to the final best solution found.

For a full API spec, visit the Timefold Documentation.

Legal notice

Timefold Solver is a derivative work of OptaPlanner and OptaPy, which includes copyrights of the original creator, Red Hat Inc., affiliates, and contributors, that were all entirely licensed under the Apache-2.0 license. Every source file has been modified.

About

Timefold Solver is an AI constraint solver for Python to optimize the Vehicle Routing Problem, Employee Rostering, Maintenance Scheduling, Task Assignment, School Timetabling, Cloud Optimization, Conference Scheduling, Job Shop Scheduling, Bin Packing and many more planning problems.

Topics

Resources

Stars

57 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages