How to solve implementation problem in sympy - python

I need to solve an equation, but spider returns me this error:
import sympy as sym
import sympy as sympy
Re=100
Epsilon=0.00000075
D=0.01
f=symbols('f')
eq=(((1/(-2* sympy.log((Epsilon/D/ 3.7)+( 2.51 / (Re*(f**0.5))), 10)))**2 -f),0)
sym.solve((eq), (f))
print(f)
NotImplementedError: could not solve -4*f*log(202702702702703/10000000000000000000 + 251/(10000*sqrt(f)))**2 + log(10)**2

The solve function is for finding analytic solutions but that isn't possible for your equation (not all equations have analytic solutions):
In [11]: eq[0]
Out[11]:
2
log (10)
-f + ──────────────────────────────────────────
2⎛ -0.5 ⎞
4⋅log ⎝0.0251⋅f + 2.02702702702703e-5⎠
You can find a numeric solution with nsolve:
In [12]: sym.nsolve(eq[0], f, 0.1)
Out[12]: 0.169438052045717
https://docs.sympy.org/latest/modules/solvers/solvers.html#sympy.solvers.solvers.nsolve

This can be represented in terms of the LambertW function, but it needs some help. SymPy doesn't recognize the inverted sqrt(f) in the log. If you replace that with 1/y and solve for y and transform the solutions for y back to f you can get a symbolic solution.
It's easier in this case to let SymPy work with symbols instead of Floats and substitute the values later. Your equation looks like this:
>>> from sympy import a,b,c
>>> seq = a**2/log(b/sqrt(f) + c)**2 - f
>>> reps = {a:log(10)/2, c:Epsilon/D/3.7, b:2.51/Re}
Replace that sqrt(f) with 1/y
>>> ysol = solve(seq.xreplace(sqrt(f), 1/y), y)
Calculate the corresponding solutions for f:
>>> fsol = [((1/i)**2) for i in ysol]
Substitute in your values -- or any values that you are interested in:
>>> [i.xreplace(reps).n(3) for i in fsol]
[0.00771 - 0.107*I, 0.169]
Testing in the original shows that the second solution is valid
>>> [eq.subs(f,i).n() for i in _]
[0.148289010493944 + 0.206688429851791*I, 6.05179945288758e-6]
So your symbolic solution is
>>> fsol[1]
(-c/b + LambertW(a*exp(a*c/b)/b)/a)**(-2)
The nice thing about this form is that you can substitute any values of a,b,c and get the corresponding value of f. Whether this is faster than using nsolve, you will have to see.

Related

Sympy 'solve' returns 'list index out of range' error

I am using JuypterLab trying to solve a simple algebra problem:
3 * r**0.25 * s**0.75 = 14.086
I need to solve for s for values of r between 3 and 17.
import numpy as np
import pandas
import sympy as sym
from sympy import symbols, solve
s = Symbol('s')
expr = 3 * 18**0.25 * s**0.75 = 14.086
sol = solve(expr)
num = sol[10]
num
When I run the code I get the list out of range error
I also tried
s = Symbol('s')
expr = 3 * 18**0.25 * s**0.75
sol = solve(expr)
u = 14.086
num = sol[u]
num
When I run this code I get list indices must be integers or slices, not float
I would like to find the value of s for values of r
between 3 and 17.
Equations in sympy are written using Eq(). You can call solve with such an equation (or a list of multiple equations). You can tell solve that you look for an expression for s given r, by providing s as a second parameter.
The result of solve can take a few different forms, depending on the equations. Usually it is a list, and in this case there is only one expression that solves for s, so a list with one element. (E.g. a quadratic equation could have multiple solutions.)
The result of solve often isn't a single number, but a symbolic expression. In this case, it is an expression involving the variable r. To get a value for s for a specific r (e.g. r=10), expr.subs(r, 10) can be used. Sometimes the solution is numeric, but still in its symbolic form (e.g. sqrt(2)). Calling .evalf() will give a fully numeric solution.
from sympy import Symbol, solve, Eq, plot
r = Symbol('r')
s = Symbol('s')
equation = Eq(3 * r**0.25 * s**0.75, 14)
sol = solve(equation, s) # [7.79846345438935/r**(1/3)]
s_of_r = sol[0]
for ri in range(3, 18):
si = s_of_r.subs(r, ri).evalf()
print(f"for r={ri} the corresponding value for s={si:.6f}")
Sympy can also do some basic plotting:
plot(s_of_r, (r, 3, 17))
Regarding the first error "When I run the code I get the list out of range error":
this is because sol is a one element list, and you are trying to access the tenth element that doesn't exist.
Regarding the second error "When I run this code I get list indices must be integers or slices, not float"
this is because to access a position of a list you are trying with a decimal, which besides not working it doesn't make sense
As for the output of sol it is [0.0].
Isn't the code bellow what you are looking for? Cause It seems to me you wanto to find out the output of the expression when s is 14.086, right?
import numpy as np
import pandas
import sympy as sym
from sympy import Symbol, solve
s = Symbol('s')
expr = 3 * 18**0.25 * s**0.75
y = expr.replace(s, 14.086)
print(y)
Instead, if you want to find the value of sol given a expression value you can use this approach
# equation example 3 + s, given an output of 5
y = solveset(Eq(3 + s, 5), s)
print(y)

Sympy series expansion with numerical integration

I want to make a series expansion for a function F(e,Eo) up to a certain power of e and integrate over the Eo variable numerically.
What I thought was using SymPy to make the power series in e, and then use MPMath for the numerical integration over Eo.
Below is an example code. I receive the message that it can not create mpf from the expression. I guess the problem has to do with the fact that with the series from SymPy has an O(e**5) term at the end, and later that I want the numerical integration to show a function of e instead of a number.
import sympy as sp
import numpy as np
from mpmath import *
e = sp.symbols('e')
Eo = sp.symbols('Eo')
expr = sp.sin(e-2*Eo).series(e, 0, 5)
F = lambda Eo : expr
I = quad(F, [0, 2*np.pi])
print(I)
It’s evident that I need a different approach, but I would still need the numerical integration for my actual code because it has much more complicated expressions that could not be integrated analytically.
Edit: I should have chosen a complex function of real variables for the example code, I am trying this (the expansion and integration) for functions such as:
expr = (cos(Eo) - e - I*sqrt(1 - e ** 2)*sin(Eo)) ** 2 * (cos(2*(Eo - e*sin(Eo))) + I*sin(2*(Eo - e*sin(Eo))))/(1 - e*cos(Eo)) ** 4
Here is an approach similar to Wrzlprmft's answer but with a different way of handling coefficients, via SymPy's polynomial module:
from sympy import sin, pi, symbols, Integral, Poly
def integrate_coeff(coeff):
partial_integral = coeff.integrate((Eo, 0, 2*pi))
return partial_integral.n() if partial_integral.has(Integral) else partial_integral
e,Eo = symbols("e Eo")
expr = sin(e-sin(2*Eo))
degree = 5
coeffs = Poly(expr.series(e, 0, degree).removeO(), e).all_coeffs()
new_coeffs = map(integrate_coeff, coeffs)
print((Poly(new_coeffs, e).as_expr() + e**degree).series(e, 0, degree))
The main code is three lines: (1) extract coefficients of e up to given degree; (2) integrate each, numerically if we must; (3) print the result, presenting it as a series rather than a polynomial (hence the trick with adding e**degree, to make SymPy aware that the series continues). Output:
-6.81273574401304e-108 + 4.80787886126883*e + 3.40636787200652e-108*e**2 - 0.801313143544804*e**3 - 2.12897992000408e-109*e**4 + O(e**5)
I want the numerical integration to show a function of e instead of a number.
This is fundamentally impossible.
Either your integration is analytical or numerical, and if it is numerical it will only handle and yield numbers for you (the words numerical and number are similar for a reason).
If you want to split the integration into numerical and analytical components, you have to do so yourself – or hope that SymPy automatically splits the integration as needed, which it unfortunately is not yet capable of.
This is how I would do it (details are commented in the code):
from sympy import sin, pi, symbols, Integral
from itertools import islice
e,Eo = symbols("e Eo")
expr = sin(e-sin(2*Eo))
# Create a generator yielding the first five summands of the series.
# This avoids the O(e**5) term.
series = islice(expr.series(e,0,None),5)
integral = 0
for power,summand in enumerate(series):
# Remove the e from the expression
Eo_part = summand/e**power
# … and ensure that it worked:
assert not Eo_part.has(e)
# Integrate the Eo part:
partial_integral = Eo_part.integrate((Eo,0,2*pi))
# If the integral cannot be evaluated analytically, …
if partial_integral.has(Integral):
# … replace it by the numerical estimate:
partial_integral = partial_integral.n()
# Re-attach the e component and add it to the sum:
integral += partial_integral*e**power
Note that I did not use NumPy or MPMath at all (though SymPy uses the latter under the hood for numerical estimates). Unless you really really know what you’re doing, mixing those two with SymPy is a bad idea as they are not even aware of SymPy expressions.

Derivative on index symbols in sympy

I am trying to do symbolical calculations (derivatives mostly) on time-indexed variables using sympy.
Using indexed symbols like r[t] below produces an error:
from sympy import *
t = Idx('t',10)
r = IndexedBase('r')
diff(r[t],r[t])
diff(r,r)
ValueError:
Can't differentiate wrt the variable: r[t], 1
Could the reason be that something went wrong here:
In [15]: r[t].indices
Out[15]: (t,)
The comma after the index t looks suspicious to me, but I have no idea what went wrong.
Does anyone know how to do this in sympy?
You can differentiate wrt symbols, functions and derivatives. Will this work:
>>> t = Idx('t',10)
>>> r=Function('r')
>>> r(t).diff(r(t))
1
>>> var('t')
t
>>> r(t).diff(t)
Derivative(r(t), t)

Equation roots: parameter doesn't get simplified

I am using Python with Sympy.
I need to solve the following equation, finding the 4 roots (omega is my unknown):
deter= 0.6*omega**4*cos(omega*t)**2 - 229.0*omega**2*cos(omega*t)**2 + 5880.0*cos(omega*t)**2
I tried to use solve:
eqcarr=solve(deter,omega,exclude=[t])
I get this output:
[-18.8143990830350, -5.26165884593044, 5.26165884593044, 18.8143990830350, 1.5707963267949/t, 4.71238898038469/t]
I only need the first 4 values, and not the values with the t coefficient. I expect the cos(omega*t)**2 to be simplified in solve, but this doesn't happen.
According to documentation solve will not solve for any of the free symbols passed in the exclude.
'exclude=[] (default)'
don't try to solve for any of the free symbols in exclude;
if expressions are given, the free symbols in them will
be extracted automatically.
It is not meant to filter solution.
You can solve your problem by doing this:
In [10]: from sympy import *
In [11]: from sympy.abc import omega, t
In [12]: deter= 0.6*omega**4*cos(omega*t)**2 - 229.0*omega**2*cos(omega*t)**2 + 5880.0*cos(omega*t)**2
In [13]: eqcarr=solve(deter,omega,exclude=[t])
In [14]: filtered = [i for i in eqcarr if not i.has(t)]
In [15]: filtered
Out[15]: [-18.8143990830350, -5.26165884593044, 5.26165884593044, 18.8143990830350]

input a symbolic function in a python code

I was just wondering if there is a method to input a symbolic function in a python code?
like in my code I have:
from sympy import *
import numpy as np
import math
myfunction = input("enter your function \n")
l = Symbol('l')
print myfunction(l**2).diff(l)
If I put cos, sin or exp, as an input then I have an output of: -2*l*sin(l**2)
What If I want to make the input function more general, say a polynomial or a complex function, or maybe a function of combined cos, sin and exp ???
As a syntax, sin + cos simply isn't going to work very well. The simplest way to get the general case to work is to give sympy an expression to evaluate. We can let sympify do the hard work of turning a string into a sympy object:
>>> s = raw_input("enter a formula: ")
enter a formula: sin(x) + x**3
>>> s
'sin(x) + x**3'
>>> f = sympy.sympify(s)
>>> f
x**3 + sin(x)
After which we can substitute and evaluate:
>>> f.subs({'x': 2})
sin(2) + 8
>>> f.subs({'x': 2}).evalf()
8.90929742682568
See also my answer here for some other tricks you can pull with a bit of work:
>>> f = definition_to_function("f(x) = sin(x) + x**3")
>>> f(3)
27.14112000805987
If you need good support for symbolic funcions, you should consider using sage.
It is a preprocessor for python, with lots of math support including symbolic functions. Sage code can be intermixed with normal python-code.
The package is quite big, but I have good experiences with it. It is free and open-source.

Categories