An AI constraint solver that optimizes planning and scheduling problems
Project description
Planning optimization made easy.
timefold.ai
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
Requirements
- Install Python 3.10 or later.
- Install JDK 17 or later with the environment variable
JAVA_HOME
configured to the JDK installation directory. For example, with Sdkman:$ sdk install java
Build from source
- Build the main branch of Timefold Solver from source
- Install the repo
$ pip install git+https://github.com/TimefoldAI/timefold-solver.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:
from dataclasses import dataclass
from datetime import time
@dataclass
class Timeslot:
id: int
day_of_week: str
start_time: time
end_time: time
Planning Entities
To declare Planning Entities, use the @planning_entity
decorator along with annotations:
from dataclasses import dataclass, field
from typing import Annotated
from timefold.solver.domain import planning_entity, PlanningId, PlanningVariable
@planning_entity
@dataclass
class Lesson:
id: Annotated[int, PlanningId]
subject: str
teacher: str
student_group: str
timeslot: 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:
from dataclasses import dataclass, field
from typing import Annotated
from timefold.solver.domain import (planning_solution, ProblemFactCollectionProperty, ValueRangeProvider,
PlanningEntityCollectionProperty, PlanningScore)
from timefold.solver.score import HardSoftScore
@planning_solution
@dataclass
class TimeTable:
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 aPlanningVariable
. -
The
ProblemFactCollection
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:
from domain import Lesson
from timefold.solver.score import (Joiners, HardSoftScore, ConstraintFactory,
Constraint, constraint_provider)
@constraint_provider
def define_constraints(constraint_factory: ConstraintFactory) -> list[Constraint]:
return [
# Hard constraints
room_conflict(constraint_factory),
# Other constraints here...
]
def room_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(lambda lesson: lesson.timeslot),
# ... in the same room ...
Joiners.equal(lambda lesson: lesson.room))
.penalize(HardSoftScore.ONE_HARD)
.as_constraint("Room conflict")
)
for more details on Constraint Streams, see https://timefold.ai/docs/timefold-solver/latest/constraints-and-score/score-calculation.
Solve
from timefold.solver import SolverFactory
from timefold.solver.config import SolverConfig, TerminationConfig, ScoreDirectorFactoryConfig, Duration
from constraints import define_constraints
from domain import TimeTable, Lesson, generate_problem
solver_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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file timefold-1.18.0b0.tar.gz
.
File metadata
- Download URL: timefold-1.18.0b0.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e740ea1e99bfcff4e8ca7d7476a5c89d9b9bb5aa3dd5f5d09ff9285c74a9967b |
|
MD5 | d82b35fda73417f3e89f455e728982f6 |
|
BLAKE2b-256 | e0b41e5e4b674eb3c367b13b31f1d9535b5c0f931e5fcbfc9eb5b860c2332adc |
Provenance
The following attestation bundles were made for timefold-1.18.0b0.tar.gz
:
Publisher:
release.yml
on TimefoldAI/timefold-solver
-
Statement:
- Statement type:
https://in-toto.io/Statement/v1
- Predicate type:
https://docs.pypi.org/attestations/publish/v1
- Subject name:
timefold-1.18.0b0.tar.gz
- Subject digest:
e740ea1e99bfcff4e8ca7d7476a5c89d9b9bb5aa3dd5f5d09ff9285c74a9967b
- Sigstore transparency entry: 162677560
- Sigstore integration time:
- Permalink:
TimefoldAI/timefold-solver@24455361647b28ccba41265cedb61dc7a5b4a8e0
- Branch / Tag:
refs/heads/main
- Owner: https://github.com/TimefoldAI
- Access:
public
- Token Issuer:
https://token.actions.githubusercontent.com
- Runner Environment:
github-hosted
- Publication workflow:
release.yml@24455361647b28ccba41265cedb61dc7a5b4a8e0
- Trigger Event:
workflow_dispatch
- Statement type:
File details
Details for the file timefold-1.18.0b0-py3-none-any.whl
.
File metadata
- Download URL: timefold-1.18.0b0-py3-none-any.whl
- Upload date:
- Size: 17.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6676a332e1b5b041ff6fd5f8aa09cf18999948c429d42e7489de7c57f7f3c0b8 |
|
MD5 | a6517127c0ec24da75ef34976e66bd4a |
|
BLAKE2b-256 | 3bb9bd5ed16b054f0c965e680f9b359c7281905bc11fba7c07549f5fc766ac0d |
Provenance
The following attestation bundles were made for timefold-1.18.0b0-py3-none-any.whl
:
Publisher:
release.yml
on TimefoldAI/timefold-solver
-
Statement:
- Statement type:
https://in-toto.io/Statement/v1
- Predicate type:
https://docs.pypi.org/attestations/publish/v1
- Subject name:
timefold-1.18.0b0-py3-none-any.whl
- Subject digest:
6676a332e1b5b041ff6fd5f8aa09cf18999948c429d42e7489de7c57f7f3c0b8
- Sigstore transparency entry: 162677566
- Sigstore integration time:
- Permalink:
TimefoldAI/timefold-solver@24455361647b28ccba41265cedb61dc7a5b4a8e0
- Branch / Tag:
refs/heads/main
- Owner: https://github.com/TimefoldAI
- Access:
public
- Token Issuer:
https://token.actions.githubusercontent.com
- Runner Environment:
github-hosted
- Publication workflow:
release.yml@24455361647b28ccba41265cedb61dc7a5b4a8e0
- Trigger Event:
workflow_dispatch
- Statement type: