Lösung spezieller kubischer Funktion

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
F.S.
User
Beiträge: 7
Registriert: Donnerstag 17. Juni 2010, 09:51

Hallo zusammen,

erster Beitrag und gleich ein Programmierproblem.... :)
Ich arbeite mit python 2.6 und nutze bei der Programmierung Spyder.

Es geht um die Nullstelle der folgenden kubischen Funktion:

Code: Alles auswählen

def func_v(v, x): 
    return (c1*v**3)+(func_1(v)*c2*(c3+func_3(x[2]))*v)-(c4)
v ist der Wert, den ich bei der Nullstellensuche variieren möchte.
x = [x0,x1,x2] ist ein array mit aktuell 3 Parametern, die während des gesamten Programmverlaufs optimiert werden sollen.
c1,c2,... sind diverse Konstanten, die sich im gesamten Programmverlauf nicht ändern.
func_1 bestimmt einen von v abhängigen Parameter (könnte eventuell auch noch mit in func_v hineingezogen werden, wäre nur etwas unübersichtlicher).

Wäre da nicht der Term "func_3(x[2])", also die Abhängigkeit von einer weiteren Variable, würde folgendes problemlos funktionieren, so habe ich das bisher gemacht:

Code: Alles auswählen

r_v=brentq(func_v, a, b)
(brentq aus scipy.optimize)

Beide Variablen, also v und x[2], variieren zu lassen um eine Nullstelle zu finden wäre jetzt auch kein Problem.

Aber wie schaffe ich es, dass ich den Wert x[2] an die Funktion übergebe, sodass x[2] während der Nullstellensuche konstant bleibt, beim nächsten Aufruf von func_v aber mit einem anderen Wert haben kann?
(ich also func_v z.B. für alle x zwischen 1 und 100 auswerten kann)
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Hallo und Willkommen im Forum,

du könntest ''lambda'' verwenden:

Code: Alles auswählen

In [78]: def f(x,b):
             return (x - b)**3
   ....: 

In [80]: for b in [-2,0,2]:
             brentq(lambda x: f(x,b), -2, 2)
   ....:     
   ....:     
Out[81]: -2.0
Out[81]: 0.0
Out[81]: 2.0
Grüße
Gerrit
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

F.S. hat geschrieben:Aber wie schaffe ich es, dass ich den Wert x[2] an die Funktion übergebe, sodass x[2] während der Nullstellensuche konstant bleibt, beim nächsten Aufruf von func_v aber mit einem anderen Wert haben kann?
Ich verstehe nicht was du willst, aber vielleicht ist es das args-Argument was du suchst?

Code: Alles auswählen

r_v=brentq(func_v, a, b, args=(x,))
F.S.
User
Beiträge: 7
Registriert: Donnerstag 17. Juni 2010, 09:51

@gkuhl:

Danke für der Vorschlag - wird ausprobiert!

Hab selbst nochmal "geforscht":
Eventuell lässt sich das Ganze auch objektorientiert lösen, indem man die augenblickliche Konfiguration in einem Objekt hinterlegt, auf das dann auch aus den einzelnen Funktionen zugegriffen werden kann (lesen wie ändern) .

@Darii:

Danke für die Antwort!
Ich verstehe nicht was du willst, aber vielleicht ist es das args-Argument was du suchst?
Vllt. noch einmal eine Beschreibung meines Problems:
Ich habe diese Funktion, die von x³ und einer weiteren Variable abhängt. Jetzt möchte ich den Wert für x finden, für den meine Funktion 0 wird (Nullstelle) - bei dieser einen gegebenen Variable. Hart eincodieren kann ich die Zahl nicht, da sie beim nächsten Programmdurchlauf anders aussehen wird.
brentq kann nur Funktionen aufrufen, die von 1 Variable abhängen (also kann ich diese zusätzliche Variable nicht beim Funktionsaufruf, Optmierungsallgorithmen optimieren gewöhnlich über allen Variablen.

Mit dieser args-Funktion habe ich bereits ein bißchen herum experimentiert - bin aber dabei zu keinem sinnvollen Ergebnis gekommen. Wie man diese Funktion benutzen müsste und was sie eigentlich genau bewirkt, erschließt sich mir aus der Beschreibung leider nicht ganz:

Code: Alles auswählen

args : tuple containing extra arguments for the function f.
    f is called by apply(f,(x)+args).
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

args ist keine Funktion, sondern ein Tupel mit Argumenten für den späteren (internen) Aufruf von func_v - dieses wird dann aufgerufen als:

Code: Alles auswählen

func_v((x,) + args)
woraus dann

Code: Alles auswählen

func_v(x, args[0], args[1], ...)
wird. Wenn du also brentq aufrufst, tu das so, wie Darii es gezeigt hat, mit args=(x,), wobei x die Zahl ist, die du zusätzlich übergeben willst, nicht wie bei dir eine Liste von Zahlen. Dann würde das ganze in etwa so aussehen:

Code: Alles auswählen

def func_v(v, n):
    return (c1*v**3)+(func_1(v)*c2*(c3+func_3(n))*v)-(c4)
...                                    # hier ^ nix mehr x[2]
for m in x:
    r_v = brentq(func_v, a, b, args=(m,))
    ... #irgendwas mit r_v anstellen
In specifications, Murphy's Law supersedes Ohm's.
F.S.
User
Beiträge: 7
Registriert: Donnerstag 17. Juni 2010, 09:51

Danke dir!
Die Lösung gefällt mir noch besser als mit dem Lambda - wenn jede Formel ihre eigene Funktion behält, bleibt das Ganze flexibler und übersichtlicher.
F.S.
User
Beiträge: 7
Registriert: Donnerstag 17. Juni 2010, 09:51

So, Problem ist gelöst. :D

Letztlich habe ich es über Klassen erledigt, also in der Zeile vor "brentq" den Problemwert func_3(x[2]) berechnet und in der Klasse MeineKlasse als MeineKlasse.wert gespeichert. So ist MeineKlasse.wert aus allen Funktionen aufrufbar und seine Rechenparameter in eine Klasse zu stecken dürfte auch besserer Programmierstil sein, als sie irgendwo im Haupttextblock zu definieren.

Vielen Dank euch nochmal für eure Hilfe, auch wenn ich es letztlich anders gelöst habe!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.
F.S. hat geschrieben:So ist MeineKlasse.wert aus allen Funktionen aufrufbar und seine Rechenparameter in eine Klasse zu stecken dürfte auch besserer Programmierstil sein, als sie irgendwo im Haupttextblock zu definieren.
Klassen an unangebrachten Stellen ist nicht unbedingt besser ;-) Dariis und pillmunchers Lösungen scheinen mir hier der richtige Weg, als Alternative bietet sich noch "functools.partial" an. Und wenn du schon Klassen benutzt, dann doch richtig und nicht über ein "wert"-Argument. Schau dir mal die "__call__"-Methode an.

Sebastian
Das Leben ist wie ein Tennisball.
Antworten