Reputation: 339
I want to take the derivative of a multivariable function using SymPy and then for a) the symbolic result to be printed and then b) the result of the derivative at a point to be printed. I'm using the following code
import math as m
import numpy
import scipy
#define constants
lambdasq = 0.09
Ca = 3
qOsq = 2
def f1(a,b,NN,ktsq,x):
return NN*x**(-a)*ktsq**b*m.exp(m.sqrt(16*Ca/9*m.log(1/x)*m.log((m.log(ktsq/lambdasq))/m.log(qOsq/lambdasq))))
from sympy import *
x = symbols('x')
def f2(NN,a,b,x,ktsq):
return -x*diff(m.log(f1),x)
This runs but I can't find a way to get the symbolic result to be printed and when I try to evaluate at a point, say e.g adding in print(f2(0.3,0.1,-0.2,0.1,3))
I get an error
TypeError: must be real number, not function
When I replace f1
with its symbolic representation, I get instead the error
ValueError:
Can't calculate 1st derivative wrt 0.100000000000000.
So I can summarise my question as follows
a) How to print out a symbolic derivative and its value at a point when I call diff(m.log(f1),x)
(i.e without having to replace f1
by its actual representation)
b) If I have to use the symbolic representation in the differentiation (i.e use diff(m.log(NN*x**(-a)*ktsq**b*m.exp(m.sqrt(16*Ca/9*m.log(1/x)*m.log((m.log(ktsq\
/lambdasq))/m.log(qOsq/lambdasq))))),x)
then how to print out the symbolic derivative and its value at a point?
New to Python so hopefully there is a relatively simple fix. Thanks!
Upvotes: 3
Views: 4066
Reputation: 3845
I'm posting this answer since this thread is #1 on my search engine when searching for 'simpy multivariate differentiation' and might help someone.
import sympy as sp
def f(u):
return (u[0]**2 + u[1]**10 + u[2] - 4)**2
u = sp.IndexedBase('u')
print(sp.diff(f(u), u[0]))
outputs
4*(u[0]**2 + u[1]**10 + u[2] - 4)*u[0]
This is the derivative of f(u) wrt u[0]
if we want the whole jacobian, we can do:
for i in range(3):
print(sp.diff(f(u), u[i]))
which outputs
4*(u[0]**2 + u[1]**10 + u[2] - 4)*u[0]
20*(u[0]**2 + u[1]**10 + u[2] - 4)*u[1]**9
2*u[0]**2 + 2*u[1]**10 + 2*u[2] - 8
we can define a temp function and copy paste these lines
def temp(u):
return np.array([
4*(u[0]**2 + u[1]**10 + u[2] - 4)*u[0],
20*(u[0]**2 + u[1]**10 + u[2] - 4)*u[1]**9,
2*u[0]**2 + 2*u[1]**10 + 2*u[2] - 8,
])
temp([1., 1., 1.])
this outputs array([ -4., -20., -2.])
and to verify
from autograd import grad
gradient = grad(f)
gradient([1., 1., 1.])
this outputs: [array(-4.), array(-20.), array(-2.)]
Note:This is just a simple showcase how you can do multivariate derivatives in sympy. I hope I can help someone with this
Upvotes: 3
Reputation:
First, math
functions are numeric, they cannot work with SymPy's symbols. Use the corresponding functions from SymPy (exp, log, sqrt) which you already imported with from sympy import *
:
def f1(a, b, NN, ktsq, x):
return NN*x**(-a)*ktsq**b*exp(sqrt(16*Ca/9*log(1/x)*log((log(ktsq/lambdasq))/log(qOsq/lambdasq))))
Second, within f2 you are trying to differentiate f1
. But f1 is a callable Python function, not a SymPy expression. You need to pass in some arguments to get a SymPy expression, which can then be differentiated.
def f2(NN, a, b, x0, ktsq):
return (-x*diff(log(f1(a, b, NN, ktsq, x)), x)).subs(x, x0)
Here the numeric arguments, except the value x0, are passed to f1, resulting in a SymPy expression containing x. That is a thing to be differentiated. After that, the numeric value x0 is substituted for x.
print(f2(0.3,0.1,-0.2,0.1,3)) # 0.366748952743614
A take-away point is that SymPy differentiates expressions, not functions. There is no concept of f'
in SymPy, only f'(x)
.
Upvotes: 1