Skip to main content

An AI constraint solver that optimizes planning and scheduling problems

Project description

Timefold Logo

Planning optimization made easy.
timefold.ai

PyPI License JVM support Python support Commit Activity

Stackoverflow GitHub Discussions GitHub Issues

Reliability Rating Security Rating Maintainability Rating Coverage

Timefold Solver for Python is an AI constraint solver 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 for Python is significantly slower than using Timefold Solver for Java or Kotlin.

Get started with Timefold Solver for Python

Requirements

Build from source

  1. Build the main branch of Timefold Solver for Java from source
  2. 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 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:

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 for Python is a derivative work of 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

timefold-1.13.0b0.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

timefold-1.13.0b0-py3-none-any.whl (16.9 MB view details)

Uploaded Python 3

File details

Details for the file timefold-1.13.0b0.tar.gz.

File metadata

  • Download URL: timefold-1.13.0b0.tar.gz
  • Upload date:
  • Size: 1.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.0 CPython/3.12.5

File hashes

Hashes for timefold-1.13.0b0.tar.gz
Algorithm Hash digest
SHA256 c828ba0cf29790eb613cd75ac1da8ba5fb479375e6401ae6ed9eff07e1360d7f
MD5 48cbc650e8cefc77fa252b405a50ebe3
BLAKE2b-256 c12a73a3f70f9ab1769535fc5a0f8e5e0a946c9ce4561d706786abe56061fa62

See more details on using hashes here.

File details

Details for the file timefold-1.13.0b0-py3-none-any.whl.

File metadata

  • Download URL: timefold-1.13.0b0-py3-none-any.whl
  • Upload date:
  • Size: 16.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.0 CPython/3.12.5

File hashes

Hashes for timefold-1.13.0b0-py3-none-any.whl
Algorithm Hash digest
SHA256 22de3f020bbe76252bf1b9f755f29b0ec10d58ad5a3786df03f5c674a54f1933
MD5 72c5ba016fad3392e9d4545f1c8c024e
BLAKE2b-256 2107ece5ed65921d8144b1417193e06a69e068d4a2ebcfa5e62ba85a02613af0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page