Optimisation avec Pyomo : un guide complet et pas à pas

L’optimisation est une outil fondamental utilisé dans diverses industries et disciplines pour prendre les meilleures décisions possibles dans des contraintes données. Que ce soit la minimisation des coûts dans un chaîne d’approvisionnement, la maximisation de l’efficacité dans les systèmes énergétiques ou la recherche des paramètres optimaux dans les modèles d’apprentissage automatique, les techniques d’optimisation sont essentielles.

Python, connu pour sa simplicité et sa polyvalence, offre d’importantes bibliothèques pour les problèmes d’optimisation. Parmi ces dernières, Pyomo se distingue en tant que bibliothèque complète et flexible qui permet aux utilisateurs de définir et de résoudre des modèles d’optimisation complexes de manière aisée.

Dans ce tutoriel, nous explorerons Pyomo depuis les fondamentaux. Nous couvrirons tout, depuis l’installation et la configuration des solveurs jusqu’à la formulation et la résolution de différents problèmes d’optimisation !

Exploration de solutions possibles dans le programme linéaire. Image de l’auteur.

Qu’est-ce que Pyomo ?

Pyomo est une bibliothèque open source pour la construction et la résolution de modèles d’optimisation utilisant Python. Elle permet de définir des modèles d’optimisation de manière mathématiquement rigoureuse et syntaxiquement intuitive pour les programmeurs Python. Elle permet de traiter une large gamme de types de problèmes, y compris :

  1. Le programme linéaire (LP): LP consiste à optimiser une fonction objectif linéaire soumise à des contraintes linéaires d’égalité et d’inegalité. Il est largement utilisé pour l’allocation de ressources, la planification des horaires et les problèmes de planification financière.
  2. Programmation non linéaire (PNL) : La PNL concerne l’optimisation d’une fonction objectif non linéaire avec des contraintes non linéaires. Elle est souvent utilisée en ingénierie et en économie pour des systèmes plus complexes où les relations ne sont pas linéaires.
  3. Programmation avec variables entières mixtes (PVM) : PVM implique des problèmes d’optimisation où certaines variables sont restreintes à être entières tandis que d’autres peuvent être continues. Cela est utile dans des scénarios tels que la conception des chaînes d’approvisionnement ou la planification de projets, où les décisions peuvent être discrètes (p. ex., allumé/éteint).
  4. Programmation stochastique: La programmation stochastique traite des problèmes d’optimisation où certaines composantes sont incertaines et sont modélisées comme des variables aléatoires. Elle est couramment appliquée aux domaines de la finance et de la gestion des chaînes d’approvisionnement pour optimiser les décisions effectuées sous incertitude.
  5. Optimisation dynamique : L’optimisation dynamique se concentre sur l’optimisation des variables de décision au fil du temps, ce qui implique généralement des systèmes évoluant dynamiquement. Elle est utilisée dans des domaines tels que la commande des processus, la robotique et l’économie pour gérer des processus temporellement dépendants.

Caractéristiques de Pyomo

Maintenant que nous comprenons mieux Pyomo, révisons certaines de ses fonctionnalités les plus importantes. 

Flexibilité et extensibilité

La flexibilité de Pyomo vient de sa capacité à modéliser des relations complexes en utilisant des constructions Python standard. Il s’intègre à divers solveurs open-source et commerciaux, ce qui facilite la résolution de nombreux problèmes d’optimisation.

Syntaxe Pythonique

Les modèles Pyomo sont construits sur Python et écrits en utilisant la syntaxe Python standard. Cela rend la courbe d’apprentissage douce pour ceux qui connaissent Python et permet d’utiliser les vastes bibliothèques de Python dans vos modèles.

Forte communauté et documentation

Pyomo dispose d’une communauté d’utilisateurs solide et d’une documentation complète, qui comprend des exemples et tutoriels pour aider les utilisateurs à tous les niveaux.

Cas d’utilisation pour Pyomo

Pyomo a un large éventail d’applications dans le monde réel. Voici quelques-uns d’entre eux :

1. Optimisation de la chaîne d’approvisionnement

Optimisation de la chaîne d’approvisionnement implique l’amélioration de la logistique, la gestion des niveaux d’inventaire et la création de programmes de production efficaces.

Cela peut inclure la minimisation des coûts de transport, l’optimisation des emplacements des entrepôts ou le maintien de l’équilibre entre l’offre et la demande.

Par exemple, une entreprise devraient répondre à la demande clientèle dans plusieurs régions tout en minimisant les coûts d’expédition et en maintenant des niveaux de stock à chaque centre de distribution.

2. Le modélisme financier

Dans le modélisme financier, l’optimisation permet d’allouer des ressources, telles que le capital, pour maximiser les rendements en minimisant le risque.

Cela peut impliquer l’optimisation du portefeuille, où les investisseurs équilibrent le risque et le gain en sélectionnant une combinaison d’actifs soumis à des contraintes telles que des limites de budget, des exigences réglementaires ou une tolérance au risque.

La modélisation financière garantit que les stratégies financières s’alignent sur des objectifs à long terme tout en atténuant les risques potentiels.

3. Systèmes énergétiques

L’optimisation dans les systèmes énergétiques se concentre sur la maximisation de la production, de la distribution et de l’efficacité de la consommation d’énergie.

Cela peut impliquer de déterminer le mélange optimal de sources d’énergie (par exemple, renouvelables vs non renouvelables) tout en minimisant les coûts de carburant, en respectant les limites d’émission et en s’adaptant à la demande fluctuante.

Ce type d’optimisation joue un rôle central dans la gestion du réseau, les opérations des centrales électriques et la réduction des impacts environnementaux.

4. Apprentissage automatique et science des données

L’optimisation est au cœur de nombreuses tâches d’apprentissage automatique et de science des données, telles que le réglage des hyperparamètres et la sélection des caractéristiques.

Dans l’ajustement des hyperparamètres, les algorithmes d’optimisation aident à trouver la meilleure configuration du modèle pour améliorer les performances prédictives.

La sélection des caractéristiques, une autre tâche critique, consiste à identifier les caractéristiques les plus importantes qui contribuent à la précision du modèle, aidant à réduire la complexité et à améliorer l’efficacité.

Maintenant que le contexte est mis en place, passons à la pratique et commençons à appliquer Pyomo à quelques exemples de problèmes de modélisation !

Configuration de Pyomo

Avant de plonger dans la modélisation, nous devons configurer notre environnement en installant Pyomo et en choisissant un résolveur approprié .

1. Préalables

Pour utiliser Pyomo, vous devez avoir Python 3.6 ou plus récent. Pyomo peut être installé à travers pip.

pip install pyomo

Ce tutoriel est créé en utilisant la version 6.8.0 de Pyomo.

import pyomo print(pyomo.__version__)

Sortie :

>>> 6.8.0

2. Choix et installation du bon solveur

Dans l’optimisation, les solveurs sont essentiels car ils sont les algorithmes qui trouvent la solution optimale au problème que vous avez défini. différents solveurs sont mieux adaptés selon le type de problème (par exemple, linéaire, non linéaire, entier). Pyomo est un outil de modélisation qui repose sur des solveurs externes pour effectuer les calculs réels.

Examinons quelques des solveurs les plus communs.

Solveurs open source

1. GLPK (GNU Linear Programming Kit)

GLPK est une importante bibliothèque de resolution de problèmes de programmation linéaire (LP) et de programmation linéaire mixte (MIP).

Elle constitue un excellent choix pour les tâches de base en optimisation linéaire et est largement utilisée dans les applications académiques et industrielles.

Installation

brew install glpk
  • Linux : 
sudo apt-get install glpk-utils
2. CBC (Coin-or Branch and Cut)

CBC est un solveur open source pour les problèmes de programmation linéaire (LP) et de programmation avec variables entières mixtes (MIP).

Il offre des fonctionnalités avancées et un meilleur rendement que GLPK dans certains cas, le rendant une excellente option pour les tâches d’optimisation plus complexes.

CBC peut être installé via le gestionnaire de paquets conda.

conda install -c conda-forge coincbc
3. IPOPT (Interior Point OPTimizer)

IPOPT est un solveur puissant conçu pour les problèmes de programmation non linéaire (NLP) de grande échelle.

Il est particulièrement adapté pour traiter des modèles non linéaires complexes, ce qui en fait un choix excellent pour les problèmes qui dépassent l’optimisation linéaire.

IPOPT peut être installé via le gestionnaire de paquets conda.

!conda install -c conda-forge ipopt

Resolveurs commerciaux

1. CPLEX

CPLEX est un résolveur d’optimisation de pointe qui traite efficacement les problèmes de programmation linéaire (LP), de programmation entière mixte (MIP) et de programmation quadratique (QP).

Il nécessite une licence d’IBM, mais est disponible gratuitement pour les utilisateurs académiques, ce qui en fait une excellente sélection pour la recherche et les fins éducatives.

2. Gurobi

Gurobi est un solveur commercial de premier plan connu pour sa vitesse et son efficacité dans la résolution de problèmes LP, MIP, QP et de programmation non linéaire (NLP).

Comme CPLEX, il nécessite une licence mais offre un accès gratuit aux utilisateurs académiques. Ainsi, il est un outil standard de l’industrie pour l’optimisation avancée.

Solveurs open-source vs. solveurs commerciaux

Les solveurs open-source tels que GLPK et CBC sont gratuits et suffisent pour la plupart des besoins de optimisation de base. Ils sont des choix excellents pour les projets de plus petite envergure et à des fins pédagogiques.

Cependant, les solveurs commerciaux tels que CPLEX et Gurobi offrent généralement de meilleures performances, en particulier pour les problèmes plus importants et plus complexes. Ces solveurs disposent de fonctionnalités avancées, notamment un support amélioré de programmation quadratique et non linéaire, et sont optimisés pour les applications industrielles de grande échelle.

Bien que les solveurs open-source puissent gérer de nombreuses tâches d’optimisation courantes, les solveurs commerciaux sont souvent un meilleur choix lorsque l’on doit traiter des exigences plus complexes et de hautes performances.

Notez que les solveurs commerciaux nécessitent une licence, bien qu’ils soient offerts gratuitement aux utilisateurs académiques.

Maintenant, voyons comment configurer un solveur dans Pyomo. J’utiliserais GLPK dans ce cas. 

3. Configurer un solveur dans Pyomo

Premièrement, veillez à ce que l’exécutable du solveur soit dans votre PATH système après l’installation.

Ensuite, créez un script Python et ajoutez ce qui suit :

from pyomo.environ import SolverFactory solver = SolverFactory('glpk')

Pour confirmer que Pyomo et votre solveur sont correctement installés, résolvons un problème de test simple.

Problème de test : programme linéaire simple.

Objectif : Minimiser Z=x+y

Sous réserve de :

  • x + 2y ≥ 4
  • x – y ≤ 1
  • x ≥ 0
  • y est égal ou supérieur à 0

Ce problème se rapporte à trouver la valeur la plus petite possible de Z, qui est la somme de deux variables, x et y. Cependant, x et y doivent remplir certaines conditions.

Premièrement, lorsque vous additionnez x et deux fois y, le résultat doit être d’au moins 4. Deuxièmement, x moins y doit être inférieur ou égal à 1. Enfin, les deux x et y doivent être des nombres nuls ou positifs (ils ne peuvent pas être négatifs). 

Le but est de trouver des valeurs de x et y qui satisfont ces conditions tout en minimisant Z le plus possible.

Implémenter en utilisant Pyomo :

import pyomo.environ as pyo # Créer un modèle model = pyo.ConcreteModel() # Définir des variables model.x = pyo.Var(within=pyo.NonNegativeReals) model.y = pyo.Var(within=pyo.NonNegativeReals) # Définir l'objectif model.obj = pyo.Objective(expr=model.x + model.y, sense=pyo.minimize) # Définir les contraintes model.con1 = pyo.Constraint(expr=model.x + 2 * model.y >= 4) model.con2 = pyo.Constraint(expr=model.x - model.y <= 1) # Sélectionner un solveur solver = pyo.SolverFactory('glpk') # Résoudre le problème result = solver.solve(model) # Afficher les résultats print('Status:', result.solver.status) print('Termination Condition:', result.solver.termination_condition) print('Optimal x:', pyo.value(model.x)) print('Optimal y:', pyo.value(model.y)) print('Optimal Objective:', pyo.value(model.obj))

Si tout fonctionne correctement, la sortie attendue sera :

Status: ok Termination Condition: optimal Optimal x: 0.0 Optimal y: 2.0 Optimal Objective: 2.0

Examinons le code ci-dessus : Premièrement, il définit deux variables, x et y, qui ne peuvent prendre que des valeurs non négatives. L’objectif du modèle est de minimiser la somme de x et y (x + y). Le code définit le solveur comme glpk pour trouver les valeurs optimales de x et y qui satisfont ces contraintes tout en minimisant l’objectif.

Après avoir exécuté le code, nous constatons que les valeurs optimales pour les variables sont x = 0.0 et y = 2.0, qui minimisent la fonction objectif Z = x + y. Par conséquent, la valeur minimale de la fonction objectif est 2.0, ce qui satisfait les contraintes données.

Principes de modélisation avec Pyomo

Comprendre comment définir les composants de base d’un modèle d’optimisation en Pyomo est nécessaire pour set up et résoudre des problèmes d’optimisation efficacement.

1. Définition des variables

Les variables représentent les décisions qui doivent être prises dans un problème d’optimisation. En Pyomo, les variables sont les quantités que le solveur ajustera pour optimiser la fonction objectif tout en satisfaisant toutes les contraintes.

Variables scalaires

Une variable scalaire est une seule variable qui n’est pas indexée sur aucun ensemble. Pour définir une variable scalaire en Pyomo, vous utilisez la classe Var du module pyomo.environ.

from pyomo.environ import Var model.x = Var()

Nous importons d’abord Var et créons une variable x en utilisant Var(). Cette variable n’a pas de bornes spécifiées, ce qui signifie qu’elle peut prendre n’importe quelle valeur réelle, à moins qu’elle ne soit contraintes autrement dans le modèle.

Ajout de bornes

Vous pouvez restreindre les valeurs qu’une variable peut prendre en spécifiant des bornes. Les bornes sont définies comme une paire (lower_bound, upper_bound) :

from pyomo.environ import Var model.x = Var(bounds=(0, None))

Définition de domaines

Pyomo fournit des domaines prédéfinis que vous pouvez utiliser pour spécifier le type de valeurs que peut prendre une variable, comme NonNegativeReals, Integers ou Binary :

from pyomo.environ import Var, NonNegativeReals model.x = Var(domain=NonNegativeReals)

Variables indexées

Lorsque vous traitez plusieurs variables similaires par nature, comme par exemple des variables représentant différentes périodes de temps ou des articles, il est efficient d’utiliser des variables indexées. Les variables indexées sont des variables définies sur un ensemble.

import pyomo.environ as pyo model.I = pyo.Set(initialize=[1, 2, 3]) model.y = pyo.Var(model.I, domain=pyo.NonNegativeReals)

Supposons que vous modélisiez les quantités de production pour trois produits. Vous pouvez définir :

model.Products = pyo.Set(initialize=['A', 'B', 'C']) model.production = pyo.Var(model.Products, domain=pyo.NonNegativeReals)

Maintenant, model.production['A'], model.production['B'] et model.production['C'] représentent respectivement les quantités de production des produits A, B et C.

2. Définition des objectifs

L’objectif de la fonction est ce que nous essayons d’optimiser (minimiser ou maximiser). Il définit l’objectif du modèle, comme minimiser les coûts ou maximiser les bénéfices, et est généralement exprimé comme une équation mathématique impliquant les variables de décision.

Ces derniers sont définis en utilisant la classe Objective :

from pyomo.environ import ConcreteModel, Var, Objective, minimize, maximize, NonNegativeReals # Créer un modèle model = ConcreteModel() # Définir les variables model.x = Var(within=NonNegativeReals) model.y = Var(within=NonNegativeReals) # Minimisation (coût) model.cost = Objective(expr=2 * model.x + 3 * model.y, sense=minimize) # Lors de la maximisation de bénéfices - (peut avoir un objectif à la fois) # model.profit = Objective(expr=5 * model.x + 4 * model.y, sense=maximize)

3. Ajout de contraintes

Les contraintes définissent les limitations ou les exigences du problème :

from pyomo.environ import Constraint model.con1 = Constraint(expr=model.x + model.y >= 10)

L’exemple ci-dessus définit une contrainte dans le modèle Pyomo en utilisant la classe Constraint. La contrainte model.con1 spécifie que la somme des variables x et y doit être supérieure ou égale à 10.

4. Paramétrisation des modèles

Les paramètres sont des valeurs fixes utilisées dans le modèle pour représenter des quantités connues ou des constantes qui ne changent pas pendant le processus d’optimisation.

Ils aident à définir les relations entre les variables et les contraintes, en donnant structure au modèle en intégrant des données ou des hypothèses du monde réel :

from pyomo.environ import Param model.p = Param(initialize=5)

Le code ci-dessus définit un paramètre p dans le modèle Pyomo en utilisant la classe Param et l’initialise avec une valeur fixe de 5. Le paramètre p peut maintenant être utilisé dans le modèle pour représenter une valeur constante qui ne change pas pendant le processus d’optimisation.

Maintenant, travaillons sur un problème d’optimisation de bout en bout !

Exemple de bout en bout avec Pyomo

Examinons un exemple de bout en bout de résolution d’un problème d’optimisation à l’aide de Pyomo. Nous modéliserons une scénario du monde réel où une usine produit deux produits, et l’objectif est de maximiser le profit en tenant compte des contraintes de temps de machine.

1. Énoncé du problème

Une usine produit deux produits, P1 et P2. Le bénéfice par unité est :

  • P1 : 40 $
  • P2: 50 $

Temps de machine disponible :

  • Machine A: 100 heures
  • Machine B: 80 heures
  • Machine C: 90 heures

Temps requis par unité :

Produit

Machine A (heures)

Machine B (heures)

Machine C (heures)

P1

1

2

0

P2

2

1

3

Objectif : Maximiser le profit.

Variables de décision:

  • x₁ : Unités de P1 à produire.
  • x₂: Unités de P2 à produire.

2. Formulation mathématique

Fonction objectif:

Maximiser Z = 40x₁ + 50x₂

Contraintes:

  1. Capacité de machine A : 1x₁ + 2x₂ ≤ 100
  2. Capacité de la machine B : 2x₁ + 1x₂ ≤ 80
  3. Capacité de la machine C : 3x₂ ≤ 90
  4. Non-négativité : x₁, x₂ ≥ 0

3. Mise en œuvre

En se basant sur l’objectif et les contraintes du problème, voici le code Python utilisé pour modéliser celui-ci, à nouveau, en utilisant GLPK.

# Étape 1 : Importation des bibliothèques import pyomo.environ as pyo # Étape 2 : Créer un modèle concret model = pyo.ConcreteModel() # Étape 3 : Définir les variables de décision (units de P1 et P2 à produire) model.x1 = pyo.Var(within=pyo.NonNegativeReals) model.x2 = pyo.Var(within=pyo.NonNegativeReals) # Étape 4 : Définir la fonction objectif (maximiser le profit) model.profit = pyo.Objective(expr=40 * model.x1 + 50 * model.x2, sense=pyo.maximize) # Étape 5 : Définir les contraintes # Contrainte de capacité de Machine A : 1x1 + 2x2 <= 100 model.machine_a = pyo.Constraint(expr=1 * model.x1 + 2 * model.x2 <= 100) # Contrainte de capacité de Machine B : 2x1 + 1x2 <= 80 model.machine_b = pyo.Constraint(expr=2 * model.x1 + 1 * model.x2 <= 80) # Contrainte de capacité de Machine C : 3x2 <= 90 model.machine_c = pyo.Constraint(expr=3 * model.x2 <= 90) # Étape 6 : Résoudre le modèle en utilisant l'optimiseur GLPK solver = pyo.SolverFactory('glpk') result = solver.solve(model) # Étape 7 : Analysez les résultats # Afficher l'état de l'optimiseur et les conditions de conclusion print('Solver Status:', result.solver.status) print('Termination Condition:', result.solver.termination_condition) # Obtenir et afficher les valeurs optimales pour x1, x2, et le maximum de profit x1_opt = pyo.value(model.x1) x2_opt = pyo.value(model.x2) profit_opt = pyo.value(model.profit) print(f'Optimal production of P1 (x1): {x1_opt}') print(f'Optimal production of P2 (x2): {x2_opt}') print(f'Maximum Profit: ${profit_opt}')

Sortie :

>>> Solver Status: ok >>> Termination Condition: optimal >>> Optimal production of P1 (x1): 25.0 >>> Optimal production of P2 (x2): 30.0 >>> Maximum Profit: $2500.0

Dans le code ci-dessus, nous définissons un modèle d’optimisation linéaire pour maximiser le bénéfice de la production de deux produits (P1 et P2). L’objectif du modèle est de maximiser le bénéfice, avec chaque unité de P1 contribuant 40 dollars et chaque unité de P2 contribuant 50 dollars.

Nous imposons trois contraintes représentant les limitations de temps de machine pour les Machines A, B, et C.

Enfin, nous utilisons le solveur GLPK pour résoudre le problème.

La réponse finale est de produire 25 unités de P1 et 30 unités de P2 où notre bénéfice maximum sera de 2 500 dollars.

Fonctionnalités avancées dans Pyomo

Dans la section précédente, nous avons vu quelle facilité il y a à implémenter un problème d’optimisation d’un bout à l’autre avec Pyomo. Cependant, la plupart des problèmes de la vie réelle ne sont pas aisés à résoudre.

Dans cette section, je présente quelques fonctionnalités avancées que vous pouvez utiliser pour résoudre des scénarios plus complexes.

1. Optimisation non linéaire

L’optimisation non linéaire minimise ou maximise une fonction objectif non linéaire soumise à des contraintes non linéaires. Voyons un exemple où nous minimisons la somme des carrés des différences sous une contrainte circulaire.

Énoncé du problème

Minimiser l’objectif :Z = (x – 1)² + (y – 2)²

Sujet à :

  • x² + y² ≤ 4
  • x, y ≥ 0

Dans Pyomo, nous pouvons définir les variables de décision x et y avec des bornes de 0 pour assurer une non-négativité. La fonction objectif est écrite sous forme de la somme des carrés des différences par rapport à des points spécifiques, et la contrainte assure que la solution se trouve dans un cercle de rayon 2.

Dans ce cas, l’ordinateur solver IPOPT est adapté pour ses capacités de résolution d’optimisation non linéaire :

import pyomo.environ as pyo model = pyo.ConcreteModel() # Définir des variables avec des bornes inférieures model.x = pyo.Var(bounds=(0, None)) model.y = pyo.Var(bounds=(0, None)) # Fonction objectif : minimiser (x - 1)² + (y - 2)² model.obj = pyo.Objective(expr=(model.x - 1)**2 + (model.y - 2)**2, sense=pyo.minimize) # Contrainte : x² + y² ≤ 4 (cercle d'un rayon de 2) model.circle = pyo.Constraint(expr=model.x**2 + model.y**2 <= 4) solver = pyo.SolverFactory('ipopt') result = solver.solve(model) print('Optimal x:', pyo.value(model.x)) print('Optimal y:', pyo.value(model.y)) print('Minimum Z:', pyo.value(model.obj))

2. Programmation mixte entière (PME)

La programmation mixte entière est utilisée lorsque certaines variables de décision sont des entiers ( souvent binaires) tandis que d’autres sont continues. Elle est utile pour les problèmes de décision tels que le choix de sites et la planification de production.

Énoncé du problème

Une entreprise doit décider s’il faut ouvrir des entrepôts dans les emplacements A, B, et C. L’objectif est de minimiser le coût total, qui inclut les coûts fixes de l’ouverture des entrepôts et les coûts de transport.

Nous commençons par initialiser les données, y compris les coûts fixes de l’ouverture des entrepôts, les coûts de transport, les limites de capacité et la demande totale :

locations = ['A', 'B', 'C'] FixedCost = {'A': 1000, 'B': 1200, 'C': 1500} TransportCost = {'A': 5, 'B': 4, 'C': 6} Capacity = {'A': 100, 'B': 80, 'C': 90} Demand = 150 model = pyo.ConcreteModel() # Variable binaire : 1 si l'entrepôt est ouvert, 0 sinon model.y = pyo.Var(locations, domain=pyo.Binary) # Variable continue : quantité de marchandises transportée model.x = pyo.Var(locations, domain=pyo.NonNegativeReals) model.cost = pyo.Objective( expr=sum(FixedCost[i] * model.y[i] + TransportCost[i] * model.x[i] for i in locations), sense=pyo.minimize ) # Contrainte de demande model.demand = pyo.Constraint(expr=sum(model.x[i] for i in locations) >= Demand) # Contraintes de capacité def capacity_rule(model, i): return model.x[i] <= Capacity[i] * model.y[i] model.capacity = pyo.Constraint(locations, rule=capacity_rule) solver = pyo.SolverFactory('cbc') result = solver.solve(model) for i in locations: print(f"Warehouse {i}: Open={pyo.value(model.y[i])}, Transported={pyo.value(model.x[i])}") print('Minimum Total Cost:', pyo.value(model.cost))

Le modèle comprend deux types de variables de décision : une variable binaire y représentant si un entrepôt est ouvert (1 si ouvert, 0 sinon), et une variable continue x représentant la quantité de marchandises transportées depuis chaque entrepôt.

L’objectif du fonctionnel est de sommer les coûts fixes et de transport de chaque entrepôt et de minimiser le total. Les contraintes s’assurent que le total des marchandises transportées répond à la demande et que la capacité de chaque entrepôt n’est pas dépassée si elle est ouverte.

3. Gestion de multiples objectifs

Parfois, les problèmes d’optimisation impliquent plusieurs objectifs qui peuvent être en conflit, comme maximiser le profit tout en minimisant l’impact environnemental. Une approche courante est la méthode de la somme pondérée, où chaque objectif est assigné un poids pour équilibrer son importance.

Énoncé du problème

Nous visons à maximiser les profits tout en minimaquant l’impact environnemental :

  • Profit :Z₁ = 3x + 5y
  • Impact environnemental :Z₂ = 2x + y

Nous pouvons combiner ces objectifs en utilisant des poids w1=0.6, w2=0.4, où l’objectif global devient une somme pondérée :

w1 = 0.6 w2 = 0.4 model.obj = pyo.Objective( expr=w1 * (3 * model.x + 5 * model.y) - w2 * (2 * model.x + model.y), sense=pyo.maximize )

Avec cet objectif combiné, nous maximisons les profits tout en minimaquant l’impact environnemental en ajustant les poids.

4. Utilisation de sources de données externes

Lorsqu’il s’agit de traiter de grands jeux de données, importer des données externes, telles que des fichiers CSV, est souvent utile. Pyomo fonctionne bien avec Pandas pour lire et utiliser des données externes.

Nous pouvons lire un fichier CSV à l’aide de Pandas et utiliser les données pour initialiser des ensembles et des paramètres dans notre modèle :

import pandas as pd data = pd.read_csv('parameters.csv') # Définir un ensemble à partir des données CSV model.I = pyo.Set(initialize=data['index'].unique()) # Définir un paramètre initialisé à partir des données CSV param_dict = data.set_index('index')['value'].to_dict() model.param = pyo.Param(model.I, initialize=param_dict)

Conseils et meilleures pratiques pour l’utilisation de Pyomo

Lorsque vous travaillez avec Pyomo, il est important de maintenir vos modèles efficaces, bien documentés et faciles à troubleshooter.

1. Débogage et troubleshooting

Lors de la construction de modèles d’optimisation en Pyomo, il est courant de rencontrer des problèmes tels que des solutions infeasibles, des échecs de résolution ou des résultats incorrects. Voici quelques meilleures pratiques pour le débogage :

  • Vérification des contraintes : Revoir vos contraintes si votre modèle ne produit pas une solution viable. Des contraintes trop rigides peuvent rendre un problème non viable. Utilisez la méthode .display() de Pyomo pour afficher les valeurs des variables et des contraintes pour vérifier qu’elles se comportent comme prévu.
  • Sortie du solveur : Activer les journaux détaillés du solveur en passant tee=True lors de l’appel de la méthode solve(). Cela peut fournir des informations sur les endroits où le solveur pourrait éprouver des difficultés, comme les variables non bornées ou l’infeasibilité.
  • Tester d’abord des modèles simples : Lorsque vous traitez des modèles complexes, testez une version simplifiée. Cela peut aider à isoler des problèmes potentiels sans l’overhead d’un modèle entièrement spécifié.

La détection des problèmes est beaucoup plus facile si vous le faites de manière systématique, en analysant les contraintes, la fonction objectif et les retours du solveur.

2. Efficacité du modélisme

Les problèmes d’optimisation peuvent devenir coûteux en calculs en fonction de la taille du modèle. Pour assurer une modélisation efficiente, considérez les conseils suivants :

  • Utiliser la sparcité : Évitez de boucler sur des indices non nécessaires lors de la définition des contraintes ou des objectifs. L’exploitation de la sparcité dans votre problème réduit le temps de calcul.
  • Variables binaires vs. continues : Dans la mesure du possible, réduisez le nombre de variables binaires ou entières. Les variables continues sont plus faciles pour les solveurs à traiter, ce qui conduit à des solutions plus rapides.
  • Formulation des contraintes : Gardez les contraintes aussi simples que possible, tant en forme mathématique qu’en implémentation. Évitez les non-linéarités non nécessaires et désagrégez les contraintes complexes en plus petites et plus gérables parties.

Les modèles efficaces résolvent plus rapidement et sont plus faciles à debugger et à maintenir.

3. Documentation et maintenance

Le maintien de modèles Pyomo bien documentés est une bonne pratique pour une utilisation à long terme et une collaboration. Une bonne documentation facilite également la révision et la mise à jour des modèles au fil du temps :

  • Utilisez des commentaires en ligne :Ajoutez toujours des commentaires pour expliquer l’objectif des variables, des contraintes et de la fonction objectif. Cela est particulièrement important dans les modèles d’optimisation où la logique peut ne pas être immédiatement évidente.
  • Modulez votre code : Divisez votre modèle en sections logiques ou même en fonctions distinctes. Cette approche modulaire peut améliorer la lisibilité et rendre plus facile la débuggage et la modification de parties spécifiques du modèle.
  • Gérez les modifications du modèle : Gardez un historique de versions de votre modèle, surtout s’il est en évolution. Utilisez des outils de gestion de version tels que Git pour suivre les modifications et assurez-vous que toutes les mises à jour ou améliorations peuvent être retracées.

Une documentation adéquate et un code structuré rendront vos modèles Pyomo plus accessibles à des collaborateurs futurs et plus faciles à élargir ou modifier selon vos besoins évolutifs.

Conclusion

Pyomo est une puissante et flexible outil pour construire et résoudre des modèles d’optimisation en Python. Au cours de ce didacticiel, nous avons exploré comment Pyomo permet aux utilisateurs de modéliser divers problèmes d’optimisation, allant de la programmation linéaire à la programmation non linéaire et la programmation mixte avec des entiers.

Avec sa syntaxe facile à utiliser et son intégration avec les solveurs, Pyomo rend la formulation et la résolution de problèmes d’optimisation du monde réel accessibles à des débutants et des utilisateurs avancés.

Si vous êtes intéressé à apprendre davantage à résoudre des problèmes du monde réel avec l’optimisation, consultez le cours gratuit Introduction à l’optimisation en Python sur DataCamp !

Source:
https://www.datacamp.com/tutorial/pyomo