CAF
CAF

Reputation: 339

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

Answers (2)

charelf
charelf

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.

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

Upvotes: 3

user6655984
user6655984

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

Related Questions