Package: optapy
OptaPyOptaPy isan AI constraint solver for Pythonto 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 theOptaPlannerengine internally,
but using OptaPy in Python is significantly slower than using OptaPlanner in Java or Kotlin.Try the OptaPy Jupyter notebook.RequirementsInstall Python 3.9 or later.Install JDK 11 or laterwith the environment variableJAVA_HOMEconfigured to the JDK installation directory.Source code overviewDomainIn OptaPy, the domain has three parts:Problem Facts, which do not changePlanning Entities, which have one or more planning variablesPlanning Solution, which define the facts and entities of the problemProblem FactsTo declare Problem Facts, use the@problem_factdecoratorfromoptapyimportproblem_fact@problem_factclassTimeslot:def__init__(self,id,day_of_week,start_time,end_time):self.id=idself.day_of_week=day_of_weekself.start_time=start_timeself.end_time=end_timePlanning EntitiesTo declare Planning Entities, use the@planning_entitydecoratorfromoptapyimportplanning_entity,planning_id,planning_variable@planning_entityclassLesson:def__init__(self,id,subject,teacher,student_group,timeslot=None,room=None):self.id=idself.subject=subjectself.teacher=teacherself.student_group=student_groupself.timeslot=timeslotself.room=room@planning_iddefget_id(self):returnself.id@planning_variable(Timeslot,value_range_provider_refs=["timeslotRange"])defget_timeslot(self):returnself.timeslotdefset_timeslot(self,new_timeslot):self.timeslot=new_timeslot@planning_variable(Room,value_range_provider_refs=["roomRange"])defget_room(self):returnself.roomdefset_room(self,new_room):self.room=new_room@planning_variablemethod 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). Thevalue_range_provider_refsparameter tells OptaPlanner what value range providers on the Planning Solution this Planning Variable can take values from.@planning_idis 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 SolutionTo declare the Planning Solution, use the@planning_solutiondecoratorfromoptapyimportplanning_solution,problem_fact_collection_property,value_range_provider,planning_entity_collection_property,planning_score@planning_solutionclassTimeTable:def__init__(self,timeslot_list,room_list,lesson_list,score=None):self.timeslot_list=timeslot_listself.room_list=room_listself.lesson_list=lesson_listself.score=score@problem_fact_collection_property(Timeslot)@value_range_provider(range_id="timeslotRange")defget_timeslot_list(self):returnself.timeslot_list@problem_fact_collection_property(Room)@value_range_provider(range_id="roomRange")defget_room_list(self):returnself.room_list@planning_entity_collection_property(Lesson)defget_lesson_list(self):returnself.lesson_list@planning_score(HardSoftScore)defget_score(self):returnself.scoredefset_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 thevalue_range_provider_refsparameter of@planning_variable. It should also have a@problem_fact_collection_propertyor 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).ConstraintsYou define your constraints by using the ConstraintFactoryfromdomainimportLessonfromoptapyimportconstraint_providerfromoptapy.typesimportJoiners,HardSoftScore@constraint_providerdefdefine_constraints(constraint_factory):return[# Hard constraintsroom_conflict(constraint_factory),# Other constraints here...]defroom_conflict(constraint_factory):# A room can accommodate at most one lesson at the same time.returnconstraint_factory.for_each_unique_pair(Lesson,# ... in the same timeslot ...Joiners.equal(lambdalesson:lesson.timeslot),# ... in the same room ...Joiners.equal(lambdalesson:lesson.room))\.penalize("Room conflict",HardSoftScore.ONE_HARD)for more details on Constraint Streams, seehttps://www.optaplanner.org/docs/optaplanner/latest/constraint-streams/constraint-streams.htmlSolvefromoptapyimportsolver_factory_createfromoptapy.typesimportSolverConfig,Durationfromconstraintsimportdefine_constraintsfromdomainimportTimeTable,Lesson,generate_problemsolver_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())solutionwill be aTimeTableinstance with planning
variables set to the final best solution found.More informationFor quickstarts, visit theoptapy quickstart repository.
For a full API spec, visitthe OptaPy Documentation.