timefold


Nametimefold JSON
Version 1.17.0b0 PyPI version JSON
download
home_pagehttps://github.com/TimefoldAI/timefold-solver
SummaryAn AI constraint solver that optimizes planning and scheduling problems
upload_time2024-12-10 14:08:48
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseApache License Version 2.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![Timefold Logo](https://raw.githubusercontent.com/TimefoldAI/timefold-solver/main/docs/src/modules/ROOT/images/shared/timefold-logo.png)

_Planning optimization made easy._  
[timefold.ai](https://timefold.ai)

[![Stackoverflow](https://img.shields.io/badge/stackoverflow-ask_question-orange.svg?logo=stackoverflow&style=for-the-badge)](https://stackoverflow.com/questions/tagged/timefold) 
[![GitHub Discussions](https://img.shields.io/github/discussions/TimefoldAI/timefold-solver?style=for-the-badge&logo=github)](https://github.com/TimefoldAI/timefold-solver/discussions)

[![PyPI](https://img.shields.io/pypi/v/timefold?style=for-the-badge& "PyPI")](https://pypi.org/project/timefold/) 
[![Python support](https://img.shields.io/badge/Python-3.10+-brightgreen.svg?style=for-the-badge)](https://www.python.org/downloads)
[![License](https://img.shields.io/github/license/TimefoldAI/timefold-solver?style=for-the-badge&logo=apache)](https://www.apache.org/licenses/LICENSE-2.0)

[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=coverage)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)


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](https://github.com/TimefoldAI/timefold-solver) or Kotlin.

## Get started with Timefold Solver in Python

* [Read a Getting Started guide](https://timefold.ai/docs)
* [Clone the Quickstarts repository](https://github.com/TimefoldAI/timefold-quickstarts)

## Requirements

- [Install Python 3.10 or later.](https://www.python.org)
- [Install JDK 17 or later](https://adoptium.net) with the environment variable `JAVA_HOME` configured to the JDK installation directory.
  For example, with [Sdkman](https://sdkman.io/):
  ```shell
  $ sdk install java
  ```

## Build from source

1. [Build the main branch of Timefold Solver from source](https://github.com/TimefoldAI/timefold-solver?tab=readme-ov-file#build-from-source)
2. Install the repo
   ```shell
   $ 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:

```python
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:

```python
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:

```python
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`.

- 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:

```python
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

```python
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](https://timefold.ai/docs/timefold-solver/latest).

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


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/TimefoldAI/timefold-solver",
    "name": "timefold",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/75/7c/e7df9183555b10a59099cb880d58736ad95159b8e1d5e76dcfd2d956e3d0/timefold-1.17.0b0.tar.gz",
    "platform": null,
    "description": "![Timefold Logo](https://raw.githubusercontent.com/TimefoldAI/timefold-solver/main/docs/src/modules/ROOT/images/shared/timefold-logo.png)\n\n_Planning optimization made easy._  \n[timefold.ai](https://timefold.ai)\n\n[![Stackoverflow](https://img.shields.io/badge/stackoverflow-ask_question-orange.svg?logo=stackoverflow&style=for-the-badge)](https://stackoverflow.com/questions/tagged/timefold) \n[![GitHub Discussions](https://img.shields.io/github/discussions/TimefoldAI/timefold-solver?style=for-the-badge&logo=github)](https://github.com/TimefoldAI/timefold-solver/discussions)\n\n[![PyPI](https://img.shields.io/pypi/v/timefold?style=for-the-badge& \"PyPI\")](https://pypi.org/project/timefold/) \n[![Python support](https://img.shields.io/badge/Python-3.10+-brightgreen.svg?style=for-the-badge)](https://www.python.org/downloads)\n[![License](https://img.shields.io/github/license/TimefoldAI/timefold-solver?style=for-the-badge&logo=apache)](https://www.apache.org/licenses/LICENSE-2.0)\n\n[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)\n[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ai.timefold:timefold-solver&metric=coverage)](https://sonarcloud.io/summary/new_code?id=ai.timefold:timefold-solver)\n\n\nTimefold Solver is an AI constraint solver you can use to optimize\nthe Vehicle Routing Problem, Employee Rostering, Maintenance Scheduling, Task Assignment, School Timetabling,\nCloud Optimization, Conference Scheduling, Job Shop Scheduling and many more planning problems.\n\nUsing Timefold Solver in Python is significantly slower \nthan using [Timefold Solver for Java](https://github.com/TimefoldAI/timefold-solver) or Kotlin.\n\n## Get started with Timefold Solver in Python\n\n* [Read a Getting Started guide](https://timefold.ai/docs)\n* [Clone the Quickstarts repository](https://github.com/TimefoldAI/timefold-quickstarts)\n\n## Requirements\n\n- [Install Python 3.10 or later.](https://www.python.org)\n- [Install JDK 17 or later](https://adoptium.net) with the environment variable `JAVA_HOME` configured to the JDK installation directory.\n  For example, with [Sdkman](https://sdkman.io/):\n  ```shell\n  $ sdk install java\n  ```\n\n## Build from source\n\n1. [Build the main branch of Timefold Solver from source](https://github.com/TimefoldAI/timefold-solver?tab=readme-ov-file#build-from-source)\n2. Install the repo\n   ```shell\n   $ pip install git+https://github.com/TimefoldAI/timefold-solver.git\n   ```\n\n## Source code overview\n\n### Domain\n\nIn Timefold Solver, the domain has three parts:\n\n- Problem Facts, which do not change.\n- Planning Entities, which have one or more planning variables.\n- Planning Solution, which define the facts and entities of the problem.\n\n#### Problem Facts\n\nProblem facts can be any Python class, which are used to describe unchanging facts in your problem:\n\n```python\nfrom dataclasses import dataclass\nfrom datetime import time\n\n@dataclass\nclass Timeslot:\n    id: int\n    day_of_week: str\n    start_time: time\n    end_time: time\n```\n\n#### Planning Entities\n\nTo declare Planning Entities, use the `@planning_entity` decorator along with annotations:\n\n```python\nfrom dataclasses import dataclass, field\nfrom typing import Annotated\nfrom timefold.solver.domain import planning_entity, PlanningId, PlanningVariable\n\n@planning_entity\n@dataclass\nclass Lesson:\n    id: Annotated[int, PlanningId]\n    subject: str\n    teacher: str\n    student_group: str\n    timeslot: Annotated[Timeslot, PlanningVariable] = field(default=None)\n    room: Annotated[Room, PlanningVariable] = field(default=None)\n```\n\n- The `PlanningVariable` annotation is used to mark what fields the solver is allowed to change.\n\n- 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.\n\n#### Planning Solution\n\nTo declare the Planning Solution, use the `@planning_solution` decorator:\n\n```python\nfrom dataclasses import dataclass, field\nfrom typing import Annotated\nfrom timefold.solver.domain import (planning_solution, ProblemFactCollectionProperty, ValueRangeProvider,\n                                    PlanningEntityCollectionProperty, PlanningScore)\nfrom timefold.solver.score import HardSoftScore\n\n@planning_solution\n@dataclass\nclass TimeTable:\n    timeslots: Annotated[list[Timeslot], ProblemFactCollectionProperty, ValueRangeProvider]\n    rooms: Annotated[list[Room], ProblemFactCollectionProperty, ValueRangeProvider]\n    lessons: Annotated[list[Lesson], PlanningEntityCollectionProperty]\n    score: Annotated[HardSoftScore, PlanningScore] = field(default=None)\n```\n\n- The `ValueRangeProvider` annotation is used to denote a field that contains possible planning values for a `PlanningVariable`.\n\n- The`ProblemFactCollection` annotation is used to denote a field that contains problem facts. This allows these facts to be queried in your constraints.\n\n- The `PlanningEntityCollection` annotation is used to denote a field that contains planning entities. The planning variables of these entities will be modified during solving. \n\n- 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.\n\n### Constraints\n\nYou define your constraints by using the ConstraintFactory:\n\n```python\nfrom domain import Lesson\nfrom timefold.solver.score import (Joiners, HardSoftScore, ConstraintFactory,\n                                   Constraint, constraint_provider)\n\n@constraint_provider\ndef define_constraints(constraint_factory: ConstraintFactory) -> list[Constraint]:\n    return [\n        # Hard constraints\n        room_conflict(constraint_factory),\n        # Other constraints here...\n    ]\n\ndef room_conflict(constraint_factory: ConstraintFactory) -> Constraint:\n    # A room can accommodate at most one lesson at the same time.\n    return (\n        constraint_factory.for_each_unique_pair(Lesson,\n                # ... in the same timeslot ...\n                Joiners.equal(lambda lesson: lesson.timeslot),\n                # ... in the same room ...\n                Joiners.equal(lambda lesson: lesson.room))\n            .penalize(HardSoftScore.ONE_HARD)\n            .as_constraint(\"Room conflict\")\n    )\n```\nfor more details on Constraint Streams,\nsee https://timefold.ai/docs/timefold-solver/latest/constraints-and-score/score-calculation.\n\n### Solve\n\n```python\nfrom timefold.solver import SolverFactory\nfrom timefold.solver.config import SolverConfig, TerminationConfig, ScoreDirectorFactoryConfig, Duration\nfrom constraints import define_constraints\nfrom domain import TimeTable, Lesson, generate_problem\n\nsolver_config = SolverConfig(\n    solution_class=TimeTable,\n    entity_class_list=[Lesson],\n    score_director_factory_config=ScoreDirectorFactoryConfig(\n        constraint_provider_function=define_constraints\n    ),\n    termination_config=TerminationConfig(\n        spent_limit=Duration(seconds=30)\n    )\n)\n\nsolver = SolverFactory.create(solver_config).build_solver()\nsolution = solver.solve(generate_problem())\n```\n\n`solution` will be a `TimeTable` instance with planning\nvariables set to the final best solution found.\n\nFor a full API spec, visit [the Timefold Documentation](https://timefold.ai/docs/timefold-solver/latest).\n\n## Legal notice\n\nTimefold Solver is a derivative work of OptaPlanner and OptaPy,\nwhich includes copyrights of the original creator, Red Hat Inc., affiliates, and contributors,\nthat were all entirely licensed under the Apache-2.0 license.\nEvery source file has been modified.\n\n",
    "bugtrack_url": null,
    "license": "Apache License Version 2.0",
    "summary": "An AI constraint solver that optimizes planning and scheduling problems",
    "version": "1.17.0b0",
    "project_urls": {
        "Homepage": "https://github.com/TimefoldAI/timefold-solver",
        "Timefold Homepage": "https://timefold.ai",
        "Timefold Solver Documentation": "https://timefold.ai/docs/timefold-solver/latest"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d8551371cc1eba983c3c138bc97c5465b66c78c5ae1b894280f0809d0956e4bb",
                "md5": "6f2864550e2e845154dedf001286335b",
                "sha256": "20181c1addc0a3d62291d4265c81dc19620ca622bb1b6b8ef1de1f4a4dbc34fb"
            },
            "downloads": -1,
            "filename": "timefold-1.17.0b0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "6f2864550e2e845154dedf001286335b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 17065085,
            "upload_time": "2024-12-10T14:08:45",
            "upload_time_iso_8601": "2024-12-10T14:08:45.487272Z",
            "url": "https://files.pythonhosted.org/packages/d8/55/1371cc1eba983c3c138bc97c5465b66c78c5ae1b894280f0809d0956e4bb/timefold-1.17.0b0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "757ce7df9183555b10a59099cb880d58736ad95159b8e1d5e76dcfd2d956e3d0",
                "md5": "cca4b91e1394003f8d7137220f1bbdbb",
                "sha256": "ed2379215266ab2223f324f113cbc505acaae5d6524b355ac33ebbd47ad00a0d"
            },
            "downloads": -1,
            "filename": "timefold-1.17.0b0.tar.gz",
            "has_sig": false,
            "md5_digest": "cca4b91e1394003f8d7137220f1bbdbb",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 1602266,
            "upload_time": "2024-12-10T14:08:48",
            "upload_time_iso_8601": "2024-12-10T14:08:48.629131Z",
            "url": "https://files.pythonhosted.org/packages/75/7c/e7df9183555b10a59099cb880d58736ad95159b8e1d5e76dcfd2d956e3d0/timefold-1.17.0b0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-10 14:08:48",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "TimefoldAI",
    "github_project": "timefold-solver",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "timefold"
}
        
Elapsed time: 0.41844s