Speed up SymPy equation solver - python

I am trying to solve a set of equations using the following python code (using SymPy of course):
def Solve(kp1, kp2):
a, b, d, e, f = S('a b d e f'.split())
equations = [
Eq(a+b, 2.6),
Eq(2*a + b + d + 2*f, 7),
Eq(d + e, 2),
Eq(a*e,kp2*b*d),
Eq( ((b * (f**0.5))/a)*((a+b+d+e+f+13.16)**-0.5), kp1)
]
return solve(equations)
The code solves the equations successfully but after approximately 35 seconds. The Solve() function is used inside an iterative block(about 2000 iterations) in another file so speed really matters to me.
Is there any way to speed up the solver? If not can you recommend another way to solve system of equations using python?

You only need to solve the equation one time. After that you will have equations of the form:
a = f_1(kp1, kp2)
b = f_2(kp1, kp2)
...
so you can simply compute a, ..., e in dependency of kp1 and kp2. For example solving the first, third and fourth equations gives:
b: -a + 2.6
e: 2.0*kp2*(5.0*a - 13.0)/(5.0*a*kp2 - 5.0*a - 13.0*kp2),
d: 10.0*a/(-5.0*a*kp2 + 5.0*a + 13.0*kp2)
Solving all five equations on my pc is too slow, but if it gives you an expression you just have to plug in (substitute) the values for kp1 and kp2, you don't have to solve the equations again. For substitution take a look at the sympy documentation.
So your loop should look like:
solutions = sympy.solve(eqs, exclude=[kp1, kp2])
for data_kp1, data_kp2 in data:
for key, eq in solutions:
solution = eq.subs([(kp1, data_kp1), (kp2, data_kp2)])
final_solutions.append("{key}={solution}".format(key=key, solution=solution))

Solve the 1st 4 linear equations for a,b,d,e. This generates two solutions. Substitute each of these into the 5th equation (in this form: Eq(b**2*f, d**2*kp1**2*(a + b + 2*d + f + 13.16))) to give two equations (e51 and e52). These two equations are nonlinear in f and, if you use unrad on them you will end up with 2 sixth-order polynomials in f -- which is likely why you get no solution since only quartics are exactly solvable in general. Call those two equations e51u, and e52u.
If you are interested in the real roots, you can use real_roots to give the roots to these polynomials after substituting in the desired values for kp1 and kp2 to leave only f as the unknown. For example,
>>> ans = solve(equations[:-1],a,b,d,e)
>>> l=equations[-1] # modified as suggested
>>> l=l.lhs-l.rhs
>>> l
b**2*f - d**2*kp1**2*(a + b + 2*d + f + 13.16)
>>> e51=l.subs(ans[0]); e51u=unrad(e51)[0]
>>> e52=l.subs(ans[1]); e52u=unrad(e52)[0]
>>> import random
>>> for r1,r2 in [[random.random() for i in range(2)] for j in range(3)]:
... print [i.n(2) for i in real_roots(e51u.subs(dict(kp1=r1,kp2=r2)))]
... print [i.n(2) for i in real_roots(e52u.subs(dict(kp1=r1,kp2=r2)))]
... print '^_r1,r2=',r1,r2
...
[1.7, 2.9, 3.0, 8.2]
[1.7, 2.9, 3.0, 8.2]
^_r1,r2= 0.937748743197 0.134640776315
[1.3, 2.3, 4.7, 7.4]
[1.3, 2.3, 4.7, 7.4]
^_r1,r2= 0.490002815309 0.324553144174
[1.1, 2.1]
[1.1, 2.1]
^_r1,r2= 0.308803300429 0.595356213169
It appears that e51u and e52u both give the same solutions, so perhaps you only need to use one of them. And you should check the answers in the original equations to see which one(s) are true solutions:
>>> r1,r2
(0.30880330042869408, 0.59535621316941589)
>>> [e51.subs(dict(kp1=r1,kp2=r2,f=i)).n(2) for i in real_roots(e51u.subs(dict(kp1=r1,kp2=r2)))]
[1.0e-12, 13.]
So here you see that only the first solution (seen to be 1.1 from above) is actually a solution; 2.1 was a spurious solution.

Your system of equations can be transformed to a polynomial system in terms of kp1 and kp2 as symbolic parameters. In this case it is advantageous to convert it to a polynomial system so that it can be partially solved in preparation for numerical solving for particular values of the parameters.
The technique her involves computing Groebner bases for which you will want to not have any floats in your equations so let's first make sure that we use exact rational numbers (e.g. use sqrt rather than **0.5 and Rational('2.6') rather than 2.6):
In [20]: kp1, kp2 = symbols('kp1, kp2')
In [21]: a, b, d, e, f = symbols('a, b, d, e, f')
In [22]: equations = [
...: Eq(a+b, Rational('2.6')),
...: Eq(2*a + b + d + 2*f, 7),
...: Eq(d + e, 2),
...: Eq(a*e,kp2*b*d),
...: Eq( ((b * sqrt(f))/a)/sqrt((a+b+d+e+f+Rational('13.16'))), kp1)
...: ]
In [23]: for eq in equations:
...: pprint(eq)
...:
a + b = 13/5
2⋅a + b + d + 2⋅f = 7
d + e = 2
a⋅e = b⋅d⋅kp₂
b⋅√f
─────────────────────────────── = kp₁
_________________________
╱ 329
a⋅ ╱ a + b + d + e + f + ───
╲╱ 25
The final equation can be trivially transformed to a polynomial: multiply out the denominator and square both sides e.g.:
In [24]: den = denom(equations[-1].lhs)
In [25]: neweq = Eq((equations[-1].lhs*den)**2, (equations[-1].rhs*den)**2)
In [26]: neweq
Out[26]:
2 2 2 ⎛ 329⎞
b ⋅f = a ⋅kp₁ ⋅⎜a + b + d + e + f + ───⎟
⎝ 25⎠
In [27]: equations[-1] = neweq
In [28]: for eq in equations:
...: pprint(eq)
...:
a + b = 13/5
2⋅a + b + d + 2⋅f = 7
d + e = 2
a⋅e = b⋅d⋅kp₂
2 2 2 ⎛ 329⎞
b ⋅f = a ⋅kp₁ ⋅⎜a + b + d + e + f + ───⎟
⎝ 25⎠
Now that we have a polynomial system we are ready to compute its Groebner basis. We will select a, b, d, e, f as the generators for the Groebner basis and leave kp1 and kp2 as part of the coefficient ring:
In [29]: basis = list(groebner(equations, [a, b, d, e, f]))
This now is a reduced system of equations for abdef with complicated looking coefficients that depend on kp1 and kp2. I'll show one of the equations as an example:
In [30]: basis[-1]
Out[30]:
⎛ 4 2 2 2 2 ⎞ ⎛
4 ⎛ 4 2 2 2 2 ⎞ 3 ⎜778⋅kp₁ ⋅kp₂ 399⋅kp₁ ⋅kp₂ 384⋅kp₁ 1⎟ 2 ⎜102481⋅
f ⋅⎝kp₁ ⋅kp₂ - kp₁ ⋅kp₂ - kp₁ + 1⎠ + f ⋅⎜───────────── - ───────────── - ──────── + ─⎟ + f ⋅⎜───────
⎝ 25 25 25 5⎠ ⎝ 6
4 2 2 2 2 2 ⎞ ⎛ 4 2 2 2
kp₁ ⋅kp₂ 15579⋅kp₁ ⋅kp₂ 13⋅kp₁ ⋅kp₂ 5148⋅kp₁ 1 ⎟ ⎜ 3799752⋅kp₁ ⋅kp₂ 8991⋅kp₁ ⋅kp₂
───────── + ─────────────── - ─────────── + ───────── + ───⎟ + f⋅⎜- ───────────────── - ──────────────
25 500 5 125 100⎠ ⎝ 3125 625
2 2⎞ 4 2
5772⋅kp₁ ⋅kp₂ 15984⋅kp₁ ⎟ 23853456⋅kp₁ ⋅kp₂
- ───────────── - ──────────⎟ + ──────────────────
125 625 ⎠ 15625
Although these equations might look complicated they have a particular structure which means that once you have substituted values for kp1 and kp2 the final equation depends only on f and all other equations give symbols linearly in terms of f. This means that you can substitute your values and then use either sympy's real_roots or numpys np.roots to get either exact or approximate roots for f, substitute those into your other equations and solve a simple system of linear equations for the remaining unknowns. These are the only steps that would need to be done in the final loop and we can use lambdify to make them happen quickly. The final result then is
from sympy import *
# First solve the system as much as possible in terms of symbolic kp1, kp2
kp1, kp2 = symbols('kp1, kp2')
a, b, d, e, f = symbols('a, b, d, e, f')
# Don't use any floats (yet)
equations = [
Eq(a+b, Rational('2.6')),
Eq(2*a + b + d + 2*f, 7),
Eq(d + e, 2),
Eq(a*e,kp2*b*d),
Eq( ((b * sqrt(f))/a)/sqrt((a+b+d+e+f+Rational('13.16'))), kp1)
]
# Convert to full polynomial system:
den = denom(equations[-1].lhs)
neweq = Eq((equations[-1].lhs*den)**2, (equations[-1].rhs*den)**2)
equations2 = equations[:-1] + [neweq]
# Compute the Groebner basis and split the linear equations for a, b, d, e
# from the polynomial equation for f
basis = list(groebner(equations2, [a, b, d, e, f]))
lineqs, eq_f = basis[:-1], basis[-1]
# Solve for a, b, d, e in terms of f, kp1 and kp2
[sol_abde] = linsolve(lineqs, [a, b, d, e])
# Use lambdify to be able to efficiently evaluate the solutions for a, b, d, e
sol_abde_lam = lambdify((f, kp1, kp2), sol_abde)
# Use lambdify to efficiently substitute kp1 and kp2 into the coefficients for eq_f
eq_f_lam = lambdify((kp1, kp2), Poly(eq_f, f).all_coeffs())
def solve_k(kp1val, kp2val):
eq_f_coeffs = eq_f_lam(kp1val, kp2val)
# Note that sympy's real_roots function is more accurate and does not need
# a threshold. It is however slower than np.roots:
#
# p_f = Poly(eq_f_coeffs, f)
# f_vals = real_roots(p_f) # exact (RootOf)
# f_vals = [r.n() for r in real_roots(p_f)] # approximate
#
f_vals = np.roots(eq_f_coeffs)
f_vals = f_vals.real[abs(f_vals.imag) < 1e-10] # arbitrary threshold
sols = []
for f_i in f_vals:
abde_vals = sol_abde_lam(f_i, kp1val, kp2val)
sol = {f: f_i}
sol.update(zip([a,b,d,e], abde_vals))
sols.append(sol)
return sols
Now you can generate the solutions for particular values of kp1 and kp2 in around 1 millisecond:
In [40]: %time solve_k(2.1, 3.8)
CPU times: user 1.59 ms, sys: 0 ns, total: 1.59 ms
Wall time: 1.51 ms
Out[40]:
[{a: 49.77432869943, b: -47.174328699430006, d: -0.7687860254920669, e: 2.768786025492067, f: -22.30277
1336968966}, {a: 3.4616794447024692, b: -0.8616794447024684, d: 36.964491584342106, e: -34.964491584342
11, f: -18.01308551452229}, {a: -0.5231222050642267, b: 3.1231222050642273, d: -0.0922228459726158, e:
2.092222845972616, f: 2.507672525518422}, {a: 0.34146680496125464, b: 2.258533195038746, d: 0.076528664
56901455, e: 1.9234713354309858, f: 1.9910022652348665}]
Caveats: the method above will work in most cases for a polynomial system like this although there are cases where the Groebner basis won't fully separate without the additional use of a splitting variable. Basically just introduce a new variable say t and a random equation like t = a + 2*b + 3*d + 4*e + 5*f. Then make t the last symbol for the Groebner basis and compute t instead of f with np.roots. Also in some cases computing the Groebner basis can be extremely slow but remember that it only ever needs to be computed once (you could save the result in a file if needed).
Another caveat is that squaring to transform into a polynomial system will introduce spurious solutions that don't satisfy the original radical equations. You can check by substituting into the original system. In this case only the last equation matters:
In [41]: sols = solve_k(2.1, 3.8)
In [42]: equations[-1].subs(sols[0])
Out[42]: -2.10000000000001 = kp₁
In [43]: equations[-1].subs(sols[1])
Out[43]: -2.10000000000006 = kp₁
In [44]: equations[-1].subs(sols[2])
Out[44]: -2.09999999999995 = kp₁
In [45]: equations[-1].subs(sols[3])
Out[45]: 2.09999999999993 = kp₁
So we see that of the 4 solutions returned only the last is correct because it (approximately) satisfies kp1 = 2.1 which was the value passed in. This means a bit of post-processing is needed to get the solutions that you actually want.

Related

sympy eliminate or chancel unwanted results

I'm trying to solve the cosine formula using sympy. (A is angle and a, b, c is sides)
sol = solve(a**2-b**2-c**2+2*b*c*cos(pi/180*A), [A, a, b, c])
print(sol)
And I end up getting results like this:
[(90.0000000000000, 5.00000000000000, 4.00000000000000, 3.00000000000000), (270.000000000000, 5.00000000000000, 4.00000000000000, 3.00000000000000)]
But it's impossible for a triangle to have a 270º interior angle.
I tried to do A, B, C <= 180 and solve(a**2-b**2-c**2+2*b*c*cos(pi/180*A), [A<=180, a, b, c]).I also try to use exclude=[A<=180] in the solve(), but it don't work too.
Let's understand what's happening:
from sympy import *
a, b, c, A = symbols("a, b, c, A")
eq = a**2-b**2-c**2+2*b*c*cos(pi/180*A)
eq is a trigonometric equation involving the cosine function, which is periodic with a period of 2*pi. Suppose you want to solve cos(x) = y where y is contained in (-1, 1]: you will get two solutions! For example, suppose you want to solve cos(x) = 0.5: one solution is x=60deg and the other is x=300deg.
Now let's focus on your equation. You have one equation with 4 symbols. Let's assume that a,b,c are known quantities and asks Sympy to solve for A (the unknown, which I assume it is the angle in degrees).
We can filter out the solutions in two approaches.
First approach
Substitute the known values a, b, c into eq and then solve for A with a specified constraint:
# substitution dictionary
d = {a: 1, b: 1, c: 1}
# solve the equation asking to find the solution for which A <= 180
sol = solve([eq.subs(d), A <= 180], A)
print(sol)
# out: (-oo < A) & (A <= 180) & (Eq(A, 60) | Eq(A, 300))
Here, SymPy produced a boolean solution (meaning it is a combination of one or more solutions with the And and Or objects). Let's try to simplify it a bit:
sol2 = sol.as_set()
print(sol2)
# out: {60}
Now we can extract it with:
A_num = list(sol2)[0]
print(A_num)
# 60
Second approach
Obtain a fully symbolic solution, then substitute the known values and filter out according to your rules:
sol = solve(eq, A)
for i, s in enumerate(sol):
print("sol", i+1, ":", s)
# output:
# sol 1 : 180*(-acos((-a**2 + b**2 + c**2)/(2*b*c)) + 2*pi)/pi
# sol 2 : 180*acos((-a**2 + b**2 + c**2)/(2*b*c))/pi
# substitution dictionary
d = {a: 1, b: 1, c: 1}
sol = [s.subs(d) for s in sol]
# apply custom filter:
sol = [s for s in sol if s <= 180]
sol = sol[0]
print(sol)
# out: 60

Updating variables with sympy

I have a problem with sympy where it won't update my values. So I'm trying to do an iterative method for solving $\sigma_x$ and when I try to put numerical values into my expression it won't update.
I have imported sympy as sy
So I first have this code:
q,b,E,t,nu,L,z,x,y = sy.symbols("q,b,E,t,nu,L,z,x,y")
D = (E*t**3)/(12*(1-nu**2))
q_0 = 4*q/(sy.pi*b) * sy.sin(sy.pi/2)*(1-sy.cos(sy.pi))
D2 = (sy.pi**2 / L**2) + (sy.pi**2 / b**2)
w = q_0/(D* D2**2) * sy.sin(sy.pi*x/L) * sy.sin(sy.pi * y / b)
M = 4
N = 4
w_iterert = 0
for m in range(1,M+1):
for n in range(N+1):
q_iterert = 4*q/(sy.pi*b*m)*sy.sin(sy.pi*n/2)*(1-sy.cos(sy.pi*m))
w_mn = q_iterert/(D*((sy.pi**2*m**2 / L**2) + (sy.pi**2 * n**2 / b**2))**2)
w_iterert += w_mn*sy.sin(m*pi*x/L)*sy.sin(n*pi*y/b)
Then I plot the analytical expression:
w_iterert
And now I use formulas to find my sigma_x:
w_xx_iter = sy.diff(w_iterert,x,2)
w_yy_iter = sy.diff(w_iterert,y,2)
sigma_x_iter = - z*E/(1-nu**2)*(w_xx_iter+nu*w_yy_iter)
Here is where I get it wrong. now I do this:
E = 210000
pi = sy.pi
q = 20
nu = 0.3
L = 4000
b = 1000
t = 10
x = 2
z = t/2
y = b/2
sigma_x_iter
And I would expect this to update the values and give me the numerical value. Instead I just get the same analytical expression. How can I update my values?
I tried everything, I just wrote and tried to copy the text into another notebook which obviously worked. But then I can't change the M N values and get a different result unless I do it automatically.
I had to edit your code several times to get something that I could copy-n-paste and run.
What I meant by subs is:
In [38]: sigma_x_iter.subs({E:210000, q:20,nu:0.3,L:4000,b:1000,t:10,x:2,z:10/2,
...: y:1000/2})
Out[38]:
⎛ ⎛ π ⎞ ⎛3⋅π ⎞⎞
⎜654766080000000000⋅sin⎜────⎟ 9844326400000000⋅sin⎜────⎟⎟
⎜ ⎝2000⎠ ⎝2000⎠⎟
2.0e-10⋅⎜──────────────────────────── + ──────────────────────────⎟ 9.6e-10⋅
⎝ 243049 2601 ⎠
─────────────────────────────────────────────────────────────────── + ────────
3
π
⎛ ⎛3⋅π ⎞ ⎛ π ⎞⎞
⎜1321369600000000⋅sin⎜────⎟ 725790720000000000⋅sin⎜────⎟⎟
⎜ ⎝2000⎠ ⎝2000⎠⎟
⎜────────────────────────── + ────────────────────────────⎟
⎝ 2601 243049 ⎠
───────────────────────────────────────────────────────────
3
π
In [39]: _38.n()
Out[39]: 0.361692509661739
In sympy you need to keep a clear distinction between a symbol, and the variable that references it. sympy works within the Python environment, without changing syntax. You may need to study the documented gotachas some more.
E as defined is a symbol:
In [42]: type(E)
Out[42]: sympy.core.symbol.Symbol
This assignment assigns an int to E, breaking any connection it had with the symbol. The symbol still exists in the various expressions, but you can no longer reference it with the variable E. This assignment does not touch any of the expressions.
In [43]: E = 210000
In [44]: type(E)
Out[44]: int

Is there a way to add my own identities to simplify a system of polynomial equations in sympy?

I have the following identity:
1 = a + b + c
Supose that I have the expression:
expr = x*(a + b + c)
It can be simplified as x.
Is there a way to declare it to SymPy so it can simplify them? Actually I do the job mannualy:
>>> import sympy
>>> sympy.vars("x a b c")
>>> expr = x*(a + b + c)
>>> expr.subs(a + b + c, 1)
x
The ratsimpmodprime function will work in your case. It simplifies a rational function with respect to some polynomials that are assumed to be equal to zero:
In [13]: a, b, c, x = symbols('a, b, c, x')
In [14]: polys = [a + b + c - 1]
In [15]: basis = groebner(polys).polys
In [16]: ratsimpmodprime(x*(a + b + c), basis)
Out[16]: x
https://docs.sympy.org/latest/modules/simplify/simplify.html#ratsimpmodprime

Solving a multiple variable equation with python

I'm trying to create a program to solve this equation:
2.5x + 3.5y + 4.5z + 5.5t + 6.5w + 10.5f = d
I want to be able to set a value for d and get posite and whole numbers as a result for each variable.
import sympy as sp
import numpy as np
x, y, z, t, w, f = sp.var('x y z t w f', Naturals0=True, positive=True)
var = [x, y, z, t, w, f]
d = 14
Eqn = sp.Eq(2.5*x + 3.5*y + 4.5*z + 5.5*t + 6.5*w + 10.5*f, d)
for i in var:
print(sp.solveset(Eqn, i, domain=sp.S.Naturals0))
I'm using the code above but I'm having 2 problems, first it give me back only the relative answers for each variable and I've not found a way to "control" the answer for being only positive and whole.
I know that maybe I get a lot of results depending on the number I set for d, but I need results in therms of numbers, nos equations.
Last but not least, I've already tried doing with numpy and matrix solving, but not suceeded.
Thanks in advance
When you want integer solutions for multiple variables in an equation you might be wanting to use diophantine; solveset is more for solving for a single variable in terms of the others.
For diophantine give it the equation as an expression with integer coefficients:
>>> from sympy import Add, nsimplify, Eq, symbols, ordered
>>> s = d, f, t, w, x, y, z=symbols('d, f, t, w, x, y, z')
>>> e = Eq(2.5*x + 3.5*y + 4.5*z + 5.5*t + 6.5*w + 10.5*f, d)
>>> nsimplify(e.rewrite(Add), rational=True)
-d + 21*f/2 + 11*t/2 + 13*w/2 + 5*x/2 + 7*y/2 + 9*z/2
>>> eq = _
Now get an integer solution:
>>> from sympy import diophantine
>>> isol = diophantine(eq, syms=s); isol
{(t_0, t_1, t_1 + t_2, t_1 + t_2 + t_3, t_1 + t_2 + t_3 + t_4,
8*t_0 - 191*t_1 - 107*t_2 - 63*t_3 - 11*t_4 + 9*t_5,
-6*t_0 + 143*t_1 + 80*t_2 + 47*t_3 + 8*t_4 - 7*t_5)}
This is a set of tuples (in this case 1) of either integers or variables representing integers that are a solution to the equation. In this case, 6 parameters are free to be chosen and then a particular solution can be found. We'll create a function f that can be used to see particular solutions easily:
>>> from sympy import Tuple, Dict, Lambda
>>> tsol = Tuple(*isol.pop())
>>> dsol = Dict(*zip(v, tsol))
>>> p = tuple(ordered(tsol.free_symbols))
>>> f = Lambda(p, dsol)
Now we can see a particular solution and see that it satisfies the original expression:
>>> f(1,2,3,4,5,6)
{d: 1, f: 2, t: 5, w: 9, x: 14, y: -948, z: 706}
>>> eq.subs(_)
0
So there are an infinite number of solutions governed by 6 arbitrary integers from which the other two are determined.

How to fix solver values when returned only the formula

I am using solver to find the zeros in the following equation. Solver returns only the formula of each one. How can i make it return for me a list of all the values calculated.
from sympy import *
A, B, C, D, r_w, r_j, r, R = symbols('A B C D rw1 rj1 r R')
equation=-pi*r**2*(A + B/(r/r_j + 1)) + pi*r**2*(C + D/(r/r_w + 1))
substitued=equation.subs([(A,232),(B,9768),(C,590),(D,7410),(rj1,1),
(rw1,2),(r,1)])
x=diff(substitued.subs(r,R),R)
solve(x,R)
`
why do i get returned the equations and not the values as a list. Please HELP!
0,−2337716−2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2−−2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2,−2337716−2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2+−2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2,−2337716−−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246+2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2+2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2,−2337716+−2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3−23062973288369571462634880387069105√137648136+3800344321791238833224√3+2200747192246+2223856515229413562200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2+2200747384492+23062973288369571462634880387069105√137648136+3800344321791238833224√3+2571462634880387069105√137648136+3800344321791238833224⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√3⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯2
It looks like things are a little scrambled here. But the short answer is that SymPy is a symbolic calculator and, except for combining numbers together automatically (like 1 + 2 -> 3), it doesn't compute sqrt(2) + 1 as 2.414... unless you tell it to. And one way to "tell it to do it" is nfloat:
>>> sol = solve(substitued.diff(r), r)
>>> nfloat(sol,3)
[0.0, -6.07 - 2.81*I, -6.07 + 2.81*I, -1.29, 0.386]
There is also nsolve if you want numerical approximations of your solutions, but for an equation like this where there are multiple roots, you will have to supply an initial guess to help the solver find the root in which you are interested. Here is a simpler equation to demonstrate:
>>> sol = solve(x**2+x-sqrt(3))
>>> sol
[-1/2 + sqrt(1 + 4*sqrt(3))/2, -sqrt(1 + 4*sqrt(3))/2 - 1/2]
>>> nfloat(sol, 3)
[0.908, -1.91]
>>> nsolve(x**2+x-sqrt(3), x, 1)
0.907853262086954
>>> nsolve(x**2+x-sqrt(3), x, -1)
-1.90785326208695

Categories

Resources