I have a python function with variable number of arguments:
F(x1, x2, ... , xN)
I want to automatically generate N functions representing the derivatives of F with respect to each argument.
F'_1 = dF/dx1
F'_2 = dF/dx2
...
F'_N = dF/dxN
For example, I be able to give both
F(x1) = sin(x1)
and
F(x1, x2) = sin(x1) * cos(x2)
and get all the derivatives automatically.
Edit2:
If function F was 2 variable (fixed number of arguments), I could use
def f(x,y):
return sin(x)*cos(y)
from sympy import *
x, y = symbols('x y')
f_1 = lambdify((x,y), f(x,y).diff(x))
The trick is to use inspect.getargspec to get the names of all the arguments to the function. After that, it's a simple list comprehension:
import inspect
from sympy import *
def get_derivatives(func):
arg_symbols = symbols(inspect.getargspec(func).args)
sym_func = func(*arg_symbols)
return [lambdify(arg_symbols, sym_func.diff(a)) for a in arg_symbols]
For example:
def f(x, y):
return sin(x)*cos(y)
all_derivatives = get_derivatives(f)
Related
I want to work with generic functions as long as possible, and only substitute functions at the end.
I'd like to define a function as the derivative of another one, define a generic expression with the function and its derivative, and substitute the function at the end.
Right now my attempts is as follows, but I get the error 'Derivative' object is not callable:
from sympy import Function
x, y, z = symbols('x y z')
f = Function('f')
df = f(x).diff(x) # <<< I'd like this to be a function of dummy variable x
expr = f(x) * df(z) + df(y) + df(0) # df is unfortunately not callable
# At the end, substitute with example function
expr.replace(f, Lambda(X, cos(X))) # should return: -cos(x)*sin(z) - sin(y) - sin(0)
I think I got it to work with integrals as follows:
I= Lambda( x, integrate( f(y), (y, 0, x))) but that won't work for derivatives.
If that helps, I'm fine restricting myself to functions of a single variable for now.
As a bonus, I'd like to get this to work with any combination (products, derivatives, integrals) of the original function.
It's pretty disappointing that f.diff(x) doesn't work, as you say. Maybe someone will create support it sometime in the future. In the mean time, there are 2 ways to go about it: either substitute x for your y, z, ... OR lambdify df.
I think the first option will work more consistently in the long run (for example, if you decide to extend to multivariate calculus). But the expr in second option is far more natural.
Using substitution:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = f(x).diff(x)
expr = f(x) * df.subs(x, z) + df.subs(x, y) + df.subs(x, 0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Lambdifying df:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = lambda t: f(t).diff(t) if isinstance(t, Symbol) else f(X).diff(X).subs(X, t)
expr = f(x) * df(z) + df(y) + df(0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Both give the desired output.
I have learned how to automatically find the partial derivative of a function with sympy. My problem is, I need to define a new function that returns the partial derivative of the other function.
from sympy import Symbol, Derivative
y= Symbol('y')
function = y ** 2
deriv = Derivative(function, y).doit()
def func(y):
return deriv
Something like that. Hope you all understood. Thanks!
So y is another function as in predefined like y = Symbol('x') ** 2? I believe your function need another input.
x = Symbol('x')
y = x ** 2
def func(function, symbol):
deriv = Derivative(function, symbol).doit()
return deriv
derivative = func(y, x)
You can't do it without specifying symbol - especially since this is partial derivative you need to tell which symbol it's trying to derive against.
I am trying to differentiate z(x) w.r.t. x using the ad library, where I know y(x) and z(y). If I cannot analytically find z(x), how can I perform the differentiation? In other words, I am trying to avoid the chain rule calculation as shown below:
from ad import gh
def y(x):
return 2*x
def z(y):
return 3*y
dzdy,hy = gh(z)
dydx,hz = gh(y)
x0 = 0 # does not matter for this example
dydx_x0 = dydx(x0)
y0 = y(x0)
dzdy_y0 = dzdy(y0)
dzdx_x0 = dzdy_y0[0] * dydx_x0[0]
print(dzdx_x0) # dz/dx = dz/dy*dy/dx = 3*2 = 6
def z_of_x(x):
return z(y(x))
gradient, hessian = gh(z_of_x)
Just define a function to compute z in terms of x, and apply automatic differentiation as usual.
import numpy
import matplotlib.pyplot as plt
from scipy import integrate
def f(x,y):
return x*y + x**2
def integral(x,y):
I = integrate.quad(f, 0, x, args=(y,))[0]
return I
def gau(x,y):
return (1+x)*integral(x,y)
xlist = numpy.linspace(-3.0, 3.0, 100)
ylist = numpy.linspace(-3.0, 3.0, 100)
X, Y = numpy.meshgrid(xlist, ylist)
Z = gau(2, Y)
print(Z)
I keep on getting the error message "Supplied function does not return a valid float." , I think the problem is that I try to pass an array to the quad function. I thought about evaluating the integral for every entry of the array with something like that:
yi=numpy.linspace(-3.0,3.0,100)
for i, item in enumerate(yi):
return integral[i]=integrate.quad(f,0,x,args=(yi,))[0]
It doesn't work but is it the right way? Any other/better suggestions?
You could use a universal function (see https://docs.scipy.org/doc/numpy/reference/ufuncs.html) which operates on arrays element-by-element. You can create these universal functions from any function using the frompyfunc function (https://docs.scipy.org/doc/numpy/reference/generated/numpy.frompyfunc.html):
ugau = numpy.frompyfunc(gau,2,1)
Z=ugau(X,Y)
It if your f() that does not provide a valid float when passed an array, not the scipy.integral itself;
why do you pass an array to your f() ?
You can use quadpy (one of my projects). quadpy is fully vectorized with respect to the dimensionality of the function range and the domains, so you can plug in a function that returns a vector and integrate that function over many intervals at once. You just have to make sure that the input function deals with vectorized input correctly. In your case, that would be
import numpy
import quadpy
def f(x, y):
return numpy.multiply.outer(y, x) + numpy.multiply.outer(numpy.ones_like(y), x ** 2)
def integral(x, y):
scheme = quadpy.line_segment.gauss_legendre(5)
intervals = numpy.array([numpy.zeros_like(x), x])
out = scheme.integrate(lambda t: f(t, y), intervals)
return out
def gau(x, y):
return (1 + x) * integral(x, y)
xlist = numpy.linspace(-3.0, 3.0, 100)
ylist = numpy.linspace(-3.0, 3.0, 100)
Z = gau(2, ylist)
print(Z)
You also insert xlist instead of 2 here to compute it all at once.
I am a beginner/intermediate in Python. I have coded a 4th-order Runge-Kutta method (RK4) into Python. It is basically solving a pendulum, but that is not the point here.
I want to improve the RK4 method in the following way: I want to be able to pass the function f directly to the RK4 function, i.e. RK4(y_0, n, h) should become RK4(f,y_0,n,h). This would have the great advantage that I could use RK4 for other f functions that describe other systems, not just this one pendulum.
I have played around with just passing simple functions to RK4, but I am doing something wrong. How do I do this in Python?
import numpy as np
def RK4(y_0, n, h):
#4th order Runge-Kutta solver, takes as input
#initial value y_0, the number of steps n and stepsize h
#returns solution vector y and time vector t
#right now function f is defined below
t = np.linspace(0,n*h,n,endpoint = False) #create time vector t
y = np.zeros((n,len(y_0))) #create solution vector y
y[0] = y_0 #assign initial value to first position in y
for i in range(0,n-1):
#compute Runge-Kutta weights k_1 till k_4
k_1 = f(t[i],y[i])
k_2 = f(t[i] + 0.5*h, y[i] + 0.5*h*k_1)
k_3 = f(t[i] + 0.5*h, y[i] + 0.5*h*k_2)
k_4 = f(t[i] + 0.5*h, y[i] + h*k_3)
#compute next y
y[i+1] = y[i] + h / 6. * (k_1 + 2.*k_2 + 2.*k_3 + k_4)
return t,y
def f(t,vec):
theta=vec[0]
omega = vec[1]
omegaDot = -np.sin(theta) - omega + np.cos(t)
result = np.array([omega,omegaDot])
return result
test = np.array([0,0.5])
t,y = RK4(test,10,0.1)
Python functions are objects too. You can pass them around like any other object:
>>> def foo(): print 'Hello world!'
...
>>> foo
<function foo at 0x10c4685f0>
>>> foo()
Hello world!
>>> bar = foo
>>> bar()
Hello world!
Simply pass a function as an extra parameter to your RK4 function and use that as a local variable.
You can pass a function to a function in Python just as you might expect:
def call_function(f):
f()
def my_function():
print "OK"
call_function(my_function) # Prints OK
Maybe you should post your failing code?
It's very simple. Change the definition of the RK4 function like so:
def RK4(f, y_0, n, h):
Here, I have added an extra argument, the function.
Then, when you call RK4, pass the function:
t, y = RK4(f, test, 10, 0.1)
And now, of course, you can substitute different functions without having to re-write the integration code.
Functions in Python are just another kind of object. You can pass them around just as you do more prosaic objects.