[PYTHON] Mit OR-Tools erlernte Optimierung [Lineare Planung: Mehrstufiges Modell]

Dieser Blog ist was

Wir lernen die mathematische Optimierung mit von Google entwickelten OR-Tools. Der größte Teil des Inhalts basiert auf diesem Buch. Practical Python AI Projects: Mathematical Models of Optimization Problems with Google OR-Tools (English Edition)

Klicken Sie hier, um eine Liste der Codes nach Autor anzuzeigen Der in diesem Blog beschriebene Code entspricht fast dem Originalcode des Autors und ist nur teilweise auf Japanisch korrigiert. Mathematische Genauigkeit und theoretischer Kommentar haben eine niedrige Priorität. Bitte verzeih mir.

Diesmal: Lineare Planung - mehrstufiges Modell -

Integrieren Sie "wann" in Ihre Entscheidungen. Am Beispiel eines Lagers ändert sich die Bestellmenge für den nächsten Monat in Abhängigkeit davon, wie viele Lagerbestände Sie am Ende dieses Monats haben. Ebenso ändert sich die Bestellmenge für den nächsten Monat in Abhängigkeit von der Bestellmenge für den nächsten Monat. Berücksichtigen Sie auf diese Weise die optimale Entscheidung in einer Situation, in der die Entscheidung in einer Phase die Entscheidung in den nachfolgenden Phasen beeinflusst.

Szeneneinstellung

Takashi betreibt eine Seifenfabrik. Da sich die Leistung der Fabrik auf Takashis Taschengeld auswirkt, habe ich mich für eine effiziente Betriebsmethode entschieden.

Seife wird durch Scheuern und Mischen verschiedener Öle hergestellt. Öle haben verschiedene Düfte wie Aprikose und Avocado, und jedes Öl enthält verschiedene Fettsäuren (Laurin, Linol, Ölsäure usw.). Unten finden Sie eine Tabelle der in Öl $ i $ enthaltenen Fettsäuren $ A_j $. image.png Berücksichtigen Sie auch die Eigenschaften der Seife (Waschmittel, Schaumbildung, Trockenheit der Haut usw.) richtig, damit der endgültige Fettsäuregehalt in einem bestimmten Bereich liegt. Hier wird angenommen, dass es in den Bereich der folgenden Tabelle fällt. image.png Hier betrachten wir eine Entscheidung, die mehrere Monate umfasst. Jedes Öl kann zur sofortigen Verwendung oder für den nächsten Monat gekauft werden. Die folgende Tabelle zeigt den Preis (Dollar / t) jedes Öls für jeden Monat. image.png Sie können bis zu 1.000 Tonnen Öl für die spätere Verwendung aufbewahren. Es gibt jedoch monatliche Lagerkosten von 5 USD pro Tonne. Darüber hinaus muss Takashis Fabrik den monatlichen Bedarf an 5.000 Tonnen Seife decken. Zu diesem Zeitpunkt hat Takashis Fabrik die in der folgenden Tabelle aufgeführten Öle. image.png

Es ist endlich das Hauptthema. ** Wie viel Öl sollte in welchem Monat geschmolzen und gemischt werden, um die Kosten zu minimieren? </ font> ** Ah, es war lang.

Formulierung: Determinante Variable

Es scheint eine Determinante dafür zu sein, wie viel jedes Öl jeden Monat gemischt wird, aber das reicht nicht aus. Wenn Sie Öl verwenden, können Sie verwenden, was Sie gekauft haben oder was Sie auf Lager hatten, also unterscheiden wir zwischen ihnen. Sie müssen auch wissen, wie viel Sie bei einer Gesamtgrenze von 1.000 Tonnen für Aktien kaufen können.

Daher benötigen wir mindestens drei Determinanten für den Ölsatz $ O $ und den Monatssatz $ M $.

x_{i,j} \geq 0 \quad \forall i \in O, \forall j \in M \Quad Kauf\\
y_{i,j} \geq 0 \quad \forall i \in O, \forall j \in M \Quad gemischt\\
z_{i,j} \geq 0 \quad \forall i \in O, \forall j \in M \Quad Stock\\

$ x_ {i, j} $ ist die Menge an Öl $ i $, die im Monat $ j $ gekauft wurde, $ y_ {i, j} $ ist das Öl $ i $, das im Monat $ j $ gemischt wurde, um Seife herzustellen Was ist $ z_ {i, j} $ ist die Menge an Öl $ i $, die Sie zu Beginn von $ j $ pro Monat haben. Repräsentiert. Obwohl dies nicht unbedingt erforderlich ist, geben wir auch eine Variable für die Anzahl der Tonnen Seife an, die pro Monat hergestellt wurden. Dies erleichtert die Beschreibung von Einschränkungen. Monatliche $ j $ Seifenproduktion

t_j \quad \forall j \in M

Wird besorgt.

Formulierung: Einschränkung

Sie müssen angeben, wie der Bestand jedes Öls jeden Monat schwankt. Deshalb

z_{i,j} + x_{i,j} - y_{i,j}= z_{i,j+1} \quad \forall i \in O, \forall j \in M \ {letzten Monat}

Bereiten Sie die Formel vor. Dies bedeutet, dass der Bestand am Monatsanfang zuzüglich des Kaufs für den aktuellen Monat abzüglich der Nutzung für den aktuellen Monat der Bestand für den nächsten Monat ist.

Da es monatlich Unter- und Obergrenzen für die Kapazität des Lagers gibt,

C_{min} \leq \sum_{i} z_{i,j} \leq C_{max} \quad  \forall j \in M

Als nächstes kommt die Mischungsbeschränkung. Es gab eine Regelung über den Bereich der Fettsäuren im Endprodukt. Wir werden die monatliche Produktion $ t_j = \ sum_ {i} y_ {i, j} \ quad \ forall j \ in M $ verwenden. Es gibt eine Reihe von Fettsäuren $ A $ und für jede Fettsäure $ k \ in A $ den angegebenen Bereich $ [l_k, u_k] $ und das Verhältnis der in Öl $ i $ p_ {i, k} $ enthaltenen Fettsäuren $ k $ Nachdenken über. Dann gibt es zwei Formeln für den Bereich des Fettsäuregehalts, die Untergrenze und die Obergrenze.

\sum_i y_{i,j} p_{i,k} \geq l_k t_j \quad \forall k \in A, \forall j \in M \\
\sum_i y_{i,j} p_{i,k} \leq u_k t_j \quad \forall k \in A, \forall j \in M

Schließlich müssen wir den monatlichen Bedarf decken (obwohl er diesmal konstant bei 5.000 t liegt). Angesichts der monatlichen Nachfrage von $ j $ $ D_j $,

t_j \geq D_j \quad \forall j \in M

Formulierung: Zielfunktion

Der Zweck dieser Zeit war es, die Kosten zu minimieren. Das heißt, um die Summe der Anschaffungs- und Lagerkosten für Öl zu minimieren. Der Kaufpreis variiert je nach Öl und Monat, die Lagerkosten pro Tonne sind jedoch fest. Daher ist die Zielfunktion

\sum_i \sum_j x_{i,j} P_{i,j} + \sum_i \sum_j z_{i,j}p

$ P_ {i, j} $ ist der monatliche Stückpreis von Öl $ i $ und $ p $ sind die Lagerkosten pro Tonne (diesmal $ 5).

Implementierung

Hier ist der Code zur Lösung dieses Beispiels. my_or_tools.py und tableutils.py Den Inhalt finden Sie unter Autor GitHub.

blend_multi.py


from my_or_tools import SolVal, ObjVal, newSolver

def solve_model(Part,Target,Cost,Inventory,D,SC,SL):
    #Part:Tabelle der Öle und Fettsäuren,Target:Regulierung des Fettsäuregehalts,Cost:Ölkaufkosten,Inventory:Anfangsbestand,
    #D:Nachfrage nach Seife,SC:Öllagerungskosten,SL:Auswahl an Ölen, die Sie auf Lager haben können

  s = newSolver('Multi-period soap blending problem')   #Löser deklarieren
  Oils= range(len(Part))    #Anzahl der Ölsorten
  Periods, Acids = range(len(Cost[0])), range(len(Part[0]))     #Anzahl der Perioden,Arten von Fettsäuren
  Buy = [[s.NumVar(0,D,'') for _ in Periods] for _ in Oils]     #Determinantenvariable x. Wie viel Öl muss ich im Monat kaufen? J.
  Blnd = [[s.NumVar(0,D,'') for _ in Periods] for _ in Oils]    #Determinantenvariable y. Wie viele Öle soll ich für den Monat verwenden? J.
  Hold = [[s.NumVar(0,D,'') for _ in Periods] for _ in Oils]    #Determinantenvariable z. Wie viele Öle habe ich pro Monat auf Lager? J.
  Prod = [s.NumVar(0,D,'') for _ in Periods]    #Hilfsvariablen. Seife produziert am Monat j
  CostP= [s.NumVar(0,D*1000,'') for _ in Periods]   #Hilfsvariablen. Monat j Anschaffungskosten
  CostS= [s.NumVar(0,D*1000,'') for _ in Periods]   #Hilfsvariablen. Lagerkosten für Monat j
  Acid = [[s.NumVar(0,D*D,'') for _ in Periods] for _ in Acids] #Hilfsvariablen. Menge der im Monat j produzierten Fettsäure k
  for i in Oils:                             
    s.Add(Hold[i][0] == Inventory[i][0])    #Einschränkungen. Der Lagerbestand zum Zeitpunkt der Entscheidung ist angegeben
  for j in Periods:                                      
    s.Add(Prod[j] == sum(Blnd[i][j] for i in Oils)) #Einschränkungen. Die monatliche Produktion ist die Summe der verwendeten Ölmenge
    s.Add(Prod[j] >= D) #Einschränkungen. Die Produktion im Monat j muss die Nachfrage dieses Monats übersteigen
    if j < Periods[-1]: #Ohne den letzten Monat
      for i in Oils:
        s.Add(Hold[i][j]+Buy[i][j]-Blnd[i][j] == Hold[i][j+1])  #Einschränkungen.(Lager am Monatsanfang)+(Kaufbetrag)-(Menge zu verwenden)=(Lager Anfang nächsten Monats)
    s.Add(sum(Hold[i][j] for i in Oils) >= SL[0])   #Einschränkungen. Untergrenze des Öls, das gelagert werden kann
    s.Add(sum(Hold[i][j] for i in Oils) <= SL[1])   #Einschränkungen. Obergrenze des Öls, das gelagert werden kann
    for k in Acids: 
      s.Add(Acid[k][j]==sum(Blnd[i][j]*Part[i][k] for i in Oils))   #Einschränkungen. Die Menge an Fettsäure k, die im Monat j produziert wird, ist die Summe der Produkte aus der Menge an verwendetem Öl und dem Gehalt an Fettsäure k in diesem Öl.
      s.Add(Acid[k][j] >= Target[0][k] * Prod[j])   #Einschränkungen. Untergrenze der Fettsäure-k-Produktion
      s.Add(Acid[k][j] <= Target[1][k] * Prod[j])   #Einschränkungen. Obergrenze der Fettsäure-k-Produktion
    s.Add(CostP[j] == sum(Buy[i][j] * Cost[i][j] for i in Oils))    #Einschränkungen. Die Anschaffungskosten für Monat j sind die Summe aus dem Produkt aus Kaufbetrag und Preis.
    s.Add(CostS[j] == sum(Hold[i][j] * SC for i in Oils))           #Einschränkungen. Die Lagerkosten für den Monat j sind die Summe aus dem Produkt aus Inventar und Lagerkosten.
  Cost_product = s.Sum(CostP[j] for j in Periods)   #Zielfunktion. Gesamtkaufkosten
  Cost_storage = s.Sum(CostS[j] for j in Periods)   #Zielfunktion. Gesamtspeicherkosten
  s.Minimize(Cost_product+Cost_storage) #Minimieren Sie die Summe der gesamten Anschaffungskosten und der gesamten Lagerkosten
  rc = s.Solve()
  B,L,H,A = SolVal(Buy),SolVal(Blnd),SolVal(Hold),SolVal(Acid)
  CP,CS,P = SolVal(CostP),SolVal(CostS),SolVal(Prod)
  return rc,ObjVal(s),B,L,H,P,A,CP,CS

my_blend_multi.py


from blend_multi import solve_model

Content = [#Öl und Fettsäuren enthalten
    [36,20,33,6,4,0,1],
    [0,68,13,0,0,8,11],
    [0,6,0,66,16,5,7],
    [0,32,0,0,0,14,54],
    [0,0,49,3,39,7,2],
    [45,0,40,0,15,0,0,0],
    [0,0,0,0,0,28,72],
    [36,55,0,0,0,0,9],
    [12,48,34,0,4,2,0]
]

Target = [#Regulierung des Fettsäuregehalts
    [13.3,23.2,17.8,3.7,4.6,8.8,23.6],
    [14.6,25.7,19.7,4.1,5.0,9.7,26.1]
]

Price = [#Monatlicher Ölpreis
    [118,128,182,182,192],
    [161,152,149,156,174],
    [129,191,118,198,147],
    [103,110,167,191,108],
    [102,133,179,119,140],
    [127,100,110,135,163],
    [171,166,191,159,164],
    [171,131,200,113,191],
    [147,123,135,156,116]
]

Inventory = [#Anfangsbestand
    [15],[52],[193],[152],[70],[141],[43],[25],[89]
]

def main():
    import sys
    import tableutils
    m=len(Content)
    n=len(Content[0])
    k=len(Price[0])
    if len(sys.argv)<=1:
        print('Usage is main [content|target|cost|inventory|run] [seed]')
        return
    """ elif len(sys.argv)>2:
        random.seed(int(sys.argv[2])) """
    C = Content
    T = Target
    K = Price
    I = Inventory
    if sys.argv[1]=='content':  #Ausgabetabelle von Ölen und enthaltenen Fettsäuren
        for j in range(m):
            C[j].insert(0,'O'+str(j))
        C.insert(0,['']+['A'+str(i) for i in range(n)])
        tableutils.printmat(C,False,1)
    elif sys.argv[1]=='target': #Ausgabe der Regulierung des Fettsäuregehalts
        T.insert(0,['']+['A'+str(i) for i in range(n)])
        T[1].insert(0,'Min')
        T[2].insert(0,'Max') 
        tableutils.printmat(T,True,1)
    elif sys.argv[1]=='cost':   #Monatlichen Ölpreis ausgeben
        for j in range(m):
            K[j].insert(0,'O'+str(j))
        K.insert(0,['']+['Month '+str(i) for i in range(k)])
        tableutils.printmat(K)
    elif sys.argv[1]=='inventory':  #Geben Sie das zum Zeitpunkt der Entscheidung gehaltene Inventar aus
        for j in range(m):
            I[j].insert(0,'O'+str(j))
        I.insert(0,['Oil','Held'])
        tableutils.printmat(I)
    elif sys.argv[1]=='run':    #Führen Sie den Solver aus
        Demand=5000 #Monatliche Nachfrage nach Seife
        Limits=[0,1000]   #Unter- und Obergrenze, die Sie auf Lager haben können
        Cost=5
        rc,Value,B,L,H,P,A,CP,CS=solve_model(C,T,K,I,Demand,Cost,Limits)
        if len(B):
            A.append([0 for l in range(len(A[0]))])
            for j in range(len(A)-1):
                for l in range(len(A[0])):
                    A[j][l] = A[j][l]/P[l]
                    A[-1][l] += A[j][l] 
            for j in range(m):
                B[j].insert(0,'O'+str(j))
                L[j].insert(0,'O'+str(j))
                H[j].insert(0,'O'+str(j))
            for l in range(n):
                A[l].insert(0,'A'+str(l))
            A[-1].insert(0,'Total')
            B.insert(0,['Buy qty']+['Month '+str(i) for i in range(k)])
            L.insert(0,['Blend qty']+['Month '+str(i) for i in range(k)])
            H.insert(0,['Hold qty']+['Month '+str(i) for i in range(k)])
            A.insert(0,['Acid %']+['Month '+str(i) for i in range(k)])
            P=[P]
            P[0].insert(0,'Prod qty')
            CP=[CP]
            CP[0].insert(0,'P. Cost')
            CS=[CS]
            CS[0].insert(0,'S. Cost')

            tableutils.printmat(B,True,1)
            tableutils.printmat(L,True,1)
            tableutils.printmat(H,True,1)
            tableutils.printmat(P,True,1)
            tableutils.printmat(CP,True,2)
            tableutils.printmat(CS,True,2)
            tableutils.printmat(A,True,1)

main()

Ergebnis

Das Ausführen des obigen Codes führt zu folgenden Ergebnissen: image.png

image.png

image.png

image.png

image.png

Takashi konnte die Seifenfabrik gut betreiben.

Entwicklung

Hier sind einige der möglichen Entwicklungen dieses Beispiels. ・ Die monatliche Nachfrage schwankt

  • Die Maximierung der Gewinne ist vorrangig, anstatt die Nachfrage zu befriedigen. In diesem Fall ist der Verkaufspreis des Produkts erforderlich. ・ Verwalten Sie die Lagerbestände nach Öl, nicht nach Gesamtmenge ・ Es kann Unsicherheiten hinsichtlich der Menge an Fettsäuren geben, die in bestimmten Ölen enthalten sind. Etc.

Zusammenfassung

Diesmal bin ich wirklich müde

Recommended Posts

Mit OR-Tools erlernte Optimierung [Lineare Planung: Mehrstufiges Modell]
Mit OR-Tools erlernte Optimierung [Lineare Planung: Projektmanagement]
Mit OR-Tools erlernte Optimierung [Linearer Plan: Lassen Sie uns Öl raffinieren]
Mit OR-Tools Part0 erlernte Optimierung [Einführung]
Regression mit einem linearen Modell
Lineare Programmierung mit PuLP
Lösen mathematischer Optimierungsmodellübungen mit den OR-Tools von Google (3) Probleme bei der Produktionsoptimierung
Lösen Sie mathematische Optimierungsmodellübungen mit den OR-Tools von Google (4) Lösen Sie Zahlenstellen
[Python] Mit Pokemon erlernte objektorientierte Programmierung
[Mathematisches Optimierungsproblem] Lineare Programmiermethode mit PuLP
Optimierung der Produktionsplanung mittels linearer Programmierung (Python + PuLP)
Vorhersage des heißen Sommers mit linearem Regressionsmodell
Portfoliooptimierung mit Python (Markovitz-Durchschnittsverteilungsmodell)
Lernen Sie Wasserstein GAN mit Keras-Modell und TensorFlow-Optimierung