Metadata-Version: 2.4
Name: pytimetable
Version: 0.2.0
Summary: A domain-independent constraint-based scheduling framework for modeling, generating, and optimizing timetable.
Project-URL: Homepage, https://github.com/briansimpo/pytimetable
Project-URL: Documentation, https://github.com/briansimpo/pytimetable#readme
Project-URL: Source, https://github.com/briansimpo/pytimetable
Project-URL: Issues, https://github.com/briansimpo/pytimetable/issues
Author-email: Brian Simpokolwe <briansimpokolwe@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: constraint-satisfaction,optimization,scheduling,timetable,timetabling
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.12
Description-Content-Type: text/markdown

# PyTimetable

**PyTimetable** is a domain-independent constraint-based scheduling framework for modeling, generating, and optimizing timetables.

It provides reusable scheduling primitives for activities, participants, facilitators, venues, time, requirements, constraints, and optimization without coupling the scheduling engine to a particular application domain.

PyTimetable can be used for problems such as:

* university timetables
* school timetables
* examination schedules
* training schedules
* meeting schedules
* resource-constrained scheduling problems

Applications can either construct PyTimetable problems directly or adapt their existing domain models into a PyTimetable `Problem`.

```text
Application Domain
       │
       ▼
 ProblemAdapter
       │
       ▼
    Problem
       │
       ▼
     Solver
       │
       ▼
    Solution
       │
       ▼
 SolutionAdapter
       │
       ▼
Application Result
```

The scheduling engine does not need to understand concepts such as courses, semesters, classrooms, or university programs. Applications translate those concepts into generic scheduling requirements.

---

## Installation

Install PyTimetable from PyPI:

```bash
pip install pytimetable
```

For local development:

```bash
git clone git clone https://github.com/briansimpo/pytimetable.git
cd pytimetable

python -m venv venv
```

Activate the virtual environment.

### Windows

```powershell
.\venv\Scripts\Activate.ps1
```

### Linux / macOS

```bash
source venv/bin/activate
```

Install the project in editable mode:

```bash
pip install -e .
```

---

# Quick Start

The following example demonstrates the basic PyTimetable workflow using native scheduling objects.

```text
Timeline
   +
Resources
   +
Activities
   │
   ▼
Problem
   │
   ▼
Solver
   │
   ▼
Solution
```

## 1. Create a Timeline

A `Timeline` defines the schedulable days and periods available to the solver.

```python
from datetime import time

from pytimetable.temporal.timeline import TimelineBuilder


timeline = TimelineBuilder(
    days=5,
    start_time=time(8, 0),
    end_time=time(17, 0),
    period_minutes=60,
).build()
```

This creates a five-day scheduling timeline with one-hour periods between 08:00 and 17:00.

---

## 2. Create Resources

PyTimetable schedules activities against resources such as facilitators and venues.

Create a location and venue type:

```python
from pytimetable.models.location import Location
from pytimetable.models.venuetype import VenueType


main_building = Location(
    name="Main Building",
)

lecture_room = VenueType(
    name="Lecture Room",
)
```

Create a venue:

```python
from pytimetable.models.venue import Venue, Venues
from pytimetable.temporal.availability import Availability


room_a = Venue(
    name="Room A",
    capacity=100,
    location=main_building,
    venue_type=lecture_room,
    availability=Availability(
        timeline.timeslots
    ),
)

venues = Venues([
    room_a,
])
```

Create an eligible facilitator:

```python
from pytimetable.models.facilitator import (
    Facilitator,
    Facilitators,
)


lecturer = Facilitator(
    name="Dr Ada Lovelace",
    availability=Availability(
        timeline.timeslots
    ),
)

facilitators = Facilitators([
    lecturer,
])
```

---

## 3. Create a Participant

A `Participant` represents the person or group that must attend an activity.

```python
from pytimetable.models.participant import Participant


students = Participant(
    name="Computer Science Y1",
    size=40,
    availability=Availability(
        timeline.timeslots
    ),
)
```

---

## 4. Create an Event

An `Event` represents the broader event to which one or more schedulable activities belong.

It can also define the facilitators eligible to conduct those activities.

```python
from pytimetable.models.event import Event


programming = Event(
    name="Programming I",
    facilitators=facilitators,
)
```

---

## 5. Create an Activity

An `Activity` is the unit that the solver places into the timetable.

The following activity represents a two-period lecture requiring one facilitator and a lecture room with sufficient capacity.

```python
from pytimetable.requirements.facilitator import (
    FacilitatorRequirement,
)
from pytimetable.requirements.timeslot import (
    TimeslotRequirement,
)
from pytimetable.requirements.venue import (
    VenueRequirement,
)
from pytimetable.scheduler.activity import (
    Activity,
    Activities,
)
from pytimetable.temporal.duration import Duration


lecture = Activity(
    name="Lecture",
    event=programming,
    participant=students,
    duration=Duration(
        periods=2,
    ),
    facilitator_requirement=(
        FacilitatorRequirement(
            minimum=1,
            maximum=1,
        )
    ),
    venue_requirement=(
        VenueRequirement(
            capacity=students.size,
            venue_type=lecture_room,
        )
    ),
    timeslot_requirement=(
        TimeslotRequirement()
    ),
)

activities = Activities([
    lecture,
])
```

The scheduling engine does not need to know what a university lecture means.

The activity simply declares its scheduling requirements:

```text
Duration       → 2 periods
Participant    → Computer Science Y1
Facilitators   → 1 required
Venue capacity → 40
Venue type     → Lecture Room
```

---

## 6. Build the Problem

Combine the activities, venues, timeline, and other scheduling information into a `Problem`.

```python
from pytimetable.problem import Problem
from pytimetable.scheduler.spatial.travel import TravelTimes


problem = Problem(
    activities=activities,
    venues=venues,
    timeline=timeline,
    travel_times=TravelTimes(),
)
```

---

## 7. Solve

Pass the problem to `Solver`:

```python
from pytimetable.solver import Solver


solution = Solver(
    seed=42,
).solve(
    problem
)
```

The solver searches for assignments satisfying the activity requirements while respecting scheduling constraints and resource availability.

A seed can be supplied to make randomized solver behaviour reproducible during development and testing.

---

# Core Concepts

PyTimetable represents scheduling problems using a small set of domain-independent concepts.

## Activity

An `Activity` represents something that must be scheduled.

Examples include:

* a lecture
* a laboratory session
* a tutorial
* an examination
* a meeting
* a training session

An activity describes its duration, participant, and resource requirements.

The solver determines where and when the activity should be scheduled.

---

## Event

An `Event` groups related scheduling information and identifies the facilitators eligible to conduct its activities.

For example:

```text
Event
└── Programming I
     ├── Lecture
     ├── Lab
     └── Tutorial
```

Each schedulable component is represented by an `Activity`.

---

## Participant

A `Participant` represents the people or group that must attend an activity.

For a university timetable, a participant might represent:

```text
Computer Science
Year 1
Semester 1
```

Participant availability and conflicts are considered when constructing the timetable.

---

## Facilitator

A `Facilitator` represents a resource responsible for conducting an activity.

Examples include:

* lecturers
* teachers
* instructors
* supervisors

An event can have multiple eligible facilitators. The scheduler selects an appropriate facilitator while respecting requirements, availability, and conflicts.

---

## Venue

A `Venue` represents a physical location where an activity can take place.

A venue can describe:

* capacity
* venue type
* location
* availability

For example:

```text
Lecture Room A
Capacity: 120
Type: Lecture Room
Location: Main Building
```

---

## Venue Type

A `VenueType` describes the purpose or category of a venue.

Examples include:

```text
Lecture Room
Computer Lab
Tutorial Room
Chemistry Lab
Workshop
Studio
```

An activity can require a particular venue type.

This allows the scheduling engine to prevent incompatible assignments such as scheduling a computer laboratory activity in an ordinary lecture room.

---

# Time Model

PyTimetable explicitly models scheduling time through days, periods, timeslots, durations, and timelines.

## Day

A `Day` represents a schedulable day of the week.

```python
from pytimetable.temporal.day import Day


monday = Day(1)

print(monday)
# Monday
```

---

## Period

A `Period` represents a schedulable period within a day.

It contains both an internal period number and its real-world time range.

```python
from datetime import time

from pytimetable.temporal.period import Period


period = Period(
    number=1,
    start_time=time(7, 30),
    end_time=time(8, 20),
)

print(period)
# 07:30-08:20
```

The period number provides a convenient internal representation for the scheduling engine, while `start_time` and `end_time` represent the actual time range.

---

## Timeslot

A `Timeslot` combines a `Day` and a `Period`.

```text
Timeslot
├── Day
└── Period
```

For example:

```text
Monday
07:30-08:20
```

represents one schedulable position in the timetable.

---

## Duration

An activity specifies how many periods it occupies.

```python
from pytimetable.temporal.duration import Duration


duration = Duration(
    periods=2,
)
```

This means the activity requires two consecutive schedulable periods.

---

## Timeline

A `Timeline` defines the complete temporal search space for a scheduling problem.

It contains the timeslots in which activities may be scheduled.

```python
from datetime import time

from pytimetable.temporal.timeline import TimelineBuilder


timeline = TimelineBuilder(
    days=5,
    start_time=time(7, 30),
    end_time=time(17, 0),
    period_minutes=50,
).build()
```

Applications can therefore define their scheduling calendar independently of the solver.

---

# Availability

Resources can specify when they are available.

For example:

```python
from pytimetable.temporal.availability import Availability


availability = Availability(
    timeline.timeslots
)
```

Availability can be associated with scheduling resources such as:

* participants
* facilitators
* venues

The scheduler uses this information when determining valid assignments.

---

# Requirements

Activities describe what they need through explicit requirements.

This keeps scheduling rules separate from application-specific concepts.

## Facilitator Requirement

An activity can specify how many facilitators it requires.

```python
FacilitatorRequirement(
    minimum=1,
    maximum=1,
)
```

The scheduler selects from the eligible facilitators associated with the event.

---

## Venue Requirement

An activity can specify venue requirements such as capacity and venue type.

```python
VenueRequirement(
    capacity=60,
    venue_type=computer_lab,
)
```

A compatible venue must satisfy those requirements.

---

## Timeslot Requirement

An activity can also describe temporal requirements.

```python
TimeslotRequirement()
```

Together with the timeline and availability information, timeslot requirements determine when an activity can be placed.

---

# Building Application Integrations

The Quick Start constructs PyTimetable objects directly.

That approach is useful for:

* learning the API
* tests
* scripts
* small scheduling applications
* domains already closely matching the PyTimetable model

Larger applications should normally keep their own domain model and adapt it to PyTimetable.

A university application, for example, might contain:

```text
Course
CourseComponent
Program
Student
Lecturer
Building
Room
CourseRegistration
```

These are application concepts and do not need to be replaced with PyTimetable classes.

Instead:

```text
University Domain
       │
       ▼
 ProblemAdapter
       │
       ▼
PyTimetable Problem
       │
       ▼
     Solver
       │
       ▼
PyTimetable Solution
       │
       ▼
 SolutionAdapter
       │
       ▼
University Timetable
```

This allows applications to use Django models, SQLAlchemy models, dataclasses, API objects, or any other data representation without coupling PyTimetable to them.

---

# Domain Context

`DomainContext` can be used by adapters to maintain relationships between application-domain objects and their PyTimetable equivalents.

Conceptually:

```text
Application                    PyTimetable

Lecturer        ←──────────→   Facilitator

Room            ←──────────→   Venue

CourseComponent ←──────────→   Activity
```

This becomes particularly useful after solving the problem.

A `SolutionAdapter` can use the same context to recover the application objects associated with each scheduling assignment.

```python
solution_adapter = SolutionAdapter(
    context=problem_adapter.context,
)

result = solution_adapter.adapt(
    solution
)
```

---

# Example: University Timetable

Consider a university course with three teaching components:

```text
Programming I

├── Lecture
│    ├── Duration: 2 periods
│    └── Venue type: Lecture Room
│
├── Lab
│    ├── Duration: 2 periods
│    └── Venue type: Computer Lab
│
└── Tutorial
     ├── Duration: 1 period
     └── Venue type: Tutorial Room
```

The university application can model these requirements explicitly:

```python
programming = Course(
    id=uuid4(),
    name="Programming I",
    components=(
        CourseComponent(
            name="Lecture",
            periods=2,
            venue_type=lecture_type,
        ),
        CourseComponent(
            name="Lab",
            periods=2,
            venue_type=lab_type,
        ),
        CourseComponent(
            name="Tutorial",
            periods=1,
            venue_type=tutorial_type,
        ),
    ),
)
```

The application's `ProblemAdapter` converts each course component into an `Activity`.

The component's venue requirement becomes a PyTimetable `VenueRequirement`.

Conceptually:

```text
CourseComponent
      │
      ├── periods
      └── venue_type
             │
             ▼
      ProblemAdapter
             │
             ▼
         Activity
             │
             ├── Duration
             └── VenueRequirement
                     │
                     ▼
                   Solver
                     │
                     ▼
             Compatible Venue
```

The resulting timetable might contain:

```text
Day         Time          Participant                  Course          Component   Venue
------------------------------------------------------------------------------------------------
Monday      12:30-14:20   Computer Science Y1 S1       Programming I   Lab         Computer Lab
Wednesday   08:30-09:20   Computer Science Y1 S1       Programming I   Tutorial    Tutorial Room
Friday      11:30-13:20   Computer Science Y1 S1       Programming I   Lecture     Lecture Room B
```

PyTimetable itself does not contain rules such as:

```python
if activity.name == "Lab":
    assign_computer_lab()
```

Instead, the activity declares a requirement for a particular venue type.

The generic scheduling engine is responsible only for satisfying that requirement.

---

# Feasibility

A timetable is **feasible** when all required hard scheduling constraints are satisfied.

Typical feasibility requirements include:

* no participant is assigned to overlapping activities
* no facilitator is assigned to overlapping activities
* no venue is double-booked
* assigned venues have sufficient capacity
* assigned venues satisfy venue-type requirements
* resources are available during their assignments
* activities fit within the timeline
* multi-period activities occupy valid consecutive periods

For example:

```text
Programming Lab
    ↓
VenueRequirement
    ↓
Computer Lab
```

is feasible if the assigned venue satisfies the activity's type, capacity, and availability requirements.

A feasible timetable is valid.

It is not necessarily a high-quality timetable.

---

# Timetable Quality

Once feasibility has been achieved, the schedule can be evaluated and optimized for quality.

Typical quality objectives include:

* minimizing participant gaps
* minimizing facilitator gaps
* limiting excessive consecutive teaching periods
* reducing venue changes
* reducing travel between locations
* distributing activities across the week
* avoiding undesirable times
* balancing resource utilization

These objectives may compete with each other.

For example, aggressively minimizing participant gaps may produce:

```text
09:00-10:00  Activity A
10:00-11:00  Activity B
11:00-12:00  Activity C
12:00-13:00  Activity D
```

This timetable has excellent compactness but potentially undesirable consecutive load.

A different timetable may reduce consecutive load while introducing gaps.

Scheduling quality is therefore an optimization problem rather than a single universal rule.

---

# Feasibility vs Optimization

PyTimetable separates two important concerns:

```text
                 Scheduling
                     │
          ┌──────────┴──────────┐
          │                     │
      Feasibility            Quality
          │                     │
     Hard constraints       Soft objectives
          │                     │
     Must be valid          Should be better
```

Hard constraints determine whether a schedule can be accepted.

Soft objectives distinguish between multiple feasible schedules.

This allows optimization algorithms to search for increasingly desirable solutions without compromising correctness.

---

# Architecture

At a high level, PyTimetable follows this architecture:

```text
┌─────────────────────────────────────┐
│          Application Domain         │
│                                     │
│ Courses, Students, Rooms, etc.      │
└──────────────────┬──────────────────┘
                   │
                   │ ProblemAdapter
                   ▼
┌─────────────────────────────────────┐
│          PyTimetable Problem        │
│                                     │
│ Activities                          │
│ Participants                        │
│ Facilitators                        │
│ Venues                              │
│ Timeline                            │
│ Requirements                        │
└──────────────────┬──────────────────┘
                   │
                   │ Solver
                   ▼
┌─────────────────────────────────────┐
│              Solution               │
│                                     │
│ Activity assignments                │
│ Timeslots                           │
│ Venues                              │
│ Facilitators                        │
└──────────────────┬──────────────────┘
                   │
                   │ SolutionAdapter
                   ▼
┌─────────────────────────────────────┐
│          Application Result         │
└─────────────────────────────────────┘
```

The application owns its business domain.

PyTimetable owns the scheduling problem.

The adapter boundary connects the two.

---

# Design Principles

## Domain Independent

PyTimetable should not know what a course, semester, curriculum, classroom, or university program is.

Those concepts belong to the application domain.

PyTimetable operates on generic scheduling concepts such as:

```text
Activity
Participant
Facilitator
Venue
Timeline
Requirement
Assignment
```

---

## Requirements Over Special Cases

Scheduling behaviour should be expressed through requirements and constraints rather than hard-coded domain rules.

Avoid:

```python
if activity.name == "Lab":
    use_computer_lab()
```

Prefer:

```text
Activity
   │
   └── VenueRequirement
            │
            └── VenueType: Computer Lab
```

The engine then satisfies the generic requirement.

---

## Explicit Domain Boundaries

Application models should not need to inherit from or depend directly on PyTimetable scheduling models.

Adapters provide the translation boundary.

This keeps both sides independently evolvable.

---

## Explicit Time Model

Days, periods, timeslots, durations, and timelines are explicit scheduling concepts rather than implicit integer conventions.

A period contains its real-world time range:

```text
Period 1 → 07:30-08:20
Period 2 → 08:30-09:20
Period 3 → 09:30-10:20
```

The scheduling engine can work efficiently with period numbers while applications can display actual times.

---

## Feasibility Before Quality

Correctness comes first.

Hard constraints establish feasibility.

Optimization then improves the quality of feasible solutions.

---

## Reproducibility

Randomized scheduling behaviour can be seeded:

```python
solution = Solver(
    seed=42,
).solve(
    problem
)
```

This makes development, testing, debugging, and performance comparisons reproducible.

---

## Composability

Scheduling concepts should remain small and composable.

Complex scheduling behaviour should emerge from combinations of:

```text
Activities
Resources
Requirements
Constraints
Objectives
Algorithms
```

rather than increasingly specialized domain-specific classes.

---

# Development

Clone the repository:

```bash
git clone https://github.com/briansimpo/pytimetable.git
cd pytimetable
```

Create a virtual environment:

```bash
python -m venv venv
```

Activate it.

Windows:

```powershell
.\venv\Scripts\Activate.ps1
```

Linux / macOS:

```bash
source venv/bin/activate
```

Install PyTimetable in editable mode:

```bash
pip install -e .
```

Run the university timetable example:

```bash
python -m examples.timetable
```

---

# Example Output

A generated university timetable may look like:

```text
Day         Time          Participant                        Course                      Component   Venue                    Lecturer

Monday      12:30-14:20   Computer Science Y1 S1             Programming I               Lab         Computer Lab             Dr Alan Turing
Tuesday     13:30-15:20   Information Technology Y1 S1       Programming I               Lab         Computer Lab             Dr Grace Hopper
Wednesday   07:30-08:20   Computer Science Y1 S1             Mathematics I               Tutorial    Tutorial Room            Dr Ada Lovelace
Wednesday   08:30-09:20   Computer Science Y1 S1             Programming I               Tutorial    Tutorial Room            Dr Alan Turing
Thursday    12:30-14:20   Information Technology Y1 S1       Academic Writing            Lecture     Lecture Room B           Dr Ada Lovelace
Thursday    14:30-15:20   Information Technology Y1 S1       Academic Writing            Tutorial    Tutorial Room            Dr Ada Lovelace
Thursday    15:30-16:20   Information Technology Y1 S1       Programming I               Tutorial    Tutorial Room            Dr Grace Hopper
Friday      07:30-09:20   Information Technology Y1 S1       Programming I               Lecture     Lecture Room A           Dr Grace Hopper
Friday      09:30-11:20   Computer Science Y1 S1             Mathematics I               Lecture     Lecture Room B           Dr Ada Lovelace
Friday      11:30-13:20   Computer Science Y1 S1             Programming I               Lecture     Lecture Room B           Dr Alan Turing
```

In this example:

* participant conflicts are avoided
* facilitator conflicts are avoided
* venues are not double-booked
* laboratories use compatible laboratory venues
* tutorials use compatible tutorial venues
* lectures use compatible lecture rooms
* multi-period activities occupy consecutive scheduling periods
* eligible facilitators are selected by the scheduler

Optimization can then improve qualities such as gaps, consecutive load, room changes, travel, and weekly distribution.

---

# Project Status

PyTimetable is under active development.

Current areas of development include:

* generic scheduling primitives
* timetable feasibility
* constraint evaluation
* timetable quality evaluation
* local-search optimization
* multi-objective optimization
* resource availability
* spatial and travel constraints
* reusable domain adapters

The public API may evolve while the architecture is being refined.

---

# Contributing

Contributions, bug reports, design discussions, and feature proposals are welcome.

When contributing, try to preserve PyTimetable's central design principle:

> **Application domains describe what must be scheduled. PyTimetable determines how to schedule it.**

Domain-specific behaviour should generally remain outside the scheduling kernel unless it can be expressed as a reusable scheduling concept.

---

# License

See the project license for details.
