Optimierung der Produktionsplanung mittels linearer Programmierung (Python + PuLP)

Einführung

Die mathematische Programmierung ist eine Methode zum Maximieren (Minimieren) eines Zielwerts, der unter bestimmten Bedingungen als Zielfunktion bezeichnet wird. Unter diesen bezieht sich lineare Programmierung (LP) auf die Zielfunktion und den Einschränkungsausdruck, die durch einen linearen Ausdruck (in Form von $ \ sum_ia_ix_i + b $) für Variablen ausgedrückt werden können. Die lineare Programmierung ist eine der einfachsten mathematischen Programmierungen, verfügt jedoch über eine umfangreiche Bibliothek für Löser und Modellierung und bietet eine benutzerfreundliche Umgebung. Insbesondere denke ich, dass Unternehmen häufig steuerbare Variablen wie Produktionsvolumen und Transportvolumen mithilfe von monetären Indikatoren wie Gewinn und Kosten als Zielfunktionen optimieren.

In diesem Artikel wird aus den folgenden Büchern, in denen die Modellierungstechniken der mathematischen Optimierung zusammengefasst sind, eine Übung herausgenommen und tatsächlich formuliert. Sie wird in PuLP, einer Modellierungssprache von Python, implementiert, um die optimale Lösung zu finden. Ich würde gerne kommen.

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

Diese Übung dient zum Lesen von Hausaufgaben in Mathematical Optimization Group von TFUG. Es ist eins. Jeder kann der TFUG-Gruppe beitreten. Wenn Sie also interessiert sind, sollten Sie sich Slack ansehen!

Dieser Artikel hat die folgende Struktur. Zuerst werden wir kurz erklären, wie man modelliert, dann die Problemstellung des Beispiels einführt und Modellierung, Implementierung und Verifizierung durchführt.

In der Mitte befindet sich ein Spaltenabschnitt, daher ist es in Ordnung, ihn zu überspringen, aber ich schreibe über ein Thema, das ich persönlich interessant finde. Bitte lesen Sie es.

Modellierungsfluss

Um einen Plan mathematisch zu modellieren, müssen Sie im Allgemeinen zwei Dinge definieren:

  1. Zielfunktion
  2. Einschränkungsausdruck

Nehmen Sie als Beispiel den Produktionsplan einer Fabrik. Erstens repräsentiert die Zielfunktion die Kosten oder den Nutzen, die Sie optimieren möchten. Wenn Sie beispielsweise in Fabrik A und Fabrik B produzieren, gehen Sie davon aus, dass die Produktionskosten wie folgt ausgedrückt werden können: $ \ text {Produktionskosten} = \ sum_ {i \ in \\ {A, B \\}} \ text {Produktionsstückpreis} \ _ i \ times \ text {Produktionsvolumen} \ _ i. $ In diesem Fall scheinen die Produktionskosten niedrig gehalten zu werden, indem das Produktionsvolumen von Fabriken mit hohen Produktionsstückpreisen verringert und das Produktionsvolumen von Fabriken mit niedrigen Produktionsstückpreisen erhöht wird. Diese Formel allein kann jedoch nicht die optimale Lösung finden, die Sie wirklich finden möchten. Dies liegt daran, dass es keine Einschränkung gibt, dass "Sie mehr als XX produzieren müssen". Wenn Sie also versuchen, die Produktionskosten zu minimieren, besteht die optimale Lösung darin, überhaupt nicht zu produzieren.

Als nächstes legen wir als Einschränkungsausdruck der Variablen eine Bedingung auf, um eine solche Situation zu vermeiden. Zum Beispiel kann die zuvor erwähnte Einschränkung "Sie müssen mehr als XX produzieren" wie folgt ausgedrückt werden. $ \ sum_ {i \ in \\ {A, B \\}} \ text {Produktion} \ _ i \ geq \ text {Nachfrage}. $

Wenn es sich um einen Produktionsplan handelt, ist die Produktionskapazität des Werks häufig begrenzt, und das Produktionsvolumen ist häufig begrenzt. Ein Einschränkungsausdruck drückt diese Geschäftsbeschränkungen und -regeln als mathematische Formel aus.

Darüber hinaus sind die folgenden Informationen erforderlich, um die Zielfunktion und den Einschränkungsausdruck zu definieren.

--Treffen

Wenn Sie persönlich von Grund auf neu modellieren möchten, ist es meiner Meinung nach am besten, zuerst die Zielfunktion zu definieren. Beim Versuch, eine Zielfunktion zu definieren, müssen die erforderlichen Informationen im Prozess organisiert werden, was zur Bestimmung von Mengen, Parametern und Variablen führt. Identifizieren Sie anschließend für jede Variable die erforderlichen Einschränkungen und drücken Sie sie einzeln als Ausdrücke aus.

Im Folgenden werden wir die Problemstellung des Beispiels vorstellen und tatsächlich modellieren.

Problemstellung: Lebensmittelherstellung 1

Dieses Mal werden wir uns mit den Produktionsplänen für Lebensmittel befassen. Insbesondere wird von Januar bis Juni gesagt, dass Lebensmittel hergestellt werden, indem jeden Monat Öl als Rohstoff gekauft, raffiniert und gemischt wird (Margarine oder so ...?). In diesem Produktionsplan wollen wir am Ende den Gewinn maximieren, indem wir die Einkaufsmenge und die Verbrauchsmenge jedes Rohstofföls jeden Monat anpassen.

In dieser Ausgabe müssen wir die Kosten und Einschränkungen berücksichtigen, die mit den folgenden Faktoren verbunden sind, um über objektive Funktionen und Einschränkungsausdrücke nachzudenken.

--Inventar --Kauf --Reinigung

Ich werde jede Situation im Detail erklären.

Lager

Die Lagerbestände an kohäsivem Öl steigen mit Neuanschaffungen und sinken mit dem Verbrauch in der Lebensmittelproduktion.

Jedes Ausgangsmaterial kann für bis zu $ 1000 [t] $ auf Lager gehalten werden. Es fallen jedoch Speicherkosten von 5 USD [£ / t] USD pro Monat an.

Für jedes Quellöl beginnt der Lagerbestand bei 500 [t] $ und endet bei 500 [t] $ oder mehr.

Kauf

Die oben genannten Öle werden von Januar bis Juni zu folgenden Stückpreisen gekauft.

Mond 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

Es gibt keine besonderen Einschränkungen hinsichtlich des Betrags, der gekauft werden kann.

Reinigung

Von der gekauften Menge und der ursprünglich auf Lager befindlichen Menge wird eine bestimmte Menge dem Reinigungsprozess unterzogen. Bei der Reinigung treten keine besonderen Verluste auf, und die Reinigungskosten sind vernachlässigbar.

Es gibt zwei Arten von Rohöl, pflanzliches und nicht pflanzliches, und der Raffinierungsprozess soll für jede Ölsorte auf verschiedenen Raffinierungslinien durchgeführt werden. Die Obergrenze der Reinigungsmenge wird wie folgt eingestellt.

Art Obergrenze der Reinigungsmenge[t/Mond]
Botanisch 200
Nicht pflanzlich 250

Darüber hinaus sind die Arten von Rohstofföl wie folgt.

Name Art
VEG 1 Botanisch
VEG 2 Botanisch
OIL 1 Nicht pflanzlich
OIL 2 Nicht pflanzlich
OIL 3 Nicht pflanzlich

Mischung

Durch Mischen aller raffinierten Öle wird das in diesem Monat zu versendende Lebensmittel fertiggestellt. Auch hier tritt kein Verlust auf, so dass das Gesamtgewicht des gemischten Rohöls die Menge der produzierten Lebensmittel ist.

Zusätzlich hat jedes Rohstofföl die in der folgenden Tabelle angegebene Härte. Die Härte des hergestellten Lebensmittels wird nach dem Verbrauch des Rohstofföls gemittelt, und die Härte des Lebensmittels muss zwischen 3 und 6 US-Dollar liegen.

Name Härte
VEG1 8.8
VEG2 6.1
OIL1 2.0
OIL2 4.2
OIL3 5.0

Verkauf

Es scheint, dass die produzierten Lebensmittel innerhalb eines Monats ausverkauft sein können. Mit anderen Worten, das Produktionsvolumen wird so wie es ist das Verkaufsvolumen. Der Stückverkaufspreis beträgt unabhängig vom Monat 150 USD [£ / t] USD.

Modellierung: Lebensmittelherstellung 1

Von nun an werden wir die zuvor erläuterte Problemeinstellung tatsächlich modellieren. Außerdem habe ich früher geschrieben, dass "es besser ist, die Menge und die Parameter zu bestimmen, während die Zielfunktion definiert wird", aber in der Erklärung ist es einfacher, die Menge, die Parameter und die Variablen zuerst zu schreiben, also mache ich das. ..

einstellen

In einem mathematischen Optimierungsmodell ist eine Menge ein Index eines Parameters oder einer Variablen. In dieser Ausgabe werden die folgenden vier Sätze betrachtet:

** Rohöl ** $ \text{OILS} = \\{\text{VEG1}, \text{VEG2}, \text{OIL1}, \text{OIL2}, \text{OIL3}\\}. $

** Zielzeitraum (Monat) ** $ \text{TIME_IDX} = \\{1, \ldots, 6 \\}. $

** Reinigungslinie ** $ \text{REF\_LINES} = \\{\text{VEG}, \text{NONVEG} \\}. $

** Reinigungsziel ** Da es für jede Reinigungslinie definiert ist, handelt es sich um eine Menge von Mengen (Mengenfamilie) als Ganzes. $ \text{USED_OILS} = \\{\text{USED_OILS}\_{VEG}, \text{USED_OILS}\_{NONVEG}\\}. $ Der Inhaltssatz jeder Reinigungslinie ist $ \begin{aligned} \text{USED_OILS}\_{VEG} &= \\{\text{VEG1}, \text{VEG2}, \text{VEG3}\\}, \\\ \text{USED_OILS}\_{NONVEG} &= \\{\text{OIL1}, \text{OIL2}\\}. \end{aligned} $

Ich gebe es hier unten weiter, aber denke daran, dass die Art und Weise, wie Mengen definiert werden, nicht eindeutig ist. Abhängig davon, wie die Menge definiert ist, kann die Vielseitigkeit des Modells verringert werden. Dies wird im Abschnitt Constraint Expressions näher erläutert.

Parameter

Als nächstes definieren wir die Parameter, die zur Berechnung der Zielfunktion und des Einschränkungsausdrucks verwendet werden.

Name Index Wertebereich Erläuterung
\text{buy\_uc} \text{OILS}
\text{TIME_IDX}
[0, +\infty) Kaufpreis des Rohstofföls.
\text{stock\_uc} - [0, +\infty) Lagereinheitspreis für Rohöl.
\text{sell\_uc} - [0, +\infty) Stückverkaufspreis für Lebensmittel.
\text{stock_init} \text{OILS} [0, +\infty) Anfangsbestand an Rohöl.
\text{stock_final_lb} \text{OILS} [0, +\infty) Die Untergrenze des Endbestandes an Rohstofföl.
\text{stock\_ub} - [0, +\infty) Obergrenze des Rohölvorrats.
\text{hardness} \text{OILS} [0, +\infty) Die Härte des Rohstofföls.
\text{ref\_ub} \text{REF\_LINES} [0, +\infty) Obergrenze der Reinigungsmenge.

uc ist eine Abkürzung für Stückkosten, was Stückpreis bedeutet, und lb / ub ist eine Abkürzung für Unter- / Obergrenze, was Ober- und Untergrenze bedeutet.

Variable

Definieren Sie auf ähnliche Weise die zu optimierenden Variablen. Es ist wünschenswert, die Nomenklatur für Variablennamen zu verwenden. Wenn sie jedoch zu lang ist, ist der Ausdruck schwer zu lesen, sodass einige Verben verwendet werden.

Name Index Wertebereich Erläuterung
\text{buy} \text{OILS}
\text{TIME_IDX}
[0, +\infty) Kaufmenge Rohöl.
\text{use} \text{OILS}
\text{TIME_IDX}
[0, +\infty) Menge des verwendeten Rohstofföls.
\text{produce} \text{TIME_IDX} [0, +\infty) Lebensmittelproduktion.
\text{opening_stock} \text{OILS}
\text{TIME_IDX}
[0, \text{stock\_ub}] Monatlicher Vorrat an Rohstofföl.
\text{closing_stock} \text{OILS}
\text{TIME_IDX}
[0, \text{stock\_ub}] Bestandsaufnahme von Rohstoff zum Monatsende.

Für das Inventar reicht es oft aus, nur eines von $ \ text {Eröffnungsbestand} $ und $ \ Text {Abschlussbestand} $ zu deklarieren. Hier gibt es auch persönliche Vorlieben.

Zielfunktion

Nachdem wir die erforderlichen Informationen haben, definieren wir die Zielfunktion. Dieses Mal wollte ich den Gewinn für den gesamten Zeitraum maximieren. $ \text{maximize} ~~\text{total\_profit}. $ Hier kann der Gewinn anhand des Umsatzes und verschiedener Kosten wie folgt berechnet werden (Beachten Sie, dass er nicht genau mit dem Begriff "Gewinn" als Buchungsbegriff übereinstimmt. Fixkosten wie Kapitalinvestitionen unterliegen einer Optimierung. Ich ignoriere diesmal, weil es draußen ist. $ \text{total\_profit} = \text{total\_sales} - \text{total\_buy_cost} - \text{total\_stock_cost} $ Umsatz und verschiedene Kosten können berechnet werden, indem die Menge der zugehörigen Lebensmittel und Rohöle mit dem Stückpreis multipliziert wird. $ \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} $

Einschränkungen

Schreiben Sie als nächstes den Einschränkungsausdruck auf. Die einfachen oberen und unteren Grenzen von Variablen werden im Abschnitt "Variablen" als Wertebereiche beschrieben.

Anfangsbestand, Endbestand

Das monatliche Inventar für Januar entspricht dem ursprünglichen Inventar. $ {}^\forall oil\in \text{OILS}, ~~\text{opening\_stock}\_{oil, 1} = \text{stock_init}_{oil}. $

Der Monatsendbestand im Juni muss über dem endgültigen Bestandslimit liegen. $ {}^\forall oil\in \text{OILS}, ~~\text{closing\_stock}\_{oil, 6} \geq \text{stock_final_lb}_{oil}. $

Aktiensaldo

Das monatliche Inventar nach Februar entspricht dem Monatsendinventar des Vormonats. $ {}^\forall t\in \{2,\ldots,6\}, ~~{}^\forall oil\in \text{OILS}, ~~\text{opening\_stock}\_{oil, t} = \text{closing\_stock}\_{oil, t - 1}. $

Das Inventar zum Monatsende ist der Betrag, der durch Addieren des Kaufbetrags zum monatlichen Inventar des Monats und Subtrahieren des Verbrauchsbetrags erhalten wird. $ {}^\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}. $

Produktionsbilanz

Die monatliche Produktion entspricht der Summe des Rohölverbrauchs. $ {}^\forall t\in \text{TIME\_IDX}, ~~\text{produce}\_t = \sum_{oil \in \text{OILS}} \text{use}\_{oil, t}. $

Härte

Der Teil, der besagt: "Die Härte des hergestellten Lebensmittels wird nach dem Verbrauch von Rohöl gemittelt, und die Härte des Lebensmittels muss zwischen 3 und 6 US-Dollar liegen", ist jedoch etwas kompliziert. Der einfache Ausdruck der Problemstellung lautet wie folgt, ist jedoch kein linearer Ausdruck für Variablen. $ 3 \leq \frac{\sum\_{oil\in \text{OILS}} \text{hardness}\_{oil} \times \text{use}\_{oil, t}}{\text{produce}_t} \leq 6. $ Sie können es jedoch in einen linearen Ausdruck konvertieren, indem Sie den Nenner bezahlen. $ 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. $

Darüber hinaus ist in der ursprünglichen Formel das Verhalten, wenn die Produktionsmenge 0 $ beträgt, verdächtig, aber in der konvertierten Formel sind sowohl die Verbrauchsmenge als auch die Produktionsmenge 0 $, so dass ersichtlich ist, dass die Einschränkung erfüllt ist. Mit dieser Problemeinstellung ist es möglich, dass die Produktion nicht ausgeführt wird, sodass kein Problem vorliegt.

Obergrenze der Reinigungsmenge

In diesem Produktionsplan gab es eine Obergrenze für die Reinigungsmenge für jede Reinigungslinie. Als Ausdruck ausgedrückt, kann es wie folgt geschrieben werden. $ {}^\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}. $ Es mag etwas schwierig zu verstehen sein, aber für jede Verfeinerungslinie ist die Summe des Verbrauchs des Zielrohstofföls auf eine bestimmte Obergrenze beschränkt.

Spalte 1: Beliebige Modellierung

Informationen über die Reinigungslinie können unterschiedlich ausgedrückt werden. Versuchen Sie beispielsweise, anstelle von $ \ text {USED \ _OILS} $ den Parameter $ \ text {ref \ _line} $ zu definieren, dh die Verfeinerungslinie für jedes Ausgangsmaterial wie folgt:

Index Wert
VEG1 VEG
VEG1 VEG
OIL1 NONVEG
OIL2 NONVEG
OIL3 NONVEG

Dies ist fast das Gleiche wie in der [Tabelle der in der Problembeschreibung genannten Rohstofföltypen](# Öltyp), daher ist es möglicherweise natürlicher, diese zu verwenden. Mit diesem Parameter kann die obere Grenze der Reinigungsgrenze ausgedrückt werden als: $ {}^\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}. $

Was wir tun, ist das gleiche wie zuvor. Wir addieren nur den Verbrauch des zu raffinierenden Rohstofföls und begrenzen ihn auf die Obergrenze. Mit diesem Modell kann mit diesen Daten das gleiche Ergebnis erzielt werden.

Es gibt jedoch Raum für Überlegungen, welche vorzuziehen sind.

Betrachten Sie als Test den Fall, in dem eine Zeile mit dem Namen $ \ text {VEGNEW} $ hinzugefügt wird, um $ \ text {VEG1} $ und $ \ text {VEG2} $ zu verfeinern. Es ist durchaus möglich, dass eine Linie entsteht, die nur einen Teil des vorhandenen Rohstofföls raffinieren kann. Das ursprüngliche Modell kann ausgedrückt werden als: $ \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} $

Aber was wäre, wenn Sie eine Formulierung hätten, die $ \ text {ref \ _line} $ verwendet? Wie Sie aus der [Tabelle oben](# ref-line) sehen können, geht dieser Parameter davon aus, dass ** ein Rohstofföl eine Raffinerielinie ** hat. Daher kann die Situation, in der $ \ text {VEG1} $ sowohl zu $ \ text {VEG} $ als auch zu $ \ text {VEGNEW} $ gehört, nicht im Modell dargestellt werden.

Wie Sie sehen, gibt es eine Vielzahl von Möglichkeiten, um vielseitig zu sein, auch wenn es nur eine Möglichkeit gibt, Mengen und Parameter zu definieren. Ein schlechtes Verständnis des Problems kann zu Vielseitigkeit (oder Misserfolg) in die falsche Richtung führen, was es schwierig macht, das Modell später zu modifizieren (vgl. Vorzeitige Abstraktion (vgl. Vorzeitige Abstraktion). vorzeitige Abstraktion).

Nicht alle Änderungen können im Voraus vorhergesehen werden, und die Annahmen selbst können sich aufgrund von Gesetzesrevisionen usw. ändern, aber mir ist klar, dass willkürliche Annahmen in die Art und Weise der Definition solcher zufälligen Mengen eingemischt sind. Ich denke das ist wichtig. Bei der eigentlichen Modellierung ist es außerdem wichtig, das Verständnis des Geschäfts mithilfe von Benutzern (Domain-Experten) zu vertiefen.

Modellimplementierung: Lebensmittelherstellung 1

Wir werden das obige Modell mit Python + PuLP implementieren. In PuLP können Mengen und Parameter jede Python-Datenstruktur verwenden. Es reicht also aus, etwas zu verwenden, das einfach zu verwenden ist. Im Folgenden werden die Deklaration von Variablen, die Definition von Zielfunktionen und die Definition von Einschränkungsausdrücken vorgestellt.

Deklaration von Variablen

PuLP-Variablen werden wie folgt deklariert:

#Name Index Untergrenze Obergrenze Typ (stetig oder ganzzahlig)
buy = LpVariable.dicts("buy", (OILS, TIME_IDX), lowBound=0, upBound=None, cat='Continuous')

Übrigens, obwohl es im Dokument nicht erwähnt wird, scheint es, dass es in Form einer Matrix deklariert werden kann.

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

Einstellen der Zielfunktion

Zunächst wird die Zielfunktion anhand der definierten Variablen und Parameter ausgedrückt.


#Berechnung der Zielfunktion
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  #Zielfunktion

Sie können dann das lineare Planungsproblem "LpProblem" definieren und durch Hinzufügen der Zielfunktion festlegen.

#Einstellungen für Modelldefinition und Zielfunktion
model = LpProblem("Food manufacture 1", LpMaximize)
model += total_profit

Sie können die Zielfunktion auch wie folgt festlegen:

model.setObjective(total_profit)

Wenn Sie mehr als eine Zielfunktion deklarieren, wird nur die letzte verwendet.

Einschränkungsausdrücke festlegen

Constraint-Ausdrücke können wie die Zielfunktion deklariert werden, indem sie zu "model" hinzugefügt werden.

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

Es ist auf die gleiche Weise wie die Zielfunktion geschrieben, scheint jedoch anhand des Klassennamens gut identifiziert zu sein. Es kann auch durch eine Methode definiert werden.

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

Obwohl bisher weggelassen, können sowohl die Zielfunktion als auch der Einschränkungsausdruck einzeln benannt werden.

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

Ganzer Code

Der gesamte Code des diesmal implementierten Modells ist unten zusammengefasst.

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

#Definition der Menge
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']
}

#Parametereinstellungen
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}
}

#Variablendefinition
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)

#Berechnung der Zielfunktion
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

#Einstellungen für Modelldefinition und Zielfunktion
model = LpProblem("Food manufacture 1", LpMaximize)
model += total_profit


#Einschränkungsausdruck
#Anfangsbestand, Endbestand
for oil in OILS:
    model += opening_stock[oil][TIME_IDX[0]] == stock_init
    model += closing_stock[oil][TIME_IDX[-1]] >= stock_final_lb

#In Bezug auf jeden Monat
for t in TIME_IDX:
    #Aktiensaldo
    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]

    #Verkaufsvolumenbilanz
    model += produce[t] == lpSum(use[oil][t] for oil in OILS)

    #Härte
    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]

    #Obergrenze der Reinigungsmenge
    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())  #Ergebnis: 107842.59264500001

Wenn Sie den obigen Code ausführen, erhalten Sie den Wert "107842.59264500001" als Wert der Zielfunktion. Dies ist das Gleiche wie im Originaltext, daher scheint es gut zu glauben, dass die optimale Lösung gesucht wird.

Modellvalidierung: Lebensmittelherstellung 1

Im vorherigen Abschnitt wurde derselbe optimale Wert wie der Text gefunden. Wenn jedoch tatsächlich eine mathematische Optimierung bei der Arbeit verwendet wird, ist es häufig so, dass weder der optimale Wert noch die optimale Lösung bekannt sind, und es ist selten möglich, die Antworten wie diesmal "abzugleichen". Daher werden wir die Gültigkeit der Ergebnisse durch qualitative Analyse des Modells überprüfen.

Die qualitative Analyse besteht darin, aus der Definition des Modells eine Vorhersage über den Wert zu treffen, den die optimale Lösung zu ziehen hat, und ihn mit dem tatsächlichen Berechnungsergebnis zu vergleichen. Diesmal ist beispielsweise das erste und letzte Inventar (die Untergrenze) festgelegt, und die Kosten richten sich nach der monatlichen Inventarmenge. Daher ist es rentabel, das Inventar zuerst zu verbrauchen und das Inventar in der Mitte wiederherzustellen. Wird höher sein. "

在庫の推移

Lassen Sie uns nun die optimale Lösung anzeigen und diese Hypothese bestätigen. Die optimale Lösung für das Jahresende-Inventar kann wie folgt erhalten werden.

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

Zeichnen wir mit dem folgenden Code.

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

最適化結果

Mit Ausnahme von OIL1, das überhaupt nicht verwendet wird, sind alle einmal aus dem ursprünglichen Bestand gefallen und haben sich dann erholt, was bestätigt, dass die Optimierungsergebnisse angemessen erscheinen.

Wir haben hier nur eine Hypothese getestet, aber in der Praxis werden wir so viele vernünftige Annahmen wie möglich treffen, um die Optimierungsergebnisse zu testen. Und wenn die optimale Lösung so gut ist wie alle Hypothesen, scheint sie korrekt implementiert zu werden. Wenn umgekehrt die optimale Lösung die Hypothese nicht erfüllt, ist entweder die Modellimplementierung oder die Hypothese falsch. Dies ist sehr nützlich, da Sie die Möglichkeit haben, das Modell selbst zu ändern und das Modell besser zu verstehen.

Spalte 2: Testen des mathematischen Optimierungsmodells

Übrigens fühlen sich einige Leute mit der Verifizierungsmethode, die ich zuvor geschrieben habe, möglicherweise unwohl. Wenn Sie ein Softwareentwickler sind, fragen Sie sich vielleicht: "Wenn Sie nacheinander Einschränkungen erhalten, warum nicht für jeden einen Komponententest schreiben?" Das ist richtig, und wenn Sie es schreiben können, sollten Sie es schreiben.

Mathematische Optimierungsmodelle sind jedoch ** riesige ** Mengen ** eng gekoppelter ** Einschränkungen, und Unit-Tests auf Einschränkungsebene sind oft schwierig. Die zuvor erwähnten Einschränkungsformeln scheinen ebenfalls getrennt zu sein, aber tatsächlich hängen sie im Modell voneinander ab. Wenn Sie beispielsweise die Obergrenze der Reinigungsmenge verringern, können Sie die Härtebeschränkung nicht erfüllen. Natürlich ist es möglich, das Modell selbst als eine große Funktion zu testen, aber es ist schwierig, die Äquivalenzklasse, den Grenzwert usw. zu kennen, und schließlich kommt es zur "Entdeckungshypothese und Verifikation" zurück. (Obwohl es automatisiert werden kann).

Wenn man sich den Open-Source-Testcode für mathematische Optimierungslöser ansieht, sieht es so aus, als hätten wir keine sehr strengen Tests durchgeführt (Modelltests und Löser), da wir nur einige Spielzeugprobleme lösen müssen, die leicht zu verstehen sind. Obwohl es im Test anders sein kann).

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

Ich suchte auch nach Recherchen und Literatur zu mathematischen Optimierungstests, konnte aber so etwas nicht finden. Es besteht die Möglichkeit, dass Sie es gerade verpasst haben. Wenn Sie also eine Meinung wie "Das ist gut" haben, würde ich es begrüßen, wenn Sie einen Kommentar abgeben könnten.

Derzeit scheint die Schwierigkeit, hier zu testen, nahe am Problem des Testens von Modellen für maschinelles Lernen zu liegen, an denen die MLSE-Community arbeitet. Daher ist es möglicherweise besser, den Trends dieser Community zu folgen.

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

Übrigens spielt es keine Rolle, aber ich hatte das Gefühl, dass ich nichts sagen konnte, als ich den folgenden Artikel sah, der mathematische Optimierung zu verwenden scheint, verbrannt und kommentiert wie "Test it". (Ich bin keine verwandte Person ...).

Es sollte "ein paar Sekunden mit KI" sein ... Auswahl des Kindergartens, Arbeit nach aufeinanderfolgenden Ferien Saitama City - Mainichi Shimbun https://mainichi.jp/articles/20200204/k00/00m/040/176000c

Selbst wenn Sie Ihr Bestes tun, um dies mit der bisher beschriebenen Methode zu überprüfen, bereitet dies Kopfschmerzen, da das Modell aufgrund unerwarteter Daten möglicherweise unbegrenzt oder nicht mehr durchführbar ist. Würzig: Hund:

abschließend

Also habe ich den Produktionsplan als lineare Programmiermethode modelliert, ihn tatsächlich mit PuLP gelöst und versucht, das Ergebnis zu überprüfen. Ich beabsichtige, nicht nur eine einfache Erklärung der Modellierung zu schreiben, sondern auch meine eigenen Gedanken zur Modellierung, die auf ein wenig praktischer Erfahrung beruhen.

Wenn Sie mit dem Modellieren beginnen, können Sie dieses Modell auf Ihre eigene Weise ändern. Sie können beispielsweise Ober- und Untergrenzen für die Kaufmenge für jede Art von Monat und Öl festlegen oder so festlegen, dass beim Raffinieren 1% verloren gehen.

Ich wollte wirklich eine Serie daraus machen und alle Übungen lösen, aber ich war erschöpft: Freude: Wenn Sie es nur lösen, ist es immer noch schwierig, einen Artikel zu schreiben.

Wenn Ihnen dieser Artikel gefällt, abonnieren Sie ihn bitte! (YouTuber-Stil).

Recommended Posts

Optimierung der Produktionsplanung mittels linearer Programmierung (Python + PuLP)
[Mathematisches Optimierungsproblem] Lineare Programmiermethode mit PuLP
Produktionsplanungsoptimierung (OR-Tools)
Python-Optimierungsbibliothek Pulp
Lineare Programmierung mit PuLP
Lineare Programmierung + Hands-on von Zellstoff
GUI-Programmierung in Python mit Appjar
Optimierung des Produktionsplans für Halbleiterwafer
Erklärung des Produktionsoptimierungsmodells durch Python
Ich habe versucht, die Bayes'sche Optimierung von Python zu verwenden
Cheet Sheet (Python) des Mathematical Optimization Modeler (PuLP)
Mit OR-Tools erlernte Optimierung [Lineare Planung: Mehrstufiges Modell]
Mit OR-Tools erlernte Optimierung [Lineare Planung: Projektmanagement]
Python-Programmierhinweis
Starten Sie Python
Programmieren mit Python
Scraping mit Python
Mit OR-Tools erlernte Optimierung [Linearer Plan: Lassen Sie uns Öl raffinieren]