if bzw elif überschreibt Einträge in dictionary Sequenz

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
LtTuvok
User
Beiträge: 18
Registriert: Freitag 11. August 2017, 09:53

Hallo

Ich bin irgendwie (grad) zu blöd was zu verstehen. Ich arbeite mit der Anaconda-Distribution an einer Optimierung. Die Nebenbedingungen werden dabei als Sequenz von Dictionaries übergen, also z.B. cons=({"type": "eq", "fun": lambda x: ...}, {"type": "eq", "fun": lambda x: ...}, ...)
Ich versuche nun diese Sequenz von Dictionaries (und die minimize-Funktion) mit einer for-Schleife zu generieren, indem ich eine 2D-Liste habe, wie z.B. [["min",function1,wert1],["lower boundary",werte_liste1, boundary1], ["fix", werte_liste2, fix_wert1], ...].
Die for-Schleife liest dann 2D_liste[0] aus und überprüft mit if und alle weiteren möglichen Fällen mit elif, ob es sich um "min", oder "lower boundary", o.a. handelt und fügt dann die Nebenbedingung zu meinem Anfangstupel, cons({},) mittels cons+=({neue Nebenbedingung},) hinzu.
Das Ganze funktioniert, solange nur einmal der erste Fall in meiner 2D-Liste auftritt. Sobald ich zwei Einträge mit z.B. "fix" habe, ignoriert? oder überschreibt? er den ersten Eintrag. Das verstehe ich überhaupt nicht. Füge ich eine zweite "fix2"-Bedingung zu (siehe unten), dann klappt es, so als ob innerhalb der for-Schleife die Variablen wie global sind und cons+= nicht wirklich erweitert wird.
Hier der Teil meines Codes:

Code: Alles auswählen

optimization=["min",log_g1_list]
condition1=["fix",Deps_list,-4.2]
condition2=["fix2",tcl_list,85]
condition3=["larger than",log_K11_list,math.log(20)]
condition5=["lower than",log_K33_list,math.log(13)]
condition_list=[optimization,condition1,condition2,condition3,condition5]


cons=({'type': 'eq', 'fun': lambda x:  sum(x[i] for i in range(len(tcl_list)))-1},)
for condition in condition_list:
	if condition[0]=="min":
		min_list=condition[1]
		fun=lambda x: sum(x[y]*(1.0)*min_list[y] for y in range(len(min_list)))
	elif condition[0]=="max":
		max_list=condition[1]
		fun=lambda x: sum(x[y]*(-1.0)*max_list[y] for y in range(len(max_list)))
	elif condition[0]=="fix":
		fix_list=condition[1]
		fix_value=condition[2]
		cons+=({'type': 'eq', 'fun': lambda x: sum(x[y]*fix_list[y] for y in range(len(fix_list)))-fix_value},)
	elif condition[0]=="fix2":
		fix_list2=condition[1]
		fix_value2=condition[2]
		cons+=({'type': 'eq', 'fun': lambda x: sum(x[y]*fix_list2[y] for y in range(len(fix_list)))-fix_value2},)
	elif condition[0]=="lower than":
		lower_list=condition[1]
		lower_value=condition[2]
		cons+=({'type': 'ineq', 'fun': lambda x: sum(x[y]*(-1.0)*lower_list[y] for y in range(len(lower_list)))+lower_value},)
	elif condition[0]=="larger than":
		larger_list=condition[1]
		larger_value=condition[2]
		cons+=({'type': 'ineq', 'fun': lambda x: sum(x[y]*larger_list[y] for y in range(len(larger_list)))-larger_value},)
Viele Grüße,
Tuvok
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

entweder verstehe ich dein Problem nicht oder ich kann es nicht nachstellen... Welches Ergebnis erwartest du denn?

Gruß, noisefloor
LtTuvok
User
Beiträge: 18
Registriert: Freitag 11. August 2017, 09:53

Hallo noisefloor

Das Problem ist, dass alle Nebenbedingungen berücksichtigt werden sollten. Zum Beispiel habe ich in meiner 2D-Liste eine Nebenbedingung mit "fix" und der dazugehörigen Parameterwerteliste. Dann irgendwann später wieder ein "fix", wobei durch die for-Schleife in cons ein weiteres Dictionary eingetragen werden soll mit der anderen Parameterwerteliste. Wenn ich die Optimierung ausführe, verhält sich der Algorithmus aber so, als ob das erste Dictionary überschrieben worden wäre, quasie wie dict.update (weil sie ja auch beide die gleichen Schlüssel "type" und "fun" haben). Aber in cons wird ein weiterer Eintrag gemacht und += sollte sich ja auch nixht so verhalten. Es sieht also eher so aus, als ob der Eintrag aus irgendwelchen Gründen ignoriert wird. Wenn ich eine komplette cons-Sequenz vorgebe, so wie die for-Schleife das machen soll, funktioniert der Algorithmus wunderbar. Es muss direkt mit der for-Schleife und dem Einfügen der Dictionary-Tupel in cons aus der 2D-Liste zu tun haben.
Ich habe gehofft, dass jemand irgendwas schreibt wie "Klar Du Idiot! Wenn Du die elif-Bedingung nimmst, dann wird das Listenelement in das gleiche cons-Dictionary übertragen" Oder was weiß ich. Also ich habe das Gefühl einen nicht ganz so einfach zu findenden Anfängerfehler gemacht zu haben.

Was mich auch stutzig macht, ist dass ich in meinem Code bei der if-Bedingung min_list definieren muss und condition[1] nicht direkt übergeben kann. Aber Letzteres funktioniert nicht. Warum auch immer. Vielleicht liegen meine Probleme an der lambda Funktion?

Viele Grüße,
Tuvok
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

ehrlich gesagt verstehe ich das immer noch nicht...

Tupel sind in Python "immutable", d.h. der Inhalt ist fix. Du kannst in einem Tupel _keine_ Elemente verändern. Was dein Code macht ist ja ein neues Tupel (unter dem alten Namen) anzulegen, dass mehr ein Element mehr hat als das vorherige Tupel. Wenn du bestehende Inhalte _verändern_ willst, dann brauchst du eine Liste oder eine Dict.

Gruß, noisefloor
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@LtTuvok: bei Dir existiert nur ein `fix_list` oder `fix_value`, weil lambdas im Namensraum des Aufrufers leben:

Code: Alles auswählen

>>> def def_func():
...     a = 5
...     fun = lambda: a
...     a = 7
...     fun2 = lambda: a
...     return fun, fun2
... 
>>> f1, f2 = def_func()
>>> f1()
7
>>> f2()
7
LtTuvok
User
Beiträge: 18
Registriert: Freitag 11. August 2017, 09:53

Hallo

Ich (bzw. mit Hilfe der Info von Sirius3) habe den Fehler gefunden, wenn gleich ich ihn auch noch nich 100%ig verstanden habe. Aber durch die Definition von Funktionen (z.B. min-func(list, value): lambda x: ...), die dann die lambda-Funktion beinhalten, auf die ich in meinerm for-Schliefe verweise (also außerhalb) funktioniert das Programm!!! Ich bin sehr froh! Ich werde mich in Zukunft noch einmal besser mit der lambda Funktion bzw. anonymen Funktionen beschäftigen müssen.

Viele Grüße,
Tuvok
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@LtTuvok: statt Funktionen zu schachteln, ist es besser Klassen zu definieren, die den Zustand sauberer in Attributen speichern und über eine __call__-Methode verfügen, so dass sie wie Funktionen verwendet werden können.
LtTuvok
User
Beiträge: 18
Registriert: Freitag 11. August 2017, 09:53

Hallo Sirius3

Danke! Ja, das sollte ich als nächstes mal machen. Ich habe schon ein paar Funktionen, die etwas verschachtelt sind. Besser ich fange an mit Klassen zu arbeiten und den Code daraufhin neu zu schreiben.

Viele Grüße,
Tuvok
Antworten