I am trying to solve the following equation for r:
from sympy import pi, S, solve, solveset, nsolve, symbols
(n_go, P_l, T, gamma_w, P_g, r, R_mol) = symbols(
'n_go, P_l, T, gamma_w, P_g, r, R_mol', real=True)
expr = -P_g + P_l - 3*R_mol*T*n_go/(4*r**3*pi) + 2*gamma_w/r
soln = solveset(expr, r, domain=S.Reals)
soln1 = solve(expr, r)
soln is of the form Complement(Intersection(FiniteSet(...))), which I really don't know what to do with.
soln1 is a list of 3 expressions, two of which are complex. In fact, if I substitute values for the symbols and compute the solutions for soln1, all are complex:
vdict = {n_go: 1e-09, P_l: 101325, T: 300, gamma_w: 0.07168596252716256, P_g: 3534.48011713030, R_mol: 8.31451457896800}
for result in soln1:
print(result.subs(vdict).n())
returns:
-9.17942953565355e-5 + 0.000158143657514283*I
-9.17942953565355e-5 - 0.000158143657514283*I
0.000182122477993494 + 1.23259516440783e-32*I
Interestingly, substituting values first and then using solveset() or solve() gives a real result:
solveset(expr.subs(vdict), r, domain=S.Reals).n()
{0.000182122477993494}
Conversely, nsolve fails with this equation, unless the starting point contains the first 7 significant digits of the solution(!):
nsolve(expr.subs(vdict), r,0.000182122 )
ValueError: Could not find root within given tolerance. (9562985778.9619347103 > 2.16840434497100886801e-19)
It should not be that hard, here is the plot:
My questions:
Why is nsolve so useless here?
How can I use the solution returned from solveset to compute any numerical solutions?
Why can I not obtain a real solution from solve if I solve first and then substitute values?
The answer from Maelstrom is good but I just want to add a few points.
The values you substitute are all floats and with those values the polynomial is ill-conditioned. That means that the form of the expression that you substitute into can affect the accuracy of the returned results. That is one reason why substituting values into the solution from solve does not necessarily give exactly the same value that you get from substituting before calling solve.
Also before you substitute the symbols it isn't possible for solve to know which of the three roots is real. That's why you get three solutions from solve(expr, r) and only one solution from solve(expr.subs(vdict), r). The third solution which is real after the substitution is the same (ignoring the tiny imaginary part) as returned by solve after the substitution:
In [7]: soln1[2].subs(vdict).n()
Out[7]: 0.000182122477993494 + 1.23259516440783e-32⋅ⅈ
In [8]: solve(expr.subs(vdict), r)
Out[8]: [0.000182122477993494]
Because the polynomial is ill-conditioned and has a large gradient at the root nsolve has a hard time finding this root. However nsolve can find the root if given a narrow enough interval:
In [9]: nsolve(expr.subs(vdict), r, [0.0001821, 0.0001823])
Out[9]: 0.000182122477993494
Since this is essentially a polynomial your best bet is actually to convert it to a polynomial and use nroots. The quickest way to do this is using as_numer_denom although in this case that introduces a spurious root at zero:
In [26]: Poly(expr.subs(vdict).as_numer_denom()[0], r).nroots()
Out[26]: [0, 0.000182122477993494, -9.17942953565356e-5 - 0.000158143657514284⋅ⅈ, -9.17942953565356e-5 + 0.000158143657514284⋅ⅈ]
Your expr is essentially a cubic equation.
Applying the subs before or after solving should not substantially change anything.
soln
soln is of the form Complement(Intersection(FiniteSet(<3 cubic solutions>), Reals), FiniteSet(0)) i.e. a cubic solution on a real domain excluding 0.
The following should give you a simple FiniteSet back but evalf does not seem to be implemented well for sets.
print(soln.subs(vdict).evalf())
Hopefully something will be done about it soon.
1
The reason why nsolve is not useful is because the graph is almost asymptotically vertical. According to your graph, the gradient is roughly 1.0e8. I don't think nsolve is useful for such steep graphs.
Plotting your substituted expression we get:
Zooming out we get:
This is a pretty wild function and I suspect nsolve uses an epsilon that is to large to be useful in this situation. To fix this, you could provide more reasonable numbers that are closer to 1 when substituting. (Consider providing different units of measurement. eg. instead of meters/year consider km/hour)
2
It is difficult to tell you how to deal with the output of solveset in general because every type of set needs to be dealt with in different ways. It's also not mathematically sensible since soln.args[0].args[0].args[0] should give the first cubic solution but it forgets that this must be real and nonzero.
You can use args or preorder_traversal or things to navigate the tree. Also reading documentation of various sets should help. solve and solveset need to be used "interactively" because there are lots of possible outputs with lots of ways to understand it.
3
I believe soln1 has 3 solutions instead of 4 as you state. Otherwise, your loop would print 4 lines instead of 3. All of them are technically of complex (as is the nature with floats in Python). However, the third solution you provide has a very small imaginary component. To remove these kinds of finicky things, there is an argument called chop which should help:
for result in soln1:
print(result.subs(vdict).n(chop=True))
One of the results is 0.000182122477993494 which looks like your root.
Here is an unswer to the underlying question: How to compute the roots of the above equation efficiently?
Based on the suggestion by #OscarBenjamin, we can do even better and faster by using Poly and roots instead of nroots. Below, sympy computes in no time the roots of the equation for 100 different values of P_g, while keeping everything else constant:
from sympy import pi, Poly, roots, solve, solveset, nsolve, nroots, symbols
(n_go, P_l, T, gamma_w, P_g, r, R_mol) = symbols(
'n_go, P_l, T, gamma_w, P_g, r, R_mol', real=True)
vdict = {pi:pi.n(), n_go:1e-09, P_l:101325, T:300, gamma_w:0.0717, R_mol: 8.31451457896800}
expr = -P_g + P_l - 3*R_mol*T*n_go/(4*r**3*pi) + 2*gamma_w/r
expr_poly = Poly(expr.as_numer_denom()[0], n_go, P_l, T, gamma_w, P_g, r, R_mol, domain='RR[pi]')
result = [roots(expr_poly.subs(vdict).subs(P_g, val)).keys() for val in range(4000,4100)]
All that remains is to check if the solutions are fulfilling our conditions (positive, real). Thank you, #OscarBenjamin!
PS: Should I expand the topic above to include nroots and roots?
lat2: =ASIN(SIN(lat1)*COS(d/ER) + COS(lat1)*SIN(d/ER)*COS(brng))
lon2: =lon1 + ATAN2(COS(d/ER)-SIN(lat1)*SIN(lat2), SIN(brng)*SIN(d/ER)*COS(lat1))
The above code is part of the code to start with Lat1 and Long1, travel azimuth and distance to arrive at Lat2 and Long2.
I am trying to convert the equations to Fortran, but I do not understand what to do with the comma. My current model is working for most test cases but is not correct when the distance crosses the 0 or 360 deg longitude line. The Long2 error is in stead of say + 10 deg E I get 350 deg E. I hope your model using the above equations handles the quadrant problem better.
ATAN2 is a Fortran function of two arguments. It is a common function that exists in several other programming languages as well, probably also in the language you are copying your lines from. You should have told us which language is that!
The function "computes the principal value of the argument function of the complex number X + i Y". The comma simply divides the first and the other argument.
Check, whether the language you are translating from uses the ATAN2 function in the same order for x and y as Fortran does. If not, switch the two arguments. Then simply call the Fortran function.
I do not understand this remark "hope your model using the above equations handles the quadrant problem better." Is it just some left-over from your private communication?
I need to solve differential equation y'=6e^(2x-y).
I am trying to do that in sympy with dsolve().
sol = dsolve(Derivative(f(x), x) - 6 *(e**(2*x-f(x))), f(x))
But always get error
expecting ints or fractions, got 7.38905609893065022723042746058 and 6
What is the problem?
Where did you get e from? It seems you used math.exp(1) or similar to get a floating point value that the symbolic package can not treat correctly
Using sympy.exp instead works perfectly, even defining e=sympy.exp(1) is correctly recognized. Both with the result
Eq(f(x), log(C1 + 3*exp(2*x)))
Hello, i want to formulate a regex expression outputted by matlab instruction solve to express an arithmetic operation in latex symboles as the example which follows:
(a+b^(c-d))/b -> \frac{(a+b^{(c-d)})}{b}
allowed input patterns:
/+-*^\w\s()
allowed output patterns:
+-*^\w\s(){}
about division, This is what i have tried so far
The caught expressions are stored in variables{division,numerator,denominator}
about exponentiation, I v tried This
Unfortunately,I found my self faced to couple of problems, one of them, is that my matlab version doesnt accept this kind of recursive regex. but I could implement it as iterative function:
a='^(dfdf ^(sdf) )';b=' ';while(~strcmp(a,b))b=a;a=regexprep(a, '\^\((?<betweenbrackets>.*)\)', '\^{$<betweenbrackets>}');end
Could you advice me anyway else to do it for both exponentiation and division ?
If you have the Symbolic Math Toolbox, you can just say
latex(sym('(a+b^(c-d))/b'))
ans =
\frac{a + b^{c - d}}{b}
It is easy to obtain such rewrite in other CAS like Mathematica.
TrigReduce[Sin[x]^2]
(*1/2 (1 - Cos[2 x])*)
However, in Sympy, trigsimp with all methods tested returns sin(x)**2
trigsimp(sin(x)*sin(x),method='fu')
While dealing with a similar issue, reducing the order of sin(x)**6, I notice that sympy can reduce the order of sin(x)**n with n=2,3,4,5,... by using, rewrite, expand, and then rewrite, followed by simplify, as shown here:
expr = sin(x)**6
expr.rewrite(sin, exp).expand().rewrite(exp, sin).simplify()
this returns:
-15*cos(2*x)/32 + 3*cos(4*x)/16 - cos(6*x)/32 + 5/16
That works for every power similarly to what Mathematica will do.
On the other hand if you want to reduce sin(x)**2*cos(x) a similar strategy works. In that case you have to rewrite the cos and sin to exp and as before expand rewrite and simplify again as:
(sin(x)**2*cos(x)).rewrite(sin, exp).rewrite(cos, exp).expand().rewrite(exp, sin).simplify()
that returns:
cos(x)/4 - cos(3*x)/4
The full "fu" method tries many different combinations of transformations to find "the best" result.
The individual transforms used in the Fu-routines can be used to do targeted transformations. You will have to read the documentation to learn what the different functions do, but just running through the functions of the FU dictionary identifies TR8 as your workhorse here:
>>> for f in FU.keys():
... print("{}: {}".format(f, FU[f](sin(var('x'))**2)))
...
8<---
TR8 -cos(2*x)/2 + 1/2
TR1 sin(x)**2
8<---
Here is a silly way to get this job done.
trigsimp((sin(x)**2).rewrite(tan))
returns:
-cos(2*x)/2 + 1/2
also works for
trigsimp((sin(x)**3).rewrite(tan))
returns
3*sin(x)/4 - sin(3*x)/4
but not works for
trigsimp((sin(x)**2*cos(x)).rewrite(tan))
retruns
4*(-tan(x/2)**2 + 1)*cos(x/2)**6*tan(x/2)**2