Using sympy.integrate on a function that involves int() - sympy

I'm trying to integrate functions in Python. scipy.integrate.quad seems to work ok; but just be sure I'd like to check the results against other integration code. It was suggested that I try sympy.integrate. Now the code for the functions I want to integrate contains int(), which I use to convert floats into ints. This is ok for quad, but not for sympy.integrate.
Here's a simple example that reproduces the error:
import sympy
def f(x):
return sympy.exp(int(x))
sympy.symbols('x')
print(sympy.integrate(f(x),(x,0,2)))
This yields the error: TypeError: can't convert symbols to int
So is there a way to integrate functions that involve int() with scipy.integrate?
Thanks

To use integrate f must be a SymPy symbolic function which disallows your particular use of int. int(x) where x is a Symbol will always yield a type error however you could represent this symbolically using the floor function:
def f(x):
return sympy.exp(sympy.floor(x))
However, using floor may defeat some of the purpose of using SymPy in the first place because it will probably prevent discovery of an analytic solution as the following python session demonstrates:
>>> from sympy import *
>>> x = symbols("x")
>>> integrate(exp(floor(x)), (x, 0, 2)) # use of floor prevents evaluated result
Integral(exp(floor(x)), (x, 0, 2))
Though you can use the evalf method to compute a numeric result (which is ultimately performed by mpmath):
>>> integrate(exp(floor(x)), (x, 0, 2)).evalf()
3.7
(perhaps this result suggests sympy could better handle this integral? Wolfram Alpha computes this as 1 + e = 3.71828... so I suppose there is at least a floating point precision bug here too - see comment re ceiling)
In any case, I don't know if you consider that an appropriate result considering the version of f without floor:
>>> integrate(exp(x), (x, 0, 2))
-1 + exp(2)
>>> _.evalf()
6.38905609893065

Related

sympy function compose - bizzare results

I'm trying to compose two functions and I get a bizzare result
'''
#!/usr/bin/python
from sympy import *
init_printing(use_unicode=True)
x= symbols('x')
f = x/(x+1);
g = x/(x+2);
print(compose(f,g))
This shows : x/((x + 1)*(x + 2))
Should be x/(2x+2)
I don't get it. Does anyone has an idea?
Thanks
Despite being available in the top-level sympy namespace under the plain name compose, sympy.compose doesn't actually do general function composition.
sympy.compose is actually sympy.polys.polytools.compose. It's actually a function for polynomial composition. When you try to compose x/(x+1) and x/(x+2), it ends up interpreting these inputs as multivariate polynomials in 3 variables, x, 1/(x+1), and 1/(x+2), and the results are total nonsense.

SymPy integration of Matrix with multivariable entries

I am using Sympy to integrate a Sympy Matrix whose components depend on variables (x,y). Integrating with respect to a single variable x (or y) works, and returns the expected Matrix whose components are the integrals of the components of the original vector.
import sympy as sp
from sympy.abc import x,y
V = sp.Matrix(4,1,[1,x,y,x*y])
display(V)
# This works
I = sp.integrate(V,(x,0,1))
display(I)
Ultimately, I would like a double integral. I can accomplish this with the following
Ix = sp.integrate(V,(x,0,1))
I = sp.integrate(Ix,(y,0,1))
display(I)
My question is why the following does not seem to work.
I = sp.integrate(V,(x,0,1),(y,0,1))
The error I get is :
ValueError: Invalid limits given: (((x, 0, 1), (y, 0, 1)),)
Is this a bug? Or am I using the wrong syntax for the double integral with a Matrix type? This syntax works on components of the Matrix, i.e.
# This works
I3 = sp.integrate(V[3,0],(x,0,1),(y,0,1))
Thanks for confirming that this was a bug in SymPy. This is now fixed in SymPy. See https://github.com/sympy/sympy/pull/23277.
The other suggestion - using
I = V.integrate((x,0,1),(y,0,1))
may even be a nicer solution.

How to check whether a symbolic expression is rational?

I'm using Sympy and I haven't found a simple way of testing for x ∈ Q.
Context: I have a set of solutions of a set of very simple, 2DoF eigenvalue problems (e.g.,
) and I want to check if one of these solutions is rational (or, in other words, if the solution doesn't contains a square root).
A direct way of checking is what I would like the best, but I could accept also an answer that deals with finding (not finding) a square root in the solution.
The function rational = lambda x: all(i.exp.is_Integer for i in x.atoms(Pow)) is a direct translation of your criteria to return True if all powers (if present) are integers.
>>> from sympy import Pow, S, sqrt
>>> rational = lambda x: all(i.exp.is_Integer for i in x.atoms(Pow))
>>> rational(S.Half)
True
>>> rational(sqrt(3))
False
>>> rational(3/(1+sqrt(3)))
False

How do I display a full expression in sympy?

I am trying to use sympy in a Jupyter notebook to document and perform a series of mathematical cacluations in a reporducible way.
If I define the following:
from sympy import *
init_printing()
x, y, z = symbols("x y z")
x=y+z
x
then I can display the value of x (that is, y+z).
How do I display the full equation (x=y+z)?
Running Eq(x,y+z), even with evaluate=False) returns the expression with the value of x substituted (y+z=y+z).
I tried using Eq(S('x'),y+z), also Eq(S('x'),x) and sympy keep returning a boolean variable.
So I found a way to display it using the Ipython built-in functions:
from sympy import *
from IPython.display import display, Math
init_printing()
x, y, z = symbols("x y z")
x=y+z
display(Math('x = '+latex(x)))
I think that this is a more general solution to the problem.
Although you first declare x as a sympy.Symbol, once you perform the assignment x=y+z, x becomes an alias for y+z. Whenever you use x from that point after, x will be automatically translated by python as y+z.
If you insist on this workflow, you could use Eq(S('x'),y+z) to display the equation.
I know this isn't exactly the answer, but for those just looking for a neat print of the right-hand-side of a function f(x,y,z,...), you can just do f.subs(x,x) like so:
import sympy as sp
x,y,z=sp.symbols('x,y,z')
f=x+2*y+3*sp.exp(z)
f.subs(x,x)

How to obtain all solutions for cos(x)*cosh(x) == 1 in Sympy?

Following is the best I can get.
map(lambda n: nsolve(cos(x)*cosh(x)-1,x,3.14/2+3.14*n),range(9))
[mpf('0.0039941152964418809'),
mpf('4.730040744862704'),
mpf('7.8532046240958376'),
mpf('10.995607838001671'),
mpf('14.137165491257464'),
mpf('17.278759657399481'),
mpf('20.420352245626061'),
mpf('23.561944902040455'),
mpf('26.703537555508186')]
If you change range(9) to range(10), sympy will return an error.
ValueError: Could not find root within given tolerance. (1.59798e-17 > 2.1684e-1
9)
Try another starting point or tweak arguments.
I have asked this in the Mathematica site, Mathematica seems can provide the solutions quite accurate and fast. Check this out: how-to-obtain-all-solutions-for-cosx-coshx-1
This is a nice example of using an intelligent initial guess. If you just provide a tolerance you can find the additional solution:
>>> len([nsolve(cos(x)*cosh(x)-1,x,3.14/2+3.14*n,tol=1e-12) for n in range(10)])
10
Note, however, that the function is very steep in the region of the roots and it is unlikely that you will every end up with an x value that will make the function value small. If you know that your initial guesses leads to a root and not a discontinuity, you can safely use the verify=False to skip the verification of the solution (and verify it yourself, perhaps by taking the slope into account). I always feel safer using the bisect method, however, in these cases:
>>> f
cos(x)*cosh(x) - 1
>>> bounds = lambda i: (3.14*i, 3.14*(i+1))
>>> root = lambda i: nsolve(f, bounds(i), solver='bisect', verify=False)
>>> root(0)
mpf('0.0')
>>> root(99)
mpf('312.58846903218443')
>>> root(100)
mpf('315.73006168577422')
You can see that the function at this point is very large, but if we normalize by the derivative of the function the answer looks better:
>>> ans = _
>>> f.subs(x, ans).n(2)
2.3e+122
>>> (f/f.diff(x)).subs(x, ans).n(2)
-3.4e-15
Note: currently, it will not work to pass a normalized function to nsolve so it can be used in the solving process: nsolve only works with the numerator of the function you pass.