2016-08-07 105 views
1

Ich benutze sympy 1.0 mit Python 2.7.10 auf einem Mac. Das Problem ist, dass wenn ich Floats für Parameter anstelle von Ints verwende, scheint solve() für immer zu drehen.Sympy arbeitet mit int params, aber spinnt mit floats

Hier ist mein Skript, mit a, b und c wie int angegeben. Es gibt die folgende Ausgabe mit oder ohne a, b smpifying und c:

from sympy import * 

x = symbols('x') 
a = 500 
b = 10 
c = 333 

y = a + b * (x - c) - (a * (x/c) + x * b * log(x/c)) 

print 'y=', y 

solution = solve(y, x) 
print 'solve() gives:', solution 

Diese Drucke:

y= -10*x*log(x/333) + 2830*x/333 - 2830 
solve() gives: [333*exp(LambertW(-283*exp(-283/333)/333) + 283/333)] 

Das ist richtig, wie ich durch die Lösung numerisch mit nSolve prüft haben() und Vergleichen mit einer unabhängig berechneten Lösung.

Nun ändern Sie die Definition von a, b und c:

a = 500.0 
b = 10.0 
c = 333.0 

Dann wird die Ausgabe wie folgt:

y= -10.0*x*log(0.003003003003003*x) + 8.4984984984985*x - 2830.0 

Damit lösen() dreht, scheinbar für immer. Beachten Sie, dass dieser Ausdruck numerisch korrekt angezeigt wird.

Also noch einmal, die Frage ist: Wie kann ich Gleitkommaparameter in sympy Gleichungen verwenden?

Antwort

0

Ich kann nicht sagen, warum Sympy Probleme hat, aber ich vermute, dass es damit zu tun hat, dass die Gleitkommadarstellung nicht exakt ist.

Eine Abhilfe zu solve sein würde, ohne explizit die Parameter spezifiziert a, b und c, und verwenden Sie dann .subs()

import sympy as sp 
x, a, b, c = sp.symbols('x, a, b, c') 
y = a + b * (x - c) - (a * (x/c) + x * b * sp.log(x/c)) 
sol = sp.solve(y, x) 

# find the second root manually by considering the k=-1 branch 
# (solve provides only the k=0 branch) 
sol_two_branches = [sol[0], sol[0].replace(sp.LambertW, lambda *args: sp.LambertW(*args,-1))] 

print([s.subs({a:500,b:10,c:333}).n() for s in sol_two_branches]) 
[333.000000000000, 242.528588686908] 

PS: Kredit für infroming mich über die Zweigauswahl an @asmeuer geht Option von LambertW

+0

Ich versehentlich vor dem Beenden veröffentlicht. Ich wollte sagen: Zuerst sehe ich, was Sie sehen, mit Schwimmern. Zweitens, wenn ich Intars anstelle der Floats verwende, bekomme ich die Lösung, die ich zuvor mit LambertW gesehen habe, anstatt eine numerische Lösung. Seltsam. Drittens gibt solve() einen einzelnen Ausdruck zurück; aber es gibt zwei Wurzeln. Der andere ist in der Nähe von 242.259. Sollte ich nicht erwarten, dass solve() auch dieses findet? – wchlm

+0

Seufzer. 2. Wenn ich Intars anstelle von Floats verwende, sehe ich eine Lösung mit LambertW (aber es ist nicht die gleiche Lösung, die ich zuvor gesehen habe - wahrscheinlich ist es nur die Sonderfalllösung für diesen Root.) – wchlm

+0

@wchlm Tatsächlich hat "y" zwei Wurzeln. Leider kann ich keinen Weg finden, um beides zu lösen (ich bin kein Experte). – Stelios

1

Ich glaube, das Problem ist, dass lösen Konvertierungen floats zu rationals standardmäßig, die lea ds zu enormen Kräften, wenn das Protokoll invertiert wird. solve(rational=False) sollte dies ausschalten, aber für mich verursacht dies solve mit NotImplementedError zu scheitern. Ich öffnete an issue dafür.

+0

Beachten Sie auch, dass, wenn die Gleichung gegeben ist, um mit ganzzahligen Koeffizienten zu lösen, nur eine Wurzel zurückgegeben wird, anstatt zwei. [Wolfram alpha] (https://www.wolframalpha.com/input/?i=Solve%5B-10*x*log (x% 2F333) +% 2B + 2830 * x% 2F333 + - + 2830% 3D% 3D0 , x% 5D) bietet beide Wurzeln – Stelios

+1

Ja, das ist ein bekanntes Problem mit lösen. Lösungen mit LambertW sollten unendlich viele komplexe Lösungen haben, eine für jeden Zweig des LambertW. Sie können die anderen Zweige erhalten, indem Sie das zweite Argument wie 'LambertW (-283 * exp (-283/333)/333, -1)' setzen. – asmeurer

+0

Ich wusste das nicht, danke! – Stelios