Bei der Modellformulierung von Problemen größerer Firmen trifft man häufig auf die Situation, dass nicht ein einzelner Standort, sondern gleich ein Verbund mehrerer Standorte abgebildet werden muss. Daher wird in dieser Lektion ein Produktionsplanungsproblem mit mehreren Standorten formuliert. Daher wird in dieser Lektion das Modell aus der vorherigen Lektion aufgegriffen und um einen Standort-Index erweitert, dessen Elemente alle verfügbaren Standorte sind, an denen die Produkte produziert werden können. Hierzu werden wieder schrittweise alle Vektoren um diesen Index erweitert.
Standortindizes sind sehr nützlich in Produktionsplanungsmodellen. Sie können Produktionsstandorte, Warenhäuser oder z.b. Verteilzentren repräsentieren.
Die Standorte, die durch die Elemente der Standortindexmenge benannt werden, sind meist durch Transportwege verknpüft. Daher werden derartige Modelle auch häufig Transport- oder Distributionsmodelle genannt; sie werden in einer späteren Lektion behandelt.
Bei kleineren, überschaubaren Modellen ist es möglich und auch häufig sinnvoll, die Daten gleich in der Modelldatei zu definieren. Sobald man aber mehrdimensionale Vektoren mitführt, wird dies sehr mühsam und es ist sinnvoller, die Daten in externen Dateien zu halten. Dies verbessert zum einen die Lesbarkeit der Daten, macht aber auch die Pflege der Daten in dafür geeigneteren Strukturen einfacher.
Das in dieser Lektion zu erstellende Modell enthält Variablenvektoren, die von den drei Indizes product, month, und plant abhängen, aber auch zwei-dimensionale Datenvektoren, wie z.b. den Demand-Vektor, dessen Daten nun aus einer externen Datei bezogen werden sollen. Hierzu kann das Befehlswort DATAFILE in Verbindung mit dem Namen der Datendatei wie im folgenden Beispiel verwendet werden:
demand[product, month] := DATAFILE("Demand.dat");
In dieser Lektion soll ein neues Produktionsplanungsmodell entwickelt werden, das als weiteren Index einen Index für die Produktionsstandorte enthält.
Hierzu sollen vier verschiedene Standorte p1, p2, p3 und p4 berücksichtigt werden, von denen jeder jedes Produkt herstellen kann. Zu diesem Zeitpunkt sei die Feinstruktur der Standorte, d.h. die Existenz individueller Anlagen, noch nicht weiter betrachtet; dies erfolgt erst in Lektion 7. In dieser Lektion wird zunächst die Indexmenge plants erzeugt, die die vier verschiedenen Standorte enthält; anschliessend wird der neue Index zu den entsprechenden Vektoren hinzugefügt.
Die Verkaufspreise je Produkt $120.00, $100.00 und $150.00 sollen, wie auch die Verkaufsnachfragen, gegenüber de vorherigen Lektion unverändert bleiben.
Allerdings soll jeder Standort verschiedene Produktionskosten haben; diese sind in der nachfolgenden Tabelle gezeigt:
Production Cost | A1 | A2 | A3 |
---|---|---|---|
plant 1 | $73.30 | $52.90 | $65.40 |
plant 2 | $79.00 | $52.00 | $66.80 |
plant 3 | $75.80 | $52.10 | $50.90 |
plant 4 | $82.70 | $63.30 | $53.80 |
Wie die nachfolgende Tabelle zeigt, sind nun auch die Produktionsraten für jedes standortabhängig:
Production Rate | A1 | A2 | A3 |
---|---|---|---|
plant 1 | 500 | 450 | 450 |
plant 2 | 550 | 450 | 300 |
plant 3 | 450 | 350 | 300 |
plant 4 | 550 | 400 | 350 |
Nachstehend ist das vollständige Modell für das Problem Planning5 aufgelistet. Gegenüber der Formulierung in Lektion 4 sind einige Erweiterungen erkennbar; sie sind im Fettdruck hervorgehoben und leicht zu verfolgen.
TITLE Production_Planning5; INDEX product := (A1, A2, A3); month := (Jan, Feb, Mar, Apr); plant := (p1, p2, p3, p4); DATA Price[product] := (120.00, 100.00, 115.00); Demand[product, month] := DATAFILE("Demand.dat"); ProdCost[plant, product] := DATAFILE("ProdCost.dat"); ProdRate[plant, product] := DATAFILE("ProdRate.dat"); ProdDaysAvail[month] := (23, 20, 23, 22); InvtCost[product] := (3.50, 4.00, 3.00); InvtCapacity := 800; VARIABLES Produce[plant, product, month] -> Prod; Inventory[product, month] -> Invt; Sales[product, month] -> Sale; MACROS TotalRevenue := SUM(product, month: Price * Sales); TotalProdCost := SUM(plant, product, month: ProdCost * Produce); TotalInvtCost := SUM(product, month: InvtCost * Inventory); TotalCost := TotalProdCost + TotalInvtCost; MODEL MAX Profit = TotalRevenue - TotalCost; SUBJECT TO ProdCapacity[plant, month] -> PCap: SUM(product: Produce / ProdRate) <= ProdDaysAvail; InvtBal[product, month] -> IBal: SUM(plant: Produce) + Inventory[month-1] = Sales + Inventory; MaxInventory[month] -> MaxI: SUM(product: Inventory) <= InvtCapacity; BOUNDS Sales <= Demand; END
Start der MPL Applikation.
Wähle File | Open und öffne die Modelldatei Planning4.mpl aus der vorherigen Lektion.
Wähle File | Save As zum Speichern der neuen Modelldatei Planning5.mpl.
Der Titel des Modells soll geändert werden um klarzustellen, dass nun mit der Modelldatei Planning5 gearbeitet wird.
TITLE Production_Planning5;
In diesem Beispiel sind vier Standorte zu berücksichtigen. Der neu zu erstellende Index soll plant heissen und die vier Element p1, p2, p3 und p4 haben. Zunächst soll die Definition für den Index plant, wie sie in Fettdruck hervorgehoben ist, zum INDEX-Abschnitt hinzugefügt werden:
INDEX product := (A1, A2, A3); month := (Jan, Feb, Mar, Apr); plant := (p1, p2, p3, p4);
In dieser Lektion sollen die Werte für den zweidimensionalen Datenvektor 'Demand' von einer externen Datei bezogen werden. Dies verbessert die Lesbarkeit des Modells, aber auch die Pflege der Daten.
Um den Demand Datenvektor mit einer exteren Datei zu verknüpfen, wird im DATA-Abschnitt der Cut-Befehl aus dem Edit-Menu verwendet, um die Werteliste aus der Definition des DemandVektors zu entfernen und anschliessend durch das Schlüsselwort DATAFILE und den Dateinamen Demand.dat wie folgt zu ersetzen:
DATA Price[product] := (120.00, 100.00, 115.00); Demand[product, month] := DATAFILE("Demand.dat");
Als nächstes ist nun die Datei Demand.dat zu erzeugen. Dazu wird ein neues Editorfenster durch Wahl von New im File-Menu geöffnet. Wurde im vorherigen Schritt 4 der Edit | Cut-Befehl verwendet, um die Daten zu entfernen, so sind können diese dem Clipboard wieder mit dem Edit | Paste-Befehl entnommen werden. Andernfalls können die Daten der Problembeschreibung in Lektion 3 entnommen und hier wieder neu eingegeben werden:
! Demand.dat - Demand per month for each product ! ! Demand[product,month]: ! ! Jan Feb Mar Apr ! ---------------------------- 4300, 4200, 6400, 5300, 4500, 5400, 6500, 7200, 5400, 6700, 7800, 8200
Die mit einem Ausrufezeichen beginnenden Zeilen sind lediglich Kommentarzeilen zur Erhöhung der Lesbarkeit. Die Zahlenwerte selbst können durch Kommas, Leerzeichen oder beides getrennt werden. Nach Eingabe aller Daten soll die Datei unter dem Namen Demand.dat in das Tutorial-Vereichnis gespeichert werden.
Zwei der im Modell enthaltenen Datenvektoren, ProdCost und ProdRate, müssen um den plant-Index erweitert werden. Der ProdCost-Datenvektor ist nun sowohl vom plant- als auch vom product-Index abhängig und wird von einer externen Datendatei mit Werten gefüllt. Der ProdRate wird nun ebenfalls mit einer externen Datendatei verknpüft. Dazu wird im Modelleditor der plant zur Deklaration der ProdCost und ProdRate-Datenvektoren hinzugefügt und mit den Dateien ProdCost.dat und ProdRate.dat wie folgt verknpüft:
Die mit einem Ausrufezeichen beginnenden Zeilen sind lediglich Kommentarzeilen zur Erhöhung der Lesbarkeit. Die Zahlenwerte selbst können durch Kommas, Leerzeichen oder beides getrennt werden. Nach Eingabe aller Daten soll die Datei unter dem Namen Demand.dat in das Tutorial-Vereichnis gespeichert werden.
ProdCost[plant, product] := DATAFILE("ProdCost.dat"); ProdRate[plant, product] := DATAFILE("ProdRate.dat"); ProdDaysAvail[month] := (23, 20, 23, 22); InvtCost[product] := (3.50, 4.00 3.00); InvtCapacity := 800;
Mit File | New im Menu wird ein neues Fenster zur Eingabe der Daten erzeugt. Hier werden nun die Produktionskosten aus der Problembeschreibung übernommen:
! ! ProdCost.dat - Cost per item produced ! ! ProdCost[plant, product]: ! ! A1 A2 A3 ! ----------------------- 73.30, 52.90, 65.40, 79.00, 52.00, 66.80, 75.80, 52.10, 50.90, 82.70, 63.30, 53.80
Wiederum sind zur Erhöhung der Lesbarkeit mit einem Ausrufezeichen markierte Kommentarzeilen eingefügt. Nach Eingabe aller Daten wird die Datei unter der Bezeichnung ProdCost.dat gespeichert.
Für die Produktionsraten soll nun die ProdRate.dat erzeugt und mit den Werten aus der Tabelle der Problembeschreibung gefüllt werden.
! ! ProdRate.dat - Items produced per day ! ! ProdRate[plant, product]: ! ! A1 A2 A3 ! ------------------ 500, 450, 450, 550, 450, 300, 450, 350, 300, 550, 400, 350
Um die Entscheidungen zu verfolgen, wieviel von jedem Produkt an jedem Standort produziert wird, muss der plant-Index zur Definition der Vektorvariablen Produce wie folgt hinzugefügt werden:
VARIABLES Produce[plant, product, month] -> Prod; Inventory[product, month] -> Invt; Sales[product, month] -> Sale;
Da die Produce-Variable nun den neuen plant-Index enthält, muss die Berechnung der gesamten Produktionskosten im MACROS-Abschnitt ebenfalls angepasst und um den plant-Index erweitert werden:
MACROS TotalRevenue := SUM(product, month: Price * Sales); TotalProdCost := SUM(plant, product, month: ProdCost * Produce) ; TotalInvtCost := SUM(product, month: InvtCost * Inventory); TotalCost := TotalProdCost + TotalInvtCost;
Die Zielfunktion selbst braucht nicht geändert zu werden, da dieselben Makros wie in der vorherigen Lektion verwendet werden.
Die Änderungen, die die Produktionskapazitätsbedingung betreffen sind sehr einfach vorzunehmen. Es braucht lediglich der plant-Index zur Deklaration der Nebenbedingung hinzugefügt zu werden; alles übrige bleibt unverändert.
SUBJECT TO ProdCapacity[plant, month] -> PCap: SUM(product: Produce / ProdRate) <= ProdDaysAvail;
Da alle Produkte an jedem der vier Standorte produziert werden können, muss nun in der Lagerblanzgleichung eine Summierung der Produktionsvariablen über alle Standorte erfolgen.
InvtBal[product, month] -> IBal: SUM(plant: Produce) + Inventory[month-1] = Sales + Inventory;
Nach dieser Ersetzung sind nun alle Korrekturen beendet und die Modelldatei kann durch Wahl von Save im File-Menu gespeichert werden.
Durch die zusäztzlichen Indizes ist die Anzahl der Variablen enorm angewachsen. Bei großen, umfangreichen Modellen mit vielen Variablen ist es nicht unbedingt sinnvoll, alle Variablen auszuweisen. Wir wollen daher nur die Variablen in der Lösungsdatei betrachten, deren Lösungswert von Null verschieden ist. MPL bietet im Options-Menu eine Reihe von Optionsdialogfenster, mit denen das standardmässige Verhalten beeinflusst werden kann. Eine dieser Dialogfenster heisst Solution File Options und bietet die Möglichkeit, die Ausgabe und die Details für den Ausdruck in die Lösungsdatei zu beeinflussen. Um zu bewirken, dass nur Variablen in die Lösungsdatei aufgenommen werden, deren Werte von Null verschieden sind, ist wie folgt vorzugehen:
Aus dem Options-Menu wird Solution File ausgewählt, um das nachfolgend gezeigte Options Dialogfenster zu öffnen:
Das Options-Dialogfenster für die Lösungsdatei
Aktivieren der Nonzero Values Only-Feldes On durch Anklicken.
Das Dialogfenster wird durch Drücken der OK-Taste geschlossen.
Nach Änderung der Nonzero Values Only-Option, soll das durch 'Planning5.mpl' kodierte Problem nun gelöst werden. Hierzu wird im Run-Menu die Option Solve CPLEX gewählt. Sofern alle Daten richtig eingegeben und alle Modifikationen korrekt durchgeführt wurden, meldet sich MPL mit der Meldung Optimal Solution Found zurück. Bei Identifizierung eines Syntaxfehlers ist die Eingabe des Modells nocheinmal zu überprüfen.
Da das Modell größer und größer wird, ist es eher praktikabel, nur bestimmte Teile der Lösung anzuschauen. Hier bietet sich es sich an, in einem Fenster die hierarchische Baumstruktur des Modells zu nutzen und nur die Teile der Lösung anzuschauen, die wirklich interessant sind.
MPL unterstützt die Visualisierung aller definierten Objekte eines Modells in einem hierarchischem Baum im sogenannten Modell-Definitions-Fenster. Jeder Zweig dieses Baumes entspricht einem Abschnitt des Modells. Allgemein scheint es ratsam, während der Arbeit mit MPL das Modell-Definitions-Fenster ständig geöffnet zu lassen. MPL aktualisiert dann ständig den Inhalt dieser Fenster. Um nun die Modelldefinitionen für das Planning5-Modells zu zeigen, wird Model Definitions aus dem View-Menu gewählt.
Das Modell-Definitions-Fenster für das Planning5-Modell
Aus dem Baum kann nun jedes beliebige Modellobjekt mit seinem zugehörigen einer genaueren Betrachtung unterzogen werden. Um zu Beispiel die Werte der Produktions-Variablen zu inspizieren, wird das Produce-Objekt im Baum gewählt und mit der View-Taste bestätigt. Dies erzeugt ein Fenster, dass die von Null verschiedenen Produktions-Variablen anzeigt.
VARIABLE Produce[plant,product,month] : plant product month Activity Reduced Cost ----------------------------------------------------------- p1 A1 Jan 4300.0000 0.0000 p1 A1 Feb 4200.0000 0.0000 p1 A1 Mar 6400.0000 0.0000 p1 A1 Apr 5300.0000 0.0000 p2 A2 Jan 4500.0000 0.0000 p2 A2 Feb 5400.0000 0.0000 p2 A2 Mar 6500.0000 0.0000 p2 A2 Apr 7200.0000 0.0000 p3 A3 Jan 5400.0000 0.0000 p3 A3 Feb 6000.0000 0.0000 p3 A3 Mar 6900.0000 0.0000 p3 A3 Apr 6600.0000 0.0000 p4 A3 Feb 700.0000 0.0000 p4 A3 Mar 900.0000 0.0000 p4 A3 Apr 1600.0000 0.0000 -----------------------------------------------------------
Bei der Betrachtung der Produktions-Variable fällt auf, dass nun genug Produktionskapazität zur Verfügung steht, um alle Nachfragen zu befriedigen. Interessant ist auch zu sehen, wie der Solver entscheidet, welcher Standort für welches Produkt 'zuständig' ist. Zum Beispiel wird am p1 das Produkt A1, am Standort p2 das Produkt A2 und schliesslich an den Standorten p3 und p4 das Produkt A3 produziert.
Verwendet man das Modell-Definitions-Fenster nun, um die ProdCapacity-Bedingung genauer anzuschauen, so erhält man die folgenden Werte:
CONSTRAINT ProdCapacity[plant,month] : plant month Slack Shadow Price -------------------------------------------------- p1 Jan 14.4000 0.0000 p1 Feb 11.6000 0.0000 p1 Mar 10.2000 0.0000 p1 Apr 11.4000 0.0000 p2 Feb 8.0000 0.0000 p2 Mar 8.5556 0.0000 p2 Apr 6.0000 0.0000 p3 Jan 5.0000 0.0000 p4 Jan 23.0000 0.0000 p4 Feb 18.0000 0.0000 p4 Mar 20.4286 0.0000 p4 Apr 17.4286 0.0000 --------------------------------------------------
Hier fällt auf, dass für alle Standorte und Monate die Werte der Schlupfvariablen anzeigen, dass noch erheblich mehr produziert werden kann; da bereits alle Nachfragen erfüllt sind, geschieht dies nicht. Zur Interpretation der Schlupfvariablen ist noch zu bemerken, dass diese, da die Produktionskapazitätsbeschränkung in Tagung spezifiziert sind, die Anzahl der freien Tage der einzelnen Standorte angeben.