Klassische Denkblockade: variable Variablennamen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
derhendrik
User
Beiträge: 17
Registriert: Donnerstag 15. Januar 2015, 16:39

Hallo Pythonfreunde!

Mittlerweile habe ich es schon 100 mal gelesen, Artikel mit den Titeln "Why you don't want to dynamically create variables" oder "Keep data out of your variable names". Diese machen auch unheimlich viel Sinn und verweisen immer wieder auf Dictionaries bzw. Listen, dennoch komme ich aber bei meinem jetzigen Problem nicht weiter. Ich glaube die Umsetzung ist relativ trivial, leider sehe ich zum jetzigen Zeitpunkt aber den Wald vor lauter Bäumen nicht.

Zum Hintergrund: Ich nutze derzeit Pulp um ein Lineares Programm (Optimierungsproblem unter Randbedingungen aus der BWL) zu formulieren. Im Vorfeld weiß ich, dass ich 2 Motoren ansteuere (Motor A und Motor B) und 1400 Zeitinkremente habe. Dazu habe ich für jeden Zeitschritt eine binäre Variable xa (für Motor A) und eine xb (für Motor B), wobei 1 jeweils "An" und 0 eben "Aus" bedeutet. Durch technische Restriktionen, welche ich durch die Formulierung der Randbedingungen berücksichtige, habe ich zusätzlich noch für jeden Zeitschritt die binäre Variablen sa und sb (ob Motor A bzw. B in t startet) und eben ha und hb (ob Motor A bzw. B in t hält).

Die Modellerstellung, das Lösen mittels Gurobi, etc. hat bis jetzt alles wunderbar geklappt. Jetzt möchte ich diese Modellerstellung aber eben parametrieren, d.h. dass ich es als Funktion aufrufe und im Vorfeld nicht weiß, ob ich Motor A & B habe oder vielleicht Motor A, Motor B, Motor C und Motor D.

Ich zeig euch einfach mal was ich meine:

So habe ich es am Anfang per Hand gemacht:

Code: Alles auswählen

from pulp import *

prob_kssplus = LpProblem("prob_kssplus",LpMinimize)

xa0 = LpVariable("xa0",0,1,LpInteger)
xa1 = LpVariable("xa1",0,1,LpInteger)
xa2 = LpVariable("xa2",0,1,LpInteger)
xa3 = LpVariable("xa3",0,1,LpInteger)
...

xb0 = LpVariable("xb0",0,1,LpInteger)
xb1 = LpVariable("xb1",0,1,LpInteger)
xb2 = LpVariable("xb2",0,1,LpInteger)
xb3 = LpVariable("xb3",0,1,LpInteger)
... 
(usw. undsofort, analog fuer sa,ha,sb,hb)
Dann mit Schleife, wobei ich jedoch im Vorfeld wusste, dass es nur A und B gibt

Code: Alles auswählen

xa = dict()
sa = dict()
ha = dict()

xb = dict()
sb = dict()
hb = dict()

for i in range(1400):
            # Komponente a 
            xa[i]=LpVariable('xa'+str(i).zfill(5),0,1,LpInteger)
            sa[i]=LpVariable('sa'+str(i).zfill(5),0,1,LpInteger)
            ha[i]=LpVariable('ha'+str(i).zfill(5),0,1,LpInteger)
            
            # Komponente b 
            xb[i]=LpVariable('xb'+str(i).zfill(5),0,1,LpInteger)
            sb[i]=LpVariable('sb'+str(i).zfill(5),0,1,LpInteger)
            hb[i]=LpVariable('hb'+str(i).zfill(5),0,1,LpInteger)
Jetzt ist meine Hoffnung, dieses mit einem "Einzeiler" umzusetzen, auch wenn ich im Vorfeld noch nicht die Anzahl der Motoren kenne:
Circa so:

Code: Alles auswählen

motoren = ["A","B","C"] #Die bekomme ich dann von extern übergeben
zustaende =["x","s","h"]

for motor in motoren:
	for zustand in zustaende:
		for i in range(1400):
			zustand+motor+i = LpVariable(zustand+motor+str(i).zfill(5),0,1,LpInteger) #Ist natürlich quatsch was hier steht, soll nur den Sinn verdeutlichen
Wie ihr seht, würde ich gerne einfach den Variablenname variabel gestalten. Dies ist ja aber anscheinend ein großes No-Go. Habt ihr eine Idee, wie ich dieses Problem am einfachsten lösen kann? Glaube eigentlich, dass es relativ einfach ist. Sehe es aber partout nicht und stehe ein bisschen auf dem Schlauch. Würde mich über eine Antwort freuen!

Gruß

Hendrik
derhendrik
User
Beiträge: 17
Registriert: Donnerstag 15. Januar 2015, 16:39

Hm, jetzt wo ich nochmal nachdenke, suche ich wahrscheinlich ein Dict, in dem der Key ein Tuple ist...
Benutzeravatar
pillmuncher
User
Beiträge: 1527
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Du bist ja schon selber draufgekommen, was du tun solltest. Trotzdem hier ein Beispiel dazu:

Code: Alles auswählen

In [1]: motoren = "ABC"

In [2]: zustände = "xsh"

In [3]: data = {}

In [4]: for motor in motoren:
    ...:     data[motor] = {}
    ...:     for zustand in zustände:
    ...:         data[motor][zustand] = []
    ...:         for i in range(14):
    ...:             data[motor][zustand].append(i * 3)
    ...:             

In [5]: data
Out[5]: 
{'A': {'h': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39],
  's': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39],
  'x': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39]},
 'B': {'h': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39],
  's': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39],
  'x': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39]},
 'C': {'h': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39],
  's': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39],
  'x': [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39]}}
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
snafu
User
Beiträge: 6834
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Man könnte auch `defaultdict` nutzen:

Code: Alles auswählen

from collections import defaultdict

data = defaultdict(lambda: defaultdict(list))
data['A']['x'].append(42)
Benutzeravatar
pillmuncher
User
Beiträge: 1527
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Oder mit Autovivifikation:

Code: Alles auswählen

In [1]: from collections import defaultdict

In [2]: from pprint import pprint

In [3]: def tree():
   ...:     return defaultdict(tree)
   ...: 

In [4]: motoren = "ABC"

In [5]: zustände = "xsh"

In [6]: data = tree()

In [7]: for motor in motoren:
   ...:     for zustand in zustände:
   ...:         for i in range(3):
   ...:             data[motor][zustand][i] = i * 3
   ...:             

In [8]: pprint(data)
{'A': {'h': {0: 0,
             1: 3,
             2: 6},
       's': {0: 0,
             1: 3,
             2: 6},
       'x': {0: 0,
             1: 3,
             2: 6}},
 'B': {'h': {0: 0,
             1: 3,
             2: 6},
       's': {0: 0,
             1: 3,
             2: 6},
       'x': {0: 0,
             1: 3,
             2: 6}},
 'C': {'h': {0: 0,
             1: 3,
             2: 6},
       's': {0: 0,
             1: 3,
             2: 6},
       'x': {0: 0,
             1: 3,
             2: 6}}}
In specifications, Murphy's Law supersedes Ohm's.
Antworten