Seite 1 von 1

Klassische Denkblockade: variable Variablennamen

Verfasst: Freitag 27. November 2015, 23:24
von derhendrik
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

Re: Klassische Denkblockade: variable Variablennamen

Verfasst: Freitag 27. November 2015, 23:34
von derhendrik
Hm, jetzt wo ich nochmal nachdenke, suche ich wahrscheinlich ein Dict, in dem der Key ein Tuple ist...

Re: Klassische Denkblockade: variable Variablennamen

Verfasst: Freitag 27. November 2015, 23:48
von pillmuncher
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]}}

Re: Klassische Denkblockade: variable Variablennamen

Verfasst: Samstag 28. November 2015, 01:06
von snafu
Man könnte auch `defaultdict` nutzen:

Code: Alles auswählen

from collections import defaultdict

data = defaultdict(lambda: defaultdict(list))
data['A']['x'].append(42)

Re: Klassische Denkblockade: variable Variablennamen

Verfasst: Samstag 28. November 2015, 01:40
von pillmuncher
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}}}