Skip to main content

An AI constraint solver that optimizes planning and scheduling problems

Project description

OptaPy

PyPI Binder

Reliability Rating Security Rating Maintainability Rating Coverage

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

OptaPy wraps the OptaPlanner engine internally, but using OptaPy in Python is significantly slower than using OptaPlanner in Java or Kotlin.

Try the OptaPy Jupyter notebook.

Requirements

Source code overview

Domain

In OptaPy, 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

To declare Problem Facts, use the @problem_fact decorator

from optapy import problem_fact


@problem_fact
class Timeslot:
    def __init__(self, id, day_of_week, start_time, end_time):
        self.id = id
        self.day_of_week = day_of_week
        self.start_time = start_time
        self.end_time = end_time

Planning Entities

To declare Planning Entities, use the @planning_entity decorator

from optapy import planning_entity, planning_id, planning_variable

@planning_entity
class Lesson:
    def __init__(self, id, subject, teacher, student_group, timeslot=None, room=None):
        self.id = id
        self.subject = subject
        self.teacher = teacher
        self.student_group = student_group
        self.timeslot = timeslot
        self.room = room

    @planning_id
    def get_id(self):
        return self.id

    @planning_variable(Timeslot, value_range_provider_refs=["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

    def set_timeslot(self, new_timeslot):
        self.timeslot = new_timeslot

    @planning_variable(Room, value_range_provider_refs=["roomRange"])
    def get_room(self):
        return self.room

    def set_room(self, new_room):
        self.room = new_room
  • @planning_variable method decorators are used to indicate what fields can change. MUST begin with get and have a corresponding set method (i.e. get_room(self), set_room(self, newRoom)). The first parameter of the decorator is the type of the Planning Variable (required). The value_range_provider_refs parameter tells OptaPlanner what value range providers on the Planning Solution this Planning Variable can take values from.

  • @planning_id 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 optapy import planning_solution, problem_fact_collection_property, value_range_provider, planning_entity_collection_property, planning_score

@planning_solution
class TimeTable:
    def __init__(self, timeslot_list, room_list, lesson_list, score=None):
        self.timeslot_list = timeslot_list
        self.room_list = room_list
        self.lesson_list = lesson_list
        self.score = score

    @problem_fact_collection_property(Timeslot)
    @value_range_provider(range_id = "timeslotRange")
    def get_timeslot_list(self):
        return self.timeslot_list

    @problem_fact_collection_property(Room)
    @value_range_provider(range_id = "roomRange")
    def get_room_list(self):
        return self.room_list

    @planning_entity_collection_property(Lesson)
    def get_lesson_list(self):
        return self.lesson_list

    @planning_score(HardSoftScore)
    def get_score(self):
        return self.score

    def set_score(self, score):
        self.score = score
  • @value_range_provider(range_id) is used to indicate a method returns values a Planning Variable can take. It can be referenced by its id in the value_range_provider_refs parameter of @planning_variable. It should also have a @problem_fact_collection_property or a @planning_entity_collection_property.

  • @problem_fact_collection_property(type) is used to indicate a method returns Problem Facts. The first parameter of the decorator is the type of the Problem Fact Collection (required). It should be a list.

  • @planning_entity_collection_property(type) is used to indicate a method returns Planning Entities. The first parameter of the decorator is the type of the Planning Entity Collection (required). It should be a list.

  • @planning_score(scoreType) is used to tell OptaPlanner what field holds the score. The method MUST begin with get and have a corresponding set method (i.e. get_score(self), set_score(self, score)). The first parameter of the decorator is the score type (required).

Constraints

You define your constraints by using the ConstraintFactory

from domain import Lesson
from optapy import constraint_provider
from optapy.types import Joiners, HardSoftScore


@constraint_provider
def define_constraints(constraint_factory):
    return [
        # Hard constraints
        room_conflict(constraint_factory),
        # Other constraints here...
    ]

def room_conflict(constraint_factory):
    # 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("Room conflict", HardSoftScore.ONE_HARD)

for more details on Constraint Streams, see https://www.optaplanner.org/docs/optaplanner/latest/constraint-streams/constraint-streams.html

Solve

from optapy import solver_factory_create
from optapy.types import SolverConfig, Duration
from constraints import define_constraints
from domain import TimeTable, Lesson, generate_problem

solver_config = SolverConfig().withEntityClasses(Lesson) \
    .withSolutionClass(TimeTable) \
    .withConstraintProviderClass(define_constraints) \
    .withTerminationSpentLimit(Duration.ofSeconds(30))

solver = solver_factory_create(solver_config).buildSolver()
solution = solver.solve(generate_problem())

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

More information

For quickstarts, visit the optapy quickstart repository. For a full API spec, visit the OptaPy Documentation.

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

optapy-9.37.0b0.tar.gz (11.5 MB view details)

Uploaded Source

Built Distribution

optapy-9.37.0b0-py3-none-any.whl (26.2 MB view details)

Uploaded Python 3

File details

Details for the file optapy-9.37.0b0.tar.gz.

File metadata

  • Download URL: optapy-9.37.0b0.tar.gz
  • Upload date:
  • Size: 11.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.3

File hashes

Hashes for optapy-9.37.0b0.tar.gz
Algorithm Hash digest
SHA256 2ed8a084aa9c0b8093fa3509bef18d6bc0465ea69797ea4723ddc7188308869a
MD5 52928e397414b9faa42ddbc5f0131b52
BLAKE2b-256 45bafd6cc5cbc3552095510108321167a53edf888b42822e7145c795c8848693

See more details on using hashes here.

File details

Details for the file optapy-9.37.0b0-py3-none-any.whl.

File metadata

  • Download URL: optapy-9.37.0b0-py3-none-any.whl
  • Upload date:
  • Size: 26.2 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.3

File hashes

Hashes for optapy-9.37.0b0-py3-none-any.whl
Algorithm Hash digest
SHA256 e2df175e94b3dea9e7ddb8e468b1b2df2a06dacf2c1fe450f8098c8fd2f2cef5
MD5 2ecb0bffac057bce0fc688f4d856fe5e
BLAKE2b-256 2afc8c230fbb245ad75a025767826a5e21aea07ecc8eacb163a0a312decdf36d

See more details on using hashes here.

Supported by

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