Ràng buộc lập trình Python

Các nhà phát triển Python hiện có thể giải quyết các vấn đề về lập kế hoạch AI (chẳng hạn như vấn đề định tuyến phương tiện và phân công nhân viên) bằng OptaPy. Hãy để tôi chỉ cho bạn cách sử dụng OptaPy và một chút mã Python đơn giản để giải quyết vấn đề tối ưu hóa toán học điển hình. tạo thời khóa biểu học tốt hơn cho giáo viên và học sinh. OptaPy là một dự án mã nguồn mở. Nó có sẵn trong PyPI và có thể sử dụng được từ bản cài đặt Python thông thường. Trong nội bộ, OptaPy sử dụng OptaPlanner, vì vậy nó cần cài đặt JDK. Hiện tại, nó chậm hơn đáng kể so với việc sử dụng OptaPlanner trực tiếp từ Java (hoặc Kotlin cho vấn đề đó), nhưng nó hoạt động và chúng tôi đang nghiên cứu các cách để thu hẹp khoảng cách về hiệu suất. Hãy tối ưu hóa thời gian biểu của trường đó bằng Python thuần túy. Vui lòng theo dõi trong sổ ghi chép OptaPy Jupyter

Ràng buộc lập trình Python

điều kiện tiên quyết

  • Trăn 3. 9 trở lên được cài đặt

  • JDK 11 trở lên được cài đặt với biến môi trường Java_HOME được định cấu hình cho thư mục cài đặt JDK

Cài đặt

  1. Tạo môi trường ảo Python mới

    python3 -m venv optapy-env

  2. Kích hoạt môi trường ảo Python

    source optapy-env/bin/activate

  3. Sử dụng pip để cài đặt OptaPy

    python3 -m pip install optapy

thời gian biểu của trường

Trong thời khóa biểu ở trường, chúng ta cần gán một danh sách các bài học cho các khoảng thời gian và phòng. Ngoài ra, có một số ràng buộc

  • Một phòng có thể có nhiều nhất một bài học cùng một lúc

  • Một giáo viên có thể dạy cùng một lúc nhiều nhất một tiết học

  • Một học sinh có thể tham dự nhiều nhất một buổi học cùng một lúc

  • Một giáo viên thích dạy tất cả các bài học trong cùng một phòng

  • Một giáo viên thích dạy các bài học theo trình tự và không thích khoảng cách giữa các bài học

  • Một học sinh không thích các bài học liên tiếp về cùng một chủ đề

Mô hình hóa miền

Các đối tượng được sử dụng trong các ràng buộc được gọi là miền của vấn đề. Trong thời gian biểu của trường, miền bao gồm các bài học, phòng và thời gian biểu

Sự kiện vấn đề

Sự thật vấn đề không thay đổi trong suốt quá trình giải quyết. Phòng và thời gian là ví dụ về sự thật của vấn đề. Tạo một tệp

source optapy-env/bin/activate
3 với đoạn mã sau để tạo lớp
source optapy-env/bin/activate
4

from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"

Trình trang trí

source optapy-env/bin/activate
5 đăng ký lớp như một sự thật của vấn đề, điều này cho phép nó được sử dụng trong các ràng buộc. Người trang trí
source optapy-env/bin/activate
6 đăng ký
source optapy-env/bin/activate
7 làm ID lập kế hoạch cho
source optapy-env/bin/activate
4. OptaPlanner yêu cầu ID lập kế hoạch cho một số chức năng, chẳng hạn như tạo các cặp duy nhất. ID lập kế hoạch phải là duy nhất cho các phiên bản của cùng một lớp

Bây giờ, trong

source optapy-env/bin/activate
3, hãy thêm đoạn mã sau để tạo lớp
python3 -m pip install optapy
0

@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )

Thực thể lập kế hoạch

Các thực thể lập kế hoạch thay đổi trong suốt quá trình giải quyết. Bài học là một thực thể lập kế hoạch, vì các thuộc tính

python3 -m pip install optapy
1 và
python3 -m pip install optapy
2 của nó thay đổi trong suốt quá trình giải. Vì các thuộc tính
python3 -m pip install optapy
1 và
python3 -m pip install optapy
2 thay đổi trong suốt quá trình giải nên chúng được gọi là các biến lập kế hoạch. Hãy thêm đoạn mã sau vào
source optapy-env/bin/activate
3 để tạo lớp
python3 -m pip install optapy
6

from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )

Trình trang trí

python3 -m pip install optapy
7 đăng ký lớp dưới dạng một thực thể lập kế hoạch, cho phép OptaPlanner gán các biến lập kế hoạch của nó và để nó được sử dụng trong các ràng buộc. Trình trang trí
python3 -m pip install optapy
8 đăng ký một phương thức làm phương thức nhận của một biến lập kế hoạch. Getter phải được đặt tên là
python3 -m pip install optapy
9 và setter phải được đặt tên là
from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
0. Đối số đầu tiên,
from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
1, cho OptaPlanner biết loại giá trị mà OptaPlanner có thể gán cho biến lập kế hoạch này. Đối số thứ hai,
from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
2, cho OptaPlanner biết phạm vi giá trị mà nó lấy giá trị từ. Chúng tôi sẽ giải thích phạm vi giá trị sau trong ví dụ này

Hạn chế

Các ràng buộc xác định phép tính điểm hoặc hàm thích nghi của một bài toán lập kế hoạch. Mỗi lời giải của bài toán quy hoạch được chấm điểm. Điểm thể hiện chất lượng của một giải pháp cụ thể. Điểm càng cao càng tốt. OptaPlanner tìm kiếm giải pháp tốt nhất, là giải pháp có số điểm cao nhất được tìm thấy trong thời gian khả dụng. Nó có thể hoặc không thể là giải pháp tối ưu

Vì trường hợp sử dụng này có các ràng buộc cứng và mềm, hãy sử dụng lớp HardSoftScore để biểu diễn điểm số

  • Các ràng buộc cứng không được phá vỡ. Ví dụ. Một phòng có thể có nhiều nhất một bài học cùng một lúc

  • Các ràng buộc mềm không nên bị phá vỡ. Ví dụ. Một giáo viên thích dạy trong một phòng đơn

Các ràng buộc cứng được tính trọng số so với các ràng buộc cứng khác. Các ràng buộc mềm cũng có trọng số, so với các ràng buộc mềm khác. Các ràng buộc cứng luôn lớn hơn các ràng buộc mềm, bất kể trọng số tương ứng của chúng

Để tính điểm, hãy tạo hàm cung cấp ràng buộc trong tệp

from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
3

from domain import Lesson, Room
from optapy import constraint_provider, get_class
from optapy.constraint import Joiners
from optapy.score import HardSoftScore

# Constraint Factory takes Java Classes, not Python Classes
LessonClass = get_class(Lesson)
RoomClass = get_class(Room)

@constraint_provider
def define_constraints(constraint_factory):
    return [
        # Hard constraints
        room_conflict(constraint_factory),
        teacher_conflict(constraint_factory),
        student_group_conflict(constraint_factory),
        # Soft constraints are only implemented in the optapy-quickstarts code
    ]

def room_conflict(constraint_factory):
    # A room can accommodate at most one lesson at the same time.
    return constraint_factory \
            .forEach(LessonClass) \
            .join(LessonClass,
                [
                    # .. in the same timeslot ...
                    Joiners.equal(lambda lesson: lesson.timeslot),
                    # .. in the same room ...
                    Joiners.equal(lambda lesson: lesson.room),
                    # .. and the pair is unique (different id, no reverse pairs) ...
                    Joiners.lessThan(lambda lesson: lesson.id)
                ]) \
            .penalize("Room conflict", HardSoftScore.ONE_HARD)


def teacher_conflict(constraint_factory):
    # A teacher can teach at most one lesson at the same time.
    return constraint_factory \
                .forEach(LessonClass)\
                .join(LessonClass,
                        [
                            Joiners.equal(lambda lesson: lesson.timeslot),
                            Joiners.equal(lambda lesson: lesson.teacher),
                    Joiners.lessThan(lambda lesson: lesson.id)
                        ]) \
                .penalize("Teacher conflict", HardSoftScore.ONE_HARD)

def student_group_conflict(constraint_factory):
    # A student can attend at most one lesson at the same time.
    return constraint_factory \
            .forEach(LessonClass) \
            .join(LessonClass,
                [
                    Joiners.equal(lambda lesson: lesson.timeslot),
                    Joiners.equal(lambda lesson: lesson.student_group),
                    Joiners.lessThan(lambda lesson: lesson.id)
                ]) \
            .penalize("Student group conflict", HardSoftScore.ONE_HARD)

Trình trang trí

from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
4 cho phép OptaPlanner sử dụng một chức năng làm trình cung cấp ràng buộc. Hàm phải nhận chính xác một đối số; . Để biết thêm thông tin, hãy xem trong tài liệu OptaPlanner

Tập hợp các đối tượng miền trong một giải pháp lập kế hoạch

Một lớp TimeTable bao bọc tất cả các phiên bản Khe thời gian, Phòng và Bài học của một tập dữ liệu. Hơn nữa, vì nó chứa tất cả các bài học, mỗi bài học có một trạng thái biến lập kế hoạch cụ thể nên lớp TimeTable là một giải pháp lập kế hoạch và có điểm số

  • Nếu các bài học vẫn chưa được gán, thì đó là một giải pháp chưa được khởi tạo, ví dụ: một giải pháp có điểm -4init/0hard/0soft

  • Nếu nó phá vỡ các ràng buộc cứng, thì đó là một giải pháp không khả thi, ví dụ, một giải pháp có điểm -2hard/-3soft

  • Nếu nó tuân thủ tất cả các ràng buộc cứng, thì đó là một giải pháp khả thi, ví dụ: một giải pháp có điểm số 0hard/-7soft

Trong

source optapy-env/bin/activate
3, hãy thêm đoạn mã sau để tạo lớp
from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
7

from optapy import planning_solution, planning_entity_collection_property, \
                   problem_fact_collection_property, \
                   value_range_provider, planning_score
from optapy.score import HardSoftScore

def format_list(a_list):
    return ',\n'.join(map(str, a_list))

@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("timeslotRange")
    def get_timeslot_list(self):
        return self.timeslot_list

    @problem_fact_collection_property(Room)
    @value_range_provider("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

    def __str__(self):
        return (
            f"TimeTable("
            f"timeslot_list={format_list(self.timeslot_list)},\n"
            f"room_list={format_list(self.room_list)},\n"
            f"lesson_list={format_list(self.lesson_list)},\n"
            f"score={str(self.score.toString()) if self.score is not None else 'None'}"
            f")"
        )

Trình trang trí

from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
8 nói với OptaPlanner rằng lớp
from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
7 chứa dữ liệu đầu vào và đầu ra. Trình trang trí
@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
0 cho OptaPlanner biết chức năng cung cấp thông tin về vấn đề. Đối số
@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
1 cho OptaPlanner biết loại dữ kiện mà nó cung cấp (ví dụ: Phòng)

Trình trang trí

@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
2 cho OptaPlanner biết hàm cung cấp một phạm vi giá trị, được sử dụng để nhận các giá trị có thể có của các biến lập kế hoạch. Đối số của nó,
@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
3 là một chuỗi được sử dụng trong trang trí
@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
4 để liên kết cả hai (ví dụ:
@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
5 được liên kết với
@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
6

Trình trang trí

@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
7 cho OptaPlanner biết chức năng cung cấp các thực thể lập kế hoạch. Đối số
@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
8 cho OptaPlanner biết loại thực thể mà nó cung cấp (ví dụ: Bài học)

Trình trang trí

@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_id
    def get_id(self):
        return self.id

    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
9 cho OptaPlanner biết hàm trả về điểm số. Nó phải được đặt tên là
python3 -m pip install optapy
9 và có một setter tương ứng là
from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
0. Đối số
from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
2 cho OptaPlanner biết loại điểm sẽ sử dụng (ví dụ:
from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
3). Loại nên được lấy từ mô-đun
from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
4

giải quyết

Để giải quyết, trước tiên chúng ta cần tạo một thể hiện của vấn đề. Thêm đoạn mã sau vào

source optapy-env/bin/activate
3

from datetime import time

def generate_problem():
    timeslot_list = [
        Timeslot(1, "MONDAY", time(hour=8, minute=30), time(hour=9, minute=30)),
        Timeslot(2, "MONDAY", time(hour=9, minute=30), time(hour=10, minute=30)),
        Timeslot(3, "MONDAY", time(hour=10, minute=30), time(hour=11, minute=30)),
        Timeslot(4, "MONDAY", time(hour=13, minute=30), time(hour=14, minute=30)),
        Timeslot(5, "MONDAY", time(hour=14, minute=30), time(hour=15, minute=30)),
        Timeslot(6, "TUESDAY", time(hour=8, minute=30), time(hour=9, minute=30)),
        Timeslot(7, "TUESDAY", time(hour=9, minute=30), time(hour=10, minute=30)),
        Timeslot(8, "TUESDAY", time(hour=10, minute=30), time(hour=11, minute=30)),
        Timeslot(9, "TUESDAY", time(hour=13, minute=30), time(hour=14, minute=30)),
        Timeslot(10, "TUESDAY", time(hour=14, minute=30), time(hour=15, minute=30)),
    ]
    room_list = [
        Room(1, "Room A"),
        Room(2, "Room B"),
        Room(3, "Room C")
    ]
    lesson_list = [
        Lesson(1, "Math", "A. Turing", "9th grade"),
        Lesson(2, "Math", "A. Turing", "9th grade"),
        Lesson(3, "Physics", "M. Curie", "9th grade"),
        Lesson(4, "Chemistry", "M. Curie", "9th grade"),
        Lesson(5, "Biology", "C. Darwin", "9th grade"),
        Lesson(6, "History", "I. Jones", "9th grade"),
        Lesson(7, "English", "I. Jones", "9th grade"),
        Lesson(8, "English", "I. Jones", "9th grade"),
        Lesson(9, "Spanish", "P. Cruz", "9th grade"),
        Lesson(10, "Spanish", "P. Cruz", "9th grade"),
        Lesson(11, "Math", "A. Turing", "10th grade"),
        Lesson(12, "Math", "A. Turing", "10th grade"),
        Lesson(13, "Math", "A. Turing", "10th grade"),
        Lesson(14, "Physics", "M. Curie", "10th grade"),
        Lesson(15, "Chemistry", "M. Curie", "10th grade"),
        Lesson(16, "French", "M. Curie", "10th grade"),
        Lesson(17, "Geography", "C. Darwin", "10th grade"),
        Lesson(18, "History", "I. Jones", "10th grade"),
        Lesson(19, "English", "P. Cruz", "10th grade"),
        Lesson(20, "Spanish", "P. Cruz", "10th grade"),
    ]
    lesson = lesson_list[0]
    lesson.set_timeslot(timeslot_list[0])
    lesson.set_room(room_list[0])

    return TimeTable(timeslot_list, room_list, lesson_list)

Tiếp theo, chúng ta cần tạo một

from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
6, cho OptaPlanner biết về vấn đề và các chiến lược sẽ sử dụng. Trong
from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
7, thêm đoạn mã sau

from domain import Lesson, TimeTable, generate_problem
from constraints import define_constraints
from optapy import get_class
import optapy.config
from optapy.types import Duration

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

Đối với

from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
6 ở trên, chúng tôi sử dụng các chiến lược mặc định, sử dụng mô hình mà chúng tôi đã xác định ở trên và đặt nó kết thúc sau 30 giây

Cuối cùng, chúng tôi chuyển

from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
6 và trường hợp vấn đề cho hàm
from domain import Lesson, Room
from optapy import constraint_provider, get_class
from optapy.constraint import Joiners
from optapy.score import HardSoftScore

# Constraint Factory takes Java Classes, not Python Classes
LessonClass = get_class(Lesson)
RoomClass = get_class(Room)

@constraint_provider
def define_constraints(constraint_factory):
    return [
        # Hard constraints
        room_conflict(constraint_factory),
        teacher_conflict(constraint_factory),
        student_group_conflict(constraint_factory),
        # Soft constraints are only implemented in the optapy-quickstarts code
    ]

def room_conflict(constraint_factory):
    # A room can accommodate at most one lesson at the same time.
    return constraint_factory \
            .forEach(LessonClass) \
            .join(LessonClass,
                [
                    # .. in the same timeslot ...
                    Joiners.equal(lambda lesson: lesson.timeslot),
                    # .. in the same room ...
                    Joiners.equal(lambda lesson: lesson.room),
                    # .. and the pair is unique (different id, no reverse pairs) ...
                    Joiners.lessThan(lambda lesson: lesson.id)
                ]) \
            .penalize("Room conflict", HardSoftScore.ONE_HARD)


def teacher_conflict(constraint_factory):
    # A teacher can teach at most one lesson at the same time.
    return constraint_factory \
                .forEach(LessonClass)\
                .join(LessonClass,
                        [
                            Joiners.equal(lambda lesson: lesson.timeslot),
                            Joiners.equal(lambda lesson: lesson.teacher),
                    Joiners.lessThan(lambda lesson: lesson.id)
                        ]) \
                .penalize("Teacher conflict", HardSoftScore.ONE_HARD)

def student_group_conflict(constraint_factory):
    # A student can attend at most one lesson at the same time.
    return constraint_factory \
            .forEach(LessonClass) \
            .join(LessonClass,
                [
                    Joiners.equal(lambda lesson: lesson.timeslot),
                    Joiners.equal(lambda lesson: lesson.student_group),
                    Joiners.lessThan(lambda lesson: lesson.id)
                ]) \
            .penalize("Student group conflict", HardSoftScore.ONE_HARD)
0, hàm này trả về giải pháp tốt nhất cuối cùng được tìm thấy. Thêm đoạn mã sau vào
from optapy import planning_entity, 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, ["timeslotRange"])
    def get_timeslot(self):
        return self.timeslot

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

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

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
7

source optapy-env/bin/activate
0

Giải pháp được trả về là một trường hợp

from optapy import problem_fact, planning_id

@problem_fact
class Room:
    def __init__(self, id, name):
        self.id = id
        self.name = name

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

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"
7 của giải pháp tốt nhất được tìm thấy. Khi giải pháp được định dạng thành một bảng, nó sẽ trông giống như thế này

source optapy-env/bin/activate
1

Chạy ứng dụng

Để chạy ứng dụng, hãy thực thi tệp chính

source optapy-env/bin/activate
2

Phần kết luận

Với OptaPy, các nhà phát triển Python hiện có thể sử dụng OptaPlanner bằng mã Python đơn giản (không cần mã Java). Ví dụ đầy đủ có thể được tìm thấy trong khởi động nhanh OptaPy

Các ràng buộc trong Python là gì?

Ràng buộc python là gì? . a module implementing support for handling CSPs (Constraint Solving Problems) over finite domain.

Lập trình ràng buộc nghĩa là gì?

Tối ưu hóa ràng buộc hoặc lập trình ràng buộc (CP) là tên được đặt để xác định các giải pháp khả thi trong số rất nhiều ứng viên, trong đó vấn đề có thể được mô hình hóa dưới dạng . Các vấn đề về CP nảy sinh trong nhiều ngành khoa học và kỹ thuật. . CP problems arise in many scientific and engineering disciplines.

Là hạn chế lập trình trí tuệ nhân tạo?

Lập trình ràng buộc là một công nghệ thỏa mãn bản địa bắt nguồn từ khoa học máy tính—lập trình logic, lý thuyết đồ thị và các nỗ lực trí tuệ nhân tạo của những năm 1980

Ràng buộc Lập trình logic được sử dụng để làm gì?

Lập trình ràng buộc là một phương pháp giải các bài toán có tính tổ hợp cao dựa trên mô tả bài toán khai báo và một công cụ truyền bá ràng buộc chung .