Optimisation de la planification de la production à l'aide de la programmation linéaire (Python + PuLP)

introduction

La programmation mathématique est une méthode de maximisation (minimisation) d'une valeur cible appelée fonction objectif sous une certaine contrainte. Parmi eux, la programmation linéaire (LP) signifie que la fonction objectif et l'expression de contrainte peuvent être exprimées par une expression linéaire (une expression de la forme $ \ sum_ia_ix_i + b $) liée à la variable. La programmation linéaire est l'une des programmations mathématiques les plus simples, mais elle dispose d'une riche bibliothèque pour les solveurs et la modélisation, offrant un environnement facile à utiliser. En particulier, je pense que les entreprises optimisent souvent des variables contrôlables telles que le volume de production et le volume de transport en utilisant des indicateurs monétaires tels que le profit et le coût comme fonctions objectives.

Dans cet article, à partir des livres suivants qui résument les techniques de modélisation de l'optimisation mathématique, un exercice est sorti et effectivement formulé, et il est implémenté dans PuLP, qui est un langage de modélisation de Python, pour trouver la solution optimale. J'aimerais venir.

Model Building in Mathematical Programming https://www.amazon.co.jp/dp/1118443330/

Cet exercice est destiné aux devoirs de lecture effectués dans Groupe d'optimisation mathématique de TFUG. C'est un. Tout le monde peut rejoindre le groupe TFUG, donc si vous êtes intéressé, vous voudrez peut-être jeter un œil à Slack!

Cet article a la structure suivante. Tout d'abord, nous expliquerons brièvement comment modéliser, puis présenterons la définition du problème de l'exemple et effectuerons la modélisation, la mise en œuvre et la vérification.

--Modélisation du flux

Il y a une section en colonne au milieu, donc vous pouvez l'ignorer, mais j'écris sur un sujet que je trouve personnellement intéressant, alors veuillez le lire.

Modélisation du flux

En général, pour modéliser un plan mathématiquement, vous devez définir deux choses:

  1. Fonction objective
  2. Expression de contrainte

Prenons l'exemple du plan de production d'une usine. Tout d'abord, la fonction objectif représente le coût ou l'avantage que vous souhaitez optimiser. Par exemple, lors de la production dans les usines A et B, supposons que le coût de production puisse être exprimé comme suit: $ \ text {Coût de production} = \ sum_ {i \ in \\ {A, B \\}} \ text {Prix unitaire de production} \ _ i \ times \ text {Volume de production} \ _ i. $ Dans ce cas, il semble que les coûts de production puissent être maintenus bas en réduisant le volume de production des usines à prix de production unitaires élevés et en augmentant le volume de production des usines à prix unitaires de production bas. Cependant, cette formule ne peut pas à elle seule trouver la solution optimale que vous voulez vraiment trouver. En effet, il n'y a aucune restriction selon laquelle "vous devez produire plus de XX", donc si vous essayez de minimiser le coût de production, la solution optimale est de ne pas produire du tout.

Donc, ensuite, en tant qu'expression de contrainte, nous imposons une condition à la variable pour éviter une telle situation. Par exemple, la contrainte «vous devez produire plus de XX» mentionnée précédemment peut être exprimée comme suit. $ \ sum_ {i \ in \\ {A, B \\}} \ text {Production} \ _ i \ geq \ text {Demande}. $

De plus, s'il s'agit d'un plan de production, il y a souvent une limite à la capacité de production de l'usine, et il y a souvent une limite supérieure sur le volume de production. Une expression de contrainte exprime ces restrictions et règles métier sous la forme d'une formule mathématique.

De plus, les informations suivantes sont nécessaires pour définir la fonction objectif et l'expression de contrainte.

--Réunion

Si vous voulez réellement modéliser à partir de zéro, personnellement, je pense qu'il est préférable de viser d'abord à définir la fonction objectif. Lorsque vous essayez de définir une fonction objectif, il est nécessaire d'organiser les informations nécessaires dans le processus, ce qui conduit à la détermination d'ensembles, de paramètres et de variables. Ensuite, pour chaque variable, identifiez les contraintes nécessaires et exprimez-les une par une sous forme d'expressions.

Dans ce qui suit, nous présenterons la définition du problème de l'exemple et le modéliserons réellement.

Définition du problème: fabrication d'aliments 1

Cette fois, nous traiterons des plans de production alimentaire. Plus précisément, de janvier à juin, on dit que la nourriture se fait en achetant chaque mois de l'huile comme matière première, en la raffinant et en la mélangeant (margarine ou quelque chose du genre ...?). Dans ce plan de production, nous visons à maximiser les profits à la fin en ajustant le montant d'achat et la quantité de consommation de chaque huile de matière première chaque mois.

Dans ce numéro, pour réfléchir aux fonctions objectives et aux expressions de contraintes, nous devons considérer les coûts et les contraintes liés aux facteurs suivants.

--Inventaire --Achat --Purification

J'expliquerai chaque situation en détail.

Stock

Les stocks cohésifs d'huile augmentent avec les nouveaux achats et diminuent avec la consommation dans la production alimentaire.

Chaque matière première peut être conservée en stock pour un maximum de 1 000 $ [t] $. Cependant, il y a un coût de stockage de 5 $ [£ / t] $ par mois.

De plus, pour toute source d'huile, l'inventaire commence à 500 $ [t] $ et se termine à 500 $ [t] $ ou plus.

achat

Les huiles ci-dessus seront achetées de janvier à juin aux prix unitaires suivants.

Mois VEG 1 VEG 2 OIL 1 OIL 2 OIL 3
Jan 110 120 130 110 115
Feb 130 130 110 90 115
Mar 110 140 130 100 95
Apr 120 110 120 120 125
May 100 120 150 110 105
Jun 90 100 140 80 135

Il n'y a pas de restrictions particulières sur le montant qui peut être acheté.

purification

De la quantité achetée et de la quantité initialement en stock, une certaine quantité est soumise au processus de purification. Dans le processus de purification, il n'y aura pas de perte particulière et le coût de la purification sera négligeable.

Il existe deux types d'huiles brutes, végétales et non végétales, et le processus de raffinage serait effectué sur des lignes de raffinage différentes pour chaque type d'huile. La limite supérieure de la quantité de purification est fixée comme suit.

type Limite supérieure de la quantité de purification[t/Mois]
Botanique 200
Non végétal 250

En outre, les types d'huile de matière première sont les suivants.

Nom type
VEG 1 Botanique
VEG 2 Botanique
OIL 1 Non végétal
OIL 2 Non végétal
OIL 3 Non végétal

mélange

En mélangeant toutes les huiles raffinées, la nourriture à expédier ce mois-là est terminée. Encore une fois, aucune perte ne se produit, de sorte que le poids total de l'huile brute mélangée est la quantité de nourriture produite.

De plus, chaque huile de matière première a la dureté indiquée dans le tableau ci-dessous. La dureté de l'aliment produit est moyennée en fonction de la consommation d'huile de matière première, et la dureté de l'aliment doit être comprise entre 3 $ et 6 $.

Nom dureté
VEG1 8.8
VEG2 6.1
OIL1 2.0
OIL2 4.2
OIL3 5.0

Vente

Il semble que la nourriture produite puisse être épuisée dans le mois. En d'autres termes, le volume de production devient le volume des ventes tel qu'il est. Le prix de vente unitaire est fixé à 150 $ [£ / t] $ quel que soit le mois.

Modélisation: Fabrication alimentaire 1

À partir de maintenant, nous modéliserons en fait le paramètre de problème expliqué précédemment. De plus, j'ai écrit plus tôt que "il est préférable de décider de l'ensemble et des paramètres tout en définissant la fonction objectif", mais dans l'explication, il est plus facile d'écrire d'abord l'ensemble, les paramètres et les variables, donc je le fais. ..

ensemble

Dans un modèle d'optimisation mathématique, un ensemble est un indice d'un paramètre ou d'une variable. Pour ce numéro, nous examinerons les quatre ensembles suivants:

** Huile brute ** $ \text{OILS} = \\{\text{VEG1}, \text{VEG2}, \text{OIL1}, \text{OIL2}, \text{OIL3}\\}. $

** Période cible (mois) ** $ \text{TIME_IDX} = \\{1, \ldots, 6 \\}. $

** Ligne de purification ** $ \text{REF\_LINES} = \\{\text{VEG}, \text{NONVEG} \\}. $

** Objectif de purification ** Puisqu'il est défini pour chaque ligne de purification, il s'agit d'un ensemble d'ensembles (famille d'ensembles) dans son ensemble. $ \text{USED_OILS} = \\{\text{USED_OILS}\_{VEG}, \text{USED_OILS}\_{NONVEG}\\}. $ L'ensemble du contenu de chaque ligne de purification est $ \begin{aligned} \text{USED_OILS}\_{VEG} &= \\{\text{VEG1}, \text{VEG2}, \text{VEG3}\\}, \\\ \text{USED_OILS}\_{NONVEG} &= \\{\text{OIL1}, \text{OIL2}\\}. \end{aligned} $

Je le donne ici, mais gardez à l'esprit que la façon dont les ensembles sont définis n'est pas unique. Selon la manière dont l'ensemble est défini, la polyvalence du modèle peut être réduite. Cela sera discuté plus en détail dans la section Expressions de contraintes.

Paramètres

Ensuite, nous définirons les paramètres utilisés pour calculer la fonction objectif et l'expression de contrainte.

Nom Indice Plage de valeurs La description
\text{buy\_uc} \text{OILS}
\text{TIME_IDX}
[0, +\infty) Prix unitaire d'achat de l'huile de matière première.
\text{stock\_uc} - [0, +\infty) Prix unitaire de stockage de l'huile de matière première.
\text{sell\_uc} - [0, +\infty) Prix de vente unitaire de la nourriture.
\text{stock_init} \text{OILS} [0, +\infty) Stock initial d'huile de matière première.
\text{stock_final_lb} \text{OILS} [0, +\infty) La limite inférieure du stock final d'huile de matière première.
\text{stock\_ub} - [0, +\infty) Limite supérieure du stock d'huile de matière première.
\text{hardness} \text{OILS} [0, +\infty) La dureté de l'huile de matière première.
\text{ref\_ub} \text{REF\_LINES} [0, +\infty) Limite supérieure de la quantité de purification.

uc est une abréviation de coût unitaire, qui signifie prix unitaire, et lb / ub est une abréviation de limite inférieure / supérieure, respectivement, qui signifie limites supérieure et inférieure.

variable

De même, définissez les variables à optimiser. Il est souhaitable d'utiliser la nomenclature pour les noms de variables, mais si elle est trop longue, l'expression sera difficile à lire, donc certains verbes sont utilisés.

Nom Indice Plage de valeurs La description
\text{buy} \text{OILS}
\text{TIME_IDX}
[0, +\infty) Achetez la quantité d'huile de matière première.
\text{use} \text{OILS}
\text{TIME_IDX}
[0, +\infty) Quantité d'huile de matière première utilisée.
\text{produce} \text{TIME_IDX} [0, +\infty) Production alimentaire.
\text{opening_stock} \text{OILS}
\text{TIME_IDX}
[0, \text{stock\_ub}] Stock mensuel d'huile de matière première.
\text{closing_stock} \text{OILS}
\text{TIME_IDX}
[0, \text{stock\_ub}] Inventaire de fin de mois de l'huile de matière première.

Pour l'inventaire, il suffit souvent de déclarer un seul parmi $ \ text {opening_stock} $ et $ \ text {closing_stock} $. Il y a aussi des goûts personnels ici.

Fonction objective

Maintenant que nous avons les informations nécessaires, définissons la fonction objectif. Cette fois, je voulais maximiser les profits sur toute la période. $ \text{maximize} ~~\text{total\_profit}. $ Ici, le profit peut être calculé en utilisant les ventes et divers coûts comme suit (notez qu'il ne correspond pas exactement au «profit» en tant que terme comptable. Les coûts fixes tels que l'investissement en capital sont sujets à optimisation. J'ignore cette fois parce que c'est à l'extérieur). $ \text{total\_profit} = \text{total\_sales} - \text{total\_buy_cost} - \text{total\_stock_cost} $ Les ventes et divers coûts peuvent être calculés en multipliant la quantité d'aliments et d'huiles brutes connexes par le prix unitaire. $ \begin{align} \text{total\_sales} &= \text{sell\_uc} \times \sum_{t\in \text{TIME\_IDX}} \text{produce}\_t, \\\ \text{total\_buy\_cost} &= \sum_{oil\in \text{OILS}, t\in \text{TIME\_IDX}} \text{buy\_uc}\_{oil, t} \times \text{buy}\_{oil, t}, \\\ \text{total\_stock\_cost} &= \text{stock\_uc} \times \sum_{oil\in \text{OILS}, t\in \text{TIME\_IDX}} \text{closing\_stock}_{oil, t}. \end{align} $

Contraintes

Ensuite, notez l'expression de contrainte. Les limites supérieures et inférieures simples des variables sont décrites comme des plages de valeurs dans la section «Variables».

Stock initial, stock final

L'inventaire mensuel de janvier correspond à l'inventaire initial. $ {}^\forall oil\in \text{OILS}, ~~\text{opening\_stock}\_{oil, 1} = \text{stock_init}_{oil}. $

L'inventaire de fin de mois en juin sera supérieur à la limite d'inventaire final. $ {}^\forall oil\in \text{OILS}, ~~\text{closing\_stock}\_{oil, 6} \geq \text{stock_final_lb}_{oil}. $

Solde des stocks

L'inventaire mensuel après février correspond à l'inventaire de fin de mois du mois précédent. $ {}^\forall t\in \{2,\ldots,6\}, ~~{}^\forall oil\in \text{OILS}, ~~\text{opening\_stock}\_{oil, t} = \text{closing\_stock}\_{oil, t - 1}. $

L'inventaire de fin de mois est le montant obtenu en ajoutant le montant de l'achat à l'inventaire mensuel du mois et en soustrayant le montant de la consommation. $ {}^\forall t\in \text{TIME\_IDX}, ~~{}^\forall oil\in \text{OILS}, ~~\text{closing_stock}_{oil, t} = \text{opening\_stock}\_{oil, t} + \text{buy}\_{oil, t} - \text{use}\_{oil, t}. $

Balance de production

La production mensuelle est égale à la somme de la consommation d'huile brute. $ {}^\forall t\in \text{TIME\_IDX}, ~~\text{produce}\_t = \sum_{oil \in \text{OILS}} \text{use}\_{oil, t}. $

dureté

La partie qui dit: «La dureté de la nourriture produite est moyennée en fonction de la consommation d'huile de matière première, et la dureté de la nourriture doit être comprise entre 3 $ et 6 », mais c'est un peu compliqué. L'expression simple de l'énoncé du problème est la suivante, mais ce n'est pas une expression linéaire pour les variables. $ 3 \leq \frac{\sum_{oil\in \text{OILS}} \text{hardness}_{oil} \times \text{use}_{oil, t}}{\text{produce}_t} \leq 6. $ Cependant, vous pouvez le convertir en une expression linéaire en payant le dénominateur. $ 3 \times \text{produce}_t \leq \sum_{oil\in \text{OILS}} \text{hardness}_{oil} \times \text{use}_{oil, t} \leq 6 \times \text{produce}_t. $$

De plus, dans la formule d'origine, le comportement lorsque le montant de la production est de 0 $ est suspect, mais dans la formule convertie, le montant de la consommation et le montant de la production sont de 0 $, donc on peut voir que la contrainte est satisfaite. Avec ce paramètre de problème, il est possible que la production ne soit pas effectuée, donc il n'y a pas de problème.

Limite supérieure de la quantité de purification

Dans ce plan de production, il y avait une limite supérieure sur la quantité de purification pour chaque ligne de purification. Exprimé sous forme d'expression, il peut s'écrire comme suit. $ {}^\forall line\in \text{REF\_LINES}, ~~{}^\forall t\in \text{TIME\_IDX}, \sum_{oil\in \text{USED\_OILS}\_{line}} \text{use}\_{oil, t} \leq \text{ref\_ub}_{line}. $ Cela peut être un peu difficile à comprendre, mais pour chaque ligne de raffinage, la somme de la consommation de l'huile de matière première cible est limitée à être inférieure à une certaine limite supérieure.

Colonne 1: Modélisation arbitraire

Les informations sur la ligne de purification peuvent être exprimées différemment. Par exemple, au lieu de $ \ text {USED \ _OILS} $, définissez le paramètre $ \ text {ref \ _line} $, ce qui signifie la ligne de raffinement pour chaque matière première, comme suit:

Indice valeur
VEG1 VEG
VEG1 VEG
OIL1 NONVEG
OIL2 NONVEG
OIL3 NONVEG

C'est presque le même que le [Tableau des types d'huile de matière première mentionnés dans l'énoncé du problème](# type d'huile), il peut donc être plus naturel de l'utiliser. En utilisant ce paramètre, la limite supérieure de la limite de purification peut être exprimée comme suit: $ {}^\forall line\in \text{REF\_LINES}, ~~{}^\forall t\in \text{TIME\_IDX}, \sum_{\substack{oil\in \text{OILS} ~\text{s.t.} \\\ \text{ref\_line}\_{oil} = line}} \text{use}\_{oil, t} \leq \text{ref\_ub}_{line}. $

Ce que nous faisons est le même qu'avant, nous additionnons simplement la consommation de la matière première huile à raffiner et la limitons à la limite supérieure. Avec ce modèle, le même résultat peut être obtenu avec ces données.

Cependant, il est possible de déterminer ce qui est préférable.

Comme test, considérons le cas où une ligne appelée $ \ text {VEGNEW} $ est ajoutée pour raffiner $ \ text {VEG1} $ et $ \ text {VEG2} . Il est tout à fait possible qu'une ligne soit créée qui ne puisse raffiner qu'une partie de l'huile de matière première existante. Le modèle original peut être exprimé comme: $ \begin{aligned} \text{USED_OILS} &= \{\text{USED_OILS}_{VEG}, \text{USED_OILS}_{VEGNEW}, \text{USED_OILS}_{NONVEG}\},\
\text{USED_OILS}_{VEG} &= \{\text{VEG1}, \text{VEG2}, \text{VEG3}\}, \
\text{USED_OILS}_{VEGNEW} &= \{\text{VEG1}, \text{VEG2}\}, \
\text{USED_OILS}_{NONVEG} &= \{\text{OIL1}, \text{OIL2}\}. \end{aligned} $$

Mais que faire si vous aviez une formulation qui utilisait $ \ text {ref \ _line} $? Comme vous pouvez le voir dans le [Tableau ci-dessus](# ref-line), ce paramètre suppose que ** une huile de matière première possède une ligne de raffinage **. Par conséquent, la situation où $ \ text {VEG1} $ appartient à la fois à $ \ text {VEG} $ et $ \ text {VEGNEW} $ ne peut pas être représentée dans le modèle.

Comme vous pouvez le voir, il existe un large éventail de façons d'avoir de la polyvalence, même s'il n'y a qu'une seule façon de définir des ensembles et des paramètres. Une mauvaise compréhension du problème peut conduire à une polyvalence (ou à un échec) dans le mauvais sens, rendant difficile la modification ultérieure du modèle (cf. abstraction prématurée (cf. abstraction prématurée). abstraction prématurée).

Tous les changements ne peuvent pas être prévus à l'avance, et les hypothèses elles-mêmes peuvent changer en raison des révisions de la loi, etc., mais je me rends compte que des hypothèses arbitraires sont mélangées à la manière de définir ces ensembles occasionnels. Je pense que c'est important. De plus, lors de la modélisation, il est essentiel d'approfondir la compréhension de l'entreprise avec l'aide d'utilisateurs (experts du domaine).

Mise en œuvre du modèle: fabrication alimentaire 1

Nous implémenterons le modèle ci-dessus avec Python + PuLP. Avec PuLP, les ensembles et les paramètres peuvent utiliser n'importe quelle structure de données Python, il suffit donc d'utiliser quelque chose de facile à utiliser. Dans ce qui suit, nous introduirons la déclaration des variables, la définition des fonctions objectifs et la définition des expressions de contraintes.

Déclaration des variables

Les variables PuLP sont déclarées comme suit:

#Nom Indice Limite inférieure Limite supérieure Type (continu ou entier)
buy = LpVariable.dicts("buy", (OILS, TIME_IDX), lowBound=0, upBound=None, cat='Continuous')

D'ailleurs, bien que cela ne soit pas mentionné dans le document, il semble qu'il puisse être déclaré sous forme de matrice.

buy = LpVariable.matrix("buy", (OILS, TIME_IDX), lowBound=0, upBound=None, cat='Continuous')

Définition de la fonction objectif

Premièrement, la fonction objectif est exprimée en utilisant les variables et paramètres définis.


#Calcul de la fonction objectif
total_sales = lpSum(produce[t] * sell_uc for t in TIME_IDX)
total_buy_cost = lpSum(buy[oil][t] * buy_uc[oil][t] for t in TIME_IDX for oil in OILS)
total_stock_cost = lpSum(closing_stock[oil][t] * stock_uc for t in TIME_IDX for oil in OILS)
total_cost = total_buy_cost + total_stock_cost
total_profit = total_sales - total_cost  #Fonction objective

Vous pouvez ensuite définir le problème de planification linéaire LpProblem et le définir en ajoutant la fonction objectif.

#Définition du modèle et paramètres de la fonction objectif
model = LpProblem("Food manufacture 1", LpMaximize)
model += total_profit

Vous pouvez également utiliser des méthodes pour définir la fonction objectif comme suit:

model.setObjective(total_profit)

Si vous déclarez plus d'une fonction objectif, seule la dernière sera utilisée.

Définition d'expressions de contrainte

Les expressions de contrainte peuvent être déclarées en les ajoutant à model, tout comme la fonction objective.

#Balance de production
for t in TIME_IDX:
    model += produce[t] == lpSum(use[oil][t] for oil in OILS)

Elle est écrite de la même manière que la fonction objectif, mais elle semble bien identifiée à partir du nom de la classe. Il peut également être défini par une méthode.

model.addConstraint(produce[t] == lpSum(use[oil][t] for oil in OILS))

Bien qu'omis jusqu'à présent, la fonction objectif et l'expression de contrainte peuvent être nommées individuellement.

model += produce[t] == lpSum(use[oil][t] for oil in OILS), "Production balance"

Code entier

L'ensemble du code du modèle implémenté cette fois est résumé ci-dessous.

import numpy as np
import pandas as pd
from pulp import LpProblem, LpMaximize, LpVariable, lpSum

#Définition de l'ensemble
TIME_IDX = [1, 2, 3, 4, 5, 6]
OILS = ['VEG1', 'VEG2', 'OIL1', 'OIL2', 'OIL3']
REF_LINES = ['VEG', 'NONVEG']
USED_OILS = {
    'VEG': ['VEG1', 'VEG2'],
    'NONVEG': ['OIL1', 'OIL2', 'OIL3']
}

#Paramètres des paramètres
sell_uc = 150
stock_uc = 5
stock_ub = 1000
stock_init = 500
stock_final_lb = 500
prod_ub = {'VEG': 200, 'NONVEG': 250}
hardness_lb = 3
hardness_ub = 6
hardness = {'VEG1': 8.8, 'VEG2': 6.1, 'OIL1': 2.0, 'OIL2': 4.2, 'OIL3': 5.0}
buy_uc = {
    'VEG1': {1: 110, 2: 130, 3: 110, 4: 120, 5: 100, 6: 90},
    'VEG2': {1: 120, 2: 130, 3: 140, 4: 110, 5: 120, 6: 100},
    'OIL1': {1: 130, 2: 110, 3: 130, 4: 120, 5: 150, 6: 140},
    'OIL2': {1: 110, 2: 90, 3: 100, 4: 120, 5: 110, 6: 80},
    'OIL3': {1: 115, 2: 115, 3: 95, 4: 125, 5: 105, 6: 135}
}

#Définition variable
buy = LpVariable.dicts("buy", (OILS, TIME_IDX), lowBound=0)
use = LpVariable.dicts("use", (OILS, TIME_IDX), lowBound=0)
produce = LpVariable.dicts("produce", TIME_IDX, lowBound=0)
opening_stock = LpVariable.dicts("opening_stock", (OILS, TIME_IDX), lowBound=0, upBound=stock_ub)
closing_stock = LpVariable.dicts("closing_stock", (OILS, TIME_IDX), lowBound=0, upBound=stock_ub)

#Calcul de la fonction objectif
total_sales = lpSum(produce[t] * sell_uc for t in TIME_IDX)
total_buy_cost = lpSum(buy[oil][t] * buy_uc[oil][t] for t in TIME_IDX for oil in OILS)
total_stock_cost = lpSum(closing_stock[oil][t] * stock_uc for t in TIME_IDX for oil in OILS)
total_cost = total_buy_cost + total_stock_cost
total_profit = total_sales - total_cost

#Définition du modèle et paramètres de la fonction objectif
model = LpProblem("Food manufacture 1", LpMaximize)
model += total_profit


#Expression de contrainte
#Stock initial, stock final
for oil in OILS:
    model += opening_stock[oil][TIME_IDX[0]] == stock_init
    model += closing_stock[oil][TIME_IDX[-1]] >= stock_final_lb

#Concernant chaque mois
for t in TIME_IDX:
    #Solde des stocks
    for oil in OILS:
        if t != TIME_IDX[0]:
            model += opening_stock[oil][t] == closing_stock[oil][t - 1]
        model += closing_stock[oil][t] == opening_stock[oil][t] + buy[oil][t] - use[oil][t]

    #Solde du volume des ventes
    model += produce[t] == lpSum(use[oil][t] for oil in OILS)

    #dureté
    total_hardness = lpSum(hardness[oil] * use[oil][t] for oil in OILS)
    model += total_hardness <= hardness_ub * produce[t]
    model += total_hardness >= hardness_lb * produce[t]

    #Limite supérieure de la quantité de purification
    for line in REF_LINES:
        total_prod_amount = lpSum(use[oil][t] for oil in USED_OILS[line])
        model += total_prod_amount <= prod_ub[line]

model.solve()
print(model.objective.value())  #résultat: 107842.59264500001

L'exécution du code ci-dessus vous donnera la valeur «107842.59264500001» comme valeur de la fonction objectif. C'est la même chose que ce qui était écrit dans le texte original, il semble donc bon de penser que la solution optimale est recherchée.

Validation du modèle: Fabrication alimentaire 1

Dans la section précédente, la même valeur optimale que le texte a été trouvée. Cependant, lorsqu'on utilise réellement l'optimisation mathématique au travail, il arrive souvent que ni la valeur optimale ni la solution optimale ne soient connues, et il est rare de pouvoir "faire correspondre les réponses" comme cette fois. Par conséquent, nous vérifierons la validité des résultats en analysant qualitativement le modèle.

L'analyse qualitative consiste ici à faire une prédiction sur la valeur à prendre par la solution optimale à partir de la définition du modèle et à la comparer avec le résultat réel du calcul. Par exemple, cette fois, le premier et le dernier inventaire (la limite inférieure) sont fixes, et cela coûte en fonction du montant de l'inventaire chaque mois, il est donc rentable de consommer l'inventaire en premier et de récupérer l'inventaire au milieu. Sera plus élevé. "

在庫の推移

Maintenant, affichons la solution optimale et confirmons cette hypothèse. La solution optimale pour l'inventaire de fin d'année peut être obtenue comme suit.

closing_stock_value = {oil: {t: closing_stock[oil][t].value() for t in TIME_IDX} for oil in OILS}

Tracons avec le code suivant.

df = pd.DataFrame(closing_stock_value, index=TIME_IDX, columns=OILS)
df.plot()

最適化結果

A l'exception de OIL1, qui n'est pas du tout utilisé, tous sont sortis du stock initial une fois puis récupérés, confirmant que les résultats d'optimisation semblent raisonnables.

Nous n'avons testé qu'une seule hypothèse ici, mais en pratique, nous ferons autant d'hypothèses raisonnables que possible pour tester les résultats d'optimisation. Et si la solution optimale est aussi bonne que toutes les hypothèses, il semble qu'elle puisse être mise en œuvre correctement. Inversement, si la solution optimale ne répond pas à l'hypothèse, alors soit la mise en œuvre du modèle, soit l'hypothèse est incorrecte. Ceci est très utile car cela vous donne la possibilité de modifier le modèle lui-même et d'acquérir une meilleure compréhension du modèle.

Colonne 2: Test du modèle d'optimisation mathématique

À propos, certaines personnes peuvent se sentir mal à l'aise avec la méthode de vérification que j'ai écrite plus tôt. Si vous êtes un ingénieur logiciel, vous vous demandez peut-être: "Si l'on vous donne des contraintes une par une, pourquoi ne pas écrire un test unitaire pour chacune?" C'est vrai, et si vous pouvez l'écrire, vous devriez l'écrire.

Cependant, les modèles d'optimisation mathématique sont des ** énormes ** ensembles de contraintes ** étroitement couplées **, et les tests unitaires au niveau des contraintes sont souvent difficiles. Les formules de contraintes mentionnées précédemment semblent également être distinctes, mais en fait elles dépendent les unes des autres dans le modèle. Par exemple, si vous réduisez la limite supérieure de la quantité de purification, vous ne pourrez pas respecter la contrainte de dureté. Bien sûr, il est possible de tester le modèle lui-même en tant que fonction énorme, mais il est difficile de connaître la classe d'équivalence, la valeur limite, etc. (Bien qu'il puisse être automatisé).

En fait, en regardant le code de test du solveur d'optimisation mathématique open source, il semble que nous n'ayons résolu que quelques problèmes de jouets qui sont faciles à comprendre et qui n'ont pas été très rigoureux (test de modèle et solveur). Bien que cela puisse être différent dans le test).

https://github.com/SCIP-Interfaces/CSIP/blob/6d24c495750c7927d1d9b1bae0e906d9c54fa439/test/test.c#L57-L63

J'ai également recherché des recherches et de la littérature sur les tests d'optimisation mathématique, mais je n'ai rien trouvé de tel. Il est possible que vous l'ayez manqué, donc si vous avez une opinion telle que "C'est bien", j'apprécierais que vous puissiez commenter.

Pour le moment, la difficulté de tester ici semble être proche du problème de tester les modèles d'apprentissage automatique sur lesquels travaille la communauté MLSE, il est donc préférable de suivre les tendances de cette communauté.

Challenges for machine learning systems toward continuous improvement https://www.slideshare.net/chezou/challenges-for-machine-learning-systems-toward-continuous-improvement

Au fait, cela n'a pas d'importance, mais j'ai eu l'impression de ne rien dire quand j'ai vu l'article suivant, qui semble utiliser l'optimisation mathématique, brûlé et commenté comme "Test it". (Je ne suis pas une personne apparentée ...).

Ça devrait être "quelques secondes avec l'IA" ... Sélection école maternelle, travail après des vacances consécutives Saitama City --Mainichi Shimbun https://mainichi.jp/articles/20200204/k00/00m/040/176000c

Même si vous faites de votre mieux pour vérifier avec la méthode décrite jusqu'à présent, c'est un casse-tête car le modèle peut devenir illimité ou irréalisable en raison de données inattendues. Épicé: chien:

en conclusion

Donc, j'ai modélisé le plan de production comme une méthode de programmation linéaire, je l'ai résolu avec PuLP et j'ai essayé de vérifier le résultat. J'ai l'intention d'écrire non seulement une simple explication de la modélisation, mais aussi mes propres réflexions sur la modélisation basées sur une petite expérience pratique.

Si vous commencez à vous entraîner à la modélisation, vous souhaiterez peut-être changer ce modèle à votre manière. Par exemple, vous pouvez définir des limites supérieures et inférieures pour chaque type de mois et de pétrole dans le montant de l'achat, ou définir une perte de 1% dans le processus de raffinage.

Je voulais vraiment en faire une série et résoudre tous les exercices, mais j'étais épuisé: joie: Si vous venez de le résoudre, il est toujours difficile d'écrire un article.

Alors, si vous aimez cet article, inscrivez-vous! (Style YouTuber).

Recommended Posts

Optimisation de la planification de la production à l'aide de la programmation linéaire (Python + PuLP)
[Problème d'optimisation mathématique] Méthode de programmation linéaire utilisant PuLP
Optimisation de la planification de la production (OU-Tools)
Bibliothèque d'optimisation Python Pulp
Programmation linéaire avec PuLP
Programmation linéaire + pratique de la pulpe
Programmation GUI en Python avec Appjar
Optimisation du plan de production de plaquettes semi-conductrices
Explication du modèle d'optimisation de la production par Python
J'ai essayé d'utiliser l'optimisation bayésienne de Python
Feuille de calcul du modélisateur d'optimisation mathématique (PuLP) (Python)
Optimisation apprise avec OR-Tools [Planification linéaire: modèle en plusieurs étapes]
Optimisation apprise avec OR-Tools [Planification linéaire: gestion de projet]
Note de programmation Python
Commencez à utiliser Python
Programmation avec Python
Scraping à l'aide de Python
Optimisation apprise avec OR-Tools [plan linéaire: raffinons l'huile]