6

I'm a beginner in python. I've recently learned about Sympy and its symbolic manipulation capabilities, in particular, differentiation. I am trying to do the following in the easiest way possible:

  1. Define f(x,y) = x^2 + xy^2.
  2. Differentiate f with respect to x. So f'(x,y) = 2x + xy^2.
  3. Evaluate the derivative, e.g., f'(1,1) = 2 + 1 = 3.

I know how to do 1 and 2. The problem is, when I try to evaluate the derivative in step 3, I get an error that python can't calculate the derivative. Here is a minimal working example:

import sympy as sym
import math


def f(x,y):
    return x**2 + x*y**2


x, y = sym.symbols('x y')

def fprime(x,y):
    return sym.diff(f(x,y),x)

print(fprime(x,y)) #This works.

print(fprime(1,1)) 

I expect the last line to print 3. It doesn't print anything, and says "can't calculate the 1st derivative wrt 1".

  • Shouldn't you expect the last line to print 0? The derivative of 2 with respect to any variable is 0. – Erotemic May 30 '17 at 19:05
  • @user46944: Yes, but `fprime` actually calls `f(x, y)`. So `fprime(1, 1)` would first do `f(1, 1)` and then try to differentiate the result. (This is assuming `expr(x, y)` is the way to evaluate a sympy expression, which it isn't, which is part of the confusion here.) – BrenBarn May 30 '17 at 19:13

3 Answers3

7

Your function fprime is not the derivative. It is a function that returns the derivative (as a Sympy expression). To evaluate it, you can use .subs to plug values into this expression:

>>> fprime(x, y).evalf(subs={x: 1, y: 1})
3.00000000000000

If you want fprime to actually be the derivative, you should assign the derivative expression directly to fprime, rather than wrapping it in a function. Then you can evalf it directly:

>>> fprime = sym.diff(f(x,y),x)
>>> fprime.evalf(subs={x: 1, y: 1})
3.00000000000000
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • @user46944: No, because `fprime` is still a sympy expression, and you don't evaluate sympy expressions by calling them. You have to use `evalf`. – BrenBarn May 30 '17 at 19:15
  • @user46944: For that you could do `fprime.subs(y, 1)`. I don't think there is a way to make a sympy object that can be manipulated symbolically (e.g., differentiated) but can also be called to substitute values like that. To substitute values you need to to use `.subs` or `.evalf`. – BrenBarn May 30 '17 at 20:37
  • @user46944: Sympy expressions and Python functions are *two different things*. Sympy expressions can be differentiated, but not called. Python functions can be called, but not differentiated. Your original question doesn't say anything about plotting or these other issues you're raising in the comments. If you have some additional question, you should probably ask it as a separate question, including in the text of that question the code you're trying to use. – BrenBarn May 30 '17 at 21:18
  • @user46944: It's not differentiating your function, it's differentiating the *return value* of your function, which is a sympy expression. – BrenBarn May 31 '17 at 01:32
2

The answer to this question is pretty simple. Sure, the subs option given in the other answer works for evaluating the derivative at a number, but it doesn't work if you want to plot the derivative. There is a way to fix this: lambdify, as explained below.

Use lambdify to convert all of the sympy functions (which can be differentiated but not evaluated) to their numpy counterparts (which can be evaluated, plotted, etc., but not differentiated). For example, sym.sin(x) will be replaced with np.sin(x). The idea is: define the function using sympy functions, differentiate as needed, and then define a new function which is the lambdified version of the original function.

As in the code below, sym.lambdify takes the following inputs:

sym.lambdify(variable, function(variable), "numpy")

The third input, "numpy", is what replaces sympy functions with their numpy counterparts. An example is:

def f(x):
    return sym.cos(x)

def fprime(x):
    return sym.diff(f(x),x)

fprimeLambdified = sym.lambdify(x,f(x),"numpy")

Then the function fprime(x) returns -sym.sin(x), and the function fprimeLambdified(x) returns -np.sin(x). We can "call"/evaluate fprimeLambdified at specific input values now, whereas we cannot "call"/evaluate fprime, since the former is composed of numpy expressions and the latter sympy expressions. In other words, it makes sense to input fprimelambdified(math.pi), and this will return an output, while fprime(math.pi) will return an error.

An example of using sym.lambdify in more than one variable is seen below.

import sympy as sym
import math


def f(x,y):
    return x**2 + x*y**2


x, y = sym.symbols('x y')

def fprime(x,y):
    return sym.diff(f(x,y),x)

print(fprime(x,y)) #This works.

DerivativeOfF = sym.lambdify((x,y),fprime(x,y),"numpy")

print(DerivativeOfF(1,1))
0

When you call fprime(1,1) in the function fprime(x,y) you call it like this sym.diff(f(1,1),1)

You have to use different variables for x and the value of x

Quartal
  • 410
  • 3
  • 14
  • @user46944 I haven't used sympy so I'm not sure how it works exactly but if you changed it to something like this def fprime(xValue, y): return sym.diff(f(valueX, y),x) I think it should work – Quartal May 30 '17 at 19:14
  • @user46944 x, y = sym.symbols('x y') this line sets x value right? – Quartal May 30 '17 at 19:23
  • @user46944 In the function def f(x,y): return x**2 + x*y**2 x takes the value which you call the function with – Quartal May 30 '17 at 20:16