OptaPy est un solveur de contraintes d'IA pour Python permettant d'optimiser le problème d'acheminement des véhicules, la liste des employés, la planification de la maintenance, l'affectation des tâches, l'horaire scolaire, l'optimisation du cloud, la planification des conférences, la planification des ateliers, l'emballage des bacs et bien d'autres problèmes de planification.
OptaPy enveloppe le moteur OptaPlanner en interne, mais l'utilisation d'OptaPy en Python est nettement plus lente que l'utilisation d'OptaPlanner en Java ou Kotlin.
Essayez le bloc-notes OptaPy Jupyter.
JAVA_HOME
configurée dans le répertoire d'installation du JDK. Dans OptaPy, le domaine comporte trois parties :
Pour déclarer des faits problématiques, utilisez le décorateur @problem_fact
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
Pour déclarer des entités de planification, utilisez le décorateur @planning_entity
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
Les décorateurs de méthode @planning_variable
sont utilisés pour indiquer quels champs peuvent changer. DOIT commencer par get et avoir une méthode set correspondante (c'est-à-dire get_room(self)
, set_room(self, newRoom)
). Le premier paramètre du décorateur est le type de variable de planification (obligatoire). Le paramètre value_range_provider_refs
indique à OptaPlanner de quelle plage de valeurs les fournisseurs de la solution de planification cette variable de planification peut prendre des valeurs.
@planning_id
est utilisé pour identifier de manière unique un objet entité d'une classe particulière. Le même identifiant de planification peut être utilisé sur des entités de classes différentes, mais les identifiants de toutes les entités d'une même classe doivent être différents.
Pour déclarer la solution de planification, utilisez le décorateur @planning_solution
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)
est utilisé pour indiquer qu'une méthode renvoie les valeurs qu'une variable de planification peut prendre. Il peut être référencé par son identifiant dans le paramètre value_range_provider_refs
de @planning_variable
. Il doit également avoir un @problem_fact_collection_property
ou un @planning_entity_collection_property
.
@problem_fact_collection_property(type)
est utilisé pour indiquer qu'une méthode renvoie des faits sur le problème. Le premier paramètre du décorateur est le type de collection de faits problématiques (obligatoire). Ce devrait être une liste.
@planning_entity_collection_property(type)
est utilisé pour indiquer qu'une méthode renvoie des entités de planification. Le premier paramètre du décorateur est le type de collection d'entités de planification (obligatoire). Ce devrait être une liste.
@planning_score(scoreType)
est utilisé pour indiquer à OptaPlanner quel champ contient le score. La méthode DOIT commencer par get et avoir une méthode set correspondante (c'est-à-dire get_score(self)
, set_score(self, score)
). Le premier paramètre du décorateur est le type de partition (obligatoire).
Vous définissez vos contraintes en utilisant 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 )
pour plus de détails sur les flux de contraintes, voir https://www.optaplanner.org/docs/optaplanner/latest/constraint-streams/constraint-streams.html
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
sera une instance TimeTable
avec des variables de planification définies sur la meilleure solution finale trouvée.
Pour des démarrages rapides, visitez le référentiel de démarrage rapide optapy. Pour une spécification complète de l'API, visitez la documentation OptaPy.