I need to manipulate a function symbolically, and then numerically integrate the function. How do I correctly use my expression f in the integrand function. How do I use lambdify correctly if that is even the sensible way to do it? Many thanks.
from sympy import *
import scipy.integrate as integrate
r = symbols('r') #define symbol
f = diff(r*r) #carry out symbolic manipulation
def integrand(x): #define function to integrate
return lambdify(x, f) #swap variable x into f
result = integrate.quad(integrand, 0, 5) #integrate numerically
print(result)
lambdify returns a function object, there is no need to use a wrapper function. Also note that the first argument of lambdify should be a tuple of variables representing sympy symbols (in this case, r) that are included in the sympy expression (in this case, f_sym) provided as its second argument.
import sympy as sp
from scipy.integrate import quad
r = sp.symbols('r')
f_sym = sp.diff(r*r, r)
f_lam = sp.lambdify(r, f_sym)
result = quad(f_lam, 0, 5)
print(result)
(25.0, 2.7755575615628914e-13)
Related
I am using SymPy for analytical handling of variables (e.g. matrix multiplication etc.).
After doing so, I end up with a new SymPy expression which I would like to use for plotting with Matplotlib. So far, my only way to do so, was to print the SymPy expression and paste it into a newly defined function manually.
How can I directly convert the SymPy expression into a function for numerical interpretation without relying on copying and pasting?
A minimal working example is the following:
import sympy as sp
import matplotlib.pyplot as plt
import numpy as np
sp.var('x A B') # x will later be the variable, A and B will be constants
temp = A*x+B # intermediate calculations
f = temp*x # function in reality, it will be more complicated.
print(f) # I printed f in order to find the expression and copy-pasting it into the function below.
def func(x,A,B):
return x*(A*x + B) # This statement was copy-pasted. This line should be changed, s.t. copy-pasting is not necessary!
#Now we can handle the function numerically for plotting (using matplotlib and numpy)
xspace = np.linspace(0,5)
plt.plot(xspace,func(x=xspace,A=1,B=2))
Sympy’s lambdify exists exactly for this. Just replace your definition of func with:
func = sp.lambdify((x,A,B),f)
I've been working with symbolic expressions in Python, and have arrived at one which I am wanting to integrate over a definite interval. The expression contains pi.
The trouble is that I have not been able to figure out how to convert this expression to a function which can be input as an argument to scipy.integrate.quad. The relevant parts of my code are as follows:
from sympy import *
import numpy as np
import scipy.integrate as integrate
from sympy.utilities.lambdify import lambdify
# this defines the symbols that
# we will be using in our computations:
x, y, g, y1, a0, a1, a2 = symbols('x y g y1 a0 a1 a2')
# this defines what a0 and a1,
# and what y and y' are:
a0 = 2
a1 = -((2/pi)+(pi*a2))
y = a0+a1*x+a2*x**2
y1 = y.diff(x)
# this defines the integrand that
# here represents the Lagrangian:
L=sqrt((1+y1**2)/(2*g*y))
# this differentiates the above with
# respect to a2, to define the integrand:
difL = L.diff(a2)
It is difL which I am wanting to integrate. I have tried defining it as a function in the following way:
def integrand(a2):
return difL
f = lambdify(x, integrand(a2))
to no avail. So my question is: how can I convert difL into a function which can then be integrated using scipy.integrate.quad?
And, as a disclaimer, I am new to Python, so if I've been employing terms incorrectly, let me know.
You do not need scipy, sympy is perfectly capable of numerical integration. Now, you have a lot of variables you are not defining (e.g. g) so I'll construct an easier example, and let you adapt to your question.
from sympy import *
from sympy.abc import x, a
# x is variable, a is parameter
y = x**2 + a
# integrate over x from 0 to 1; then evaluate with the value of the parameter
integrate(y, (x, 0, 1)).evalf(subs={a: -4})
I am trying to plot an integration of a special (eg. Bessel) function and my minimal code is the following.
#!/usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
import scipy.integrate as integrate
import scipy.special as sp
from scipy.special import jn
#x = np.arange(0.0, 10.0, 0.1)
U = np.linspace(0,10,1000)
#Delta = U**2
#Delta = U-4+8*integrate.quad(lambda x: sp.jv(1,x)/(x*(1.0+np.exp(U*x*0.5))), 0, 100)
Delta = U-4+8*integrate.quad(lambda x: jn(1,x)/(x*(1.0+np.exp(U*x*0.5))), 0.1, 1000)
plt.plot(U,Delta)
plt.xlabel('U')
plt.ylabel('$\Delta$')
plt.show()
However, this gives me several an error messages saying quadpack.error: Supplied function does not return a valid float whereas the function gets easily plotted in Mathematica. Do Python's Bessel's functions have limitations?
I have used this documentation for my plotting.
It is difficult to provide an answer that solves the problem before understanding what exactly you are trying to do. However, let me list a number of issues and provide an example that may not achieve what you are trying to do but at least it will provide a path forward.
Because your lambda function multiplies x by an array U, it returns an array instead of a number. A function that needs to be integrated should return a single number. You could fix this, for example, by replacing U by u:
f = lambda x, u: jn(1,x)/(x*(1.0+np.exp(u*x*0.5)))
Make Delta a function of u AND make quad pass additional argument u to f (defined in the previous point) AND extract only the value of the integral from the returned tuple from quad (quad returns a tuple of several values: the integral, the error, etc.):
Delta = lambda u: -4+8*integrate.quad(f, 0.1, 1000, args=(u,))[0]
Compute Delta for each u:
deltas = np.array(map(Delta, U))
plot the data:
plt.plot(U, deltas)
I'd like to calculate the derivative, then solve for when it is zero.
I am using the sympy module to do this.
r = somefunction(x1,x2)
Using this function, I'd like to be able to call these two matrices.
r_grad = [r.diff(x1), r.diff(x2)]
r_hess = [[r.diff(x1,x1), r.diff(x1,x2)],[r.diff(x2,x1), r.diff(x2,x2)]]
I'd then like to solve for when r_grad[0] and r_grad[1] == 0, and plug that into the hessian.
How can I make these .diff() symbols callable?
SymPy has a lambdify module for these purposes:
from sympy.utilities.lambdify import lambdify
func = lambdify((x1, x2), r.diff(x1))
func(1, 2) # evaluate the function efficiently at (1, 2)
I am trying to calculate the definite integral of a function with multiple variables over just one variable in scipy.
This is kind of like what my code looks like-
from scipy.integrate import quad
import numpy as np
def integrand(x,y):
return x*np.exp(x/y)
quad(integrand, 1,2, args=())
And it returns this type error:
TypeError: integrand() takes exactly 2 arguments (1 given)
However, it works if I put a number into args. But I don't want to, because I want y to remain as y and not a number. Does anyone know how this can be done?
EDIT: Sorry, don't think I was clear. I want the end result to be a function of y, with y still being a symbol.
Thanks to mdurant, here's what works:
from sympy import integrate, Symbol, exp
from sympy.abc import x
y=Symbol('y')
f=x*exp(x/y)
integrate(f, (x, 1, 2))
Answer:
-(-y**2 + y)*exp(1/y) + (-y**2 + 2*y)*exp(2/y)
You probably just want the result to be a function of y right?:
from scipy.integrate import quad
import numpy as np
def integrand(x,y):
return x*np.exp(x/y)
partial_int = lambda y: quad(integrand, 1,2, args=(y,))
print partial_int(5)
#(2.050684698584342, 2.2767173686148355e-14)
The best you can do is use functools.partial, to bind what arguments you have for the moment. But one fundamentally cannot numerically integrate a definite integral if you havnt got the entire domain specified yet; in that case the resulting expression will necessarily still contain symbolic parts, so the intermediate result isn't numerical.
(Assuming that you are talking about computing the definite integral over x given a specific, fixed value of y.)
You could use a lambda:
quad(lambda x:integrand(x, 10), 1, 2, args=())
or functools.partial():
quad(functools.partial(integrand, y=10), 1, 2, args=())
from scipy.integrate import quad
import numpy as np
def integrand(x,y):
return x*np.exp(x/y)
vec_int = np.vectorize(integrand)
y = np.linspace(0, 10, 100)
vec_int(y)