简体   繁体   中英

Differentiation of a multivariate function via SymPy and evaluation at a point

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 eg 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) (ie without having to replace f1 by its actual representation)

b) If I have to use the symbolic representation in the differentiation (ie 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!

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) .

I'm posting this answer since this thread is #1 on my search engine when searching for 'simpy multivariate differentiation' and might help someone.

example 1

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]


example 2

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM