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
điều kiện tiên quyết
Cài đặt
-
Tạo môi trường ảo Python mới
python3 -m venv optapy-env
-
Kích hoạt môi trường ảo Python
source optapy-env/bin/activate
-
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 đượ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ì?
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 .