Search code examples
pythonpython-3.xsyntax-errorsympydifferentiation

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!


Solution

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