sympy diff without resubstituting?

54 views Asked by At

I'm facing problems using python sympy.

The problem is reduced to very minimal working examples

import sympy as sp
from sympy import *

x, xb, xi, alpha = sp.symbols('x xbar xi alpha')
Eqxb = sp.Eq(xb, (x+xi) )
problemExpr = (xb*cos(alpha))**2

# Following is zero for sure
display( problemExpr.diff(xi) )

# Naive approach
out = problemExpr.subs(xb, Eqxb.rhs).diff(xi).subs(Eqxb.rhs, xb)
display( out ) # gives (2x + 2 xi)*cos^2(alpha)
# Want I want is 2*xb*cos^(alpha)

# Some simple tests
test1 = (Eqxb.rhs + xb) 
display(test1.subs(Eqxb.rhs, xb)) # gives 2*xbar | -> good

# 
test2 = 2*(Eqxb.rhs + xb) 
display(test2.subs(Eqxb.rhs, xb)) # gives 2*x + 2*xbar + 2*xi | -> not good

# 
test3 = 2*x + 2*xi
display(test3.subs(Eqxb.rhs, xb)) # gives 2*x + 2*xi | -> not good

# test 4, explicit version 
display(test3.subs( { x+xi : xb })) # gives 2*x + 2*xi | -> not good

Questions 1: Why is the expression x+xi not properly substituted with xb. Am I using this function wrong? At least in test1 it works as expected.

Question 2: Here, this is a simple function with only one substitution. How is this performed, if multiple subs are necessary? This step of subs and re-subs seems like there should be at least one more elegant way.

1

There are 1 answers

1
smichr On BEST ANSWER

What about keeping a dictionary of things that you want to be able to differentiate but also want to represent as a simpler expression (like xb). Use a function of xb to do this as follows:

import sympy as sp
from sympy import *

x, xi, alpha = sp.symbols('x xi alpha')
xb = Function('xb')(x)
f = {xb: (x+xi)}
d = {k.diff(x):v.diff(x) for k,v in f.items()}
eq = (xb*cos(alpha))**2
>>> eq.diff(x)
2*xb(x)*cos(alpha)**2*Derivative(xb(x), x)
>>> eq.diff(x).subs(d)
2*xb(x)*cos(alpha)**2
>>> eq.diff(x).subs(d).subs(f)
2*(x + xi)*cos(alpha)**2

The issue of trying to replace a sum with a symbol is an often asked question. Unless the sum appears exactly as given in subs -- not with a constant multiplying each term -- the substitution will fail. Solving for one of the symbols in the sum other than the one you want to have in the final expression is the usual solution, e.g.

>>> from sympy.abc import y
>>> rep= solve(Eq(x + xi, y),exclude=[y],dict=True)[0]
>>> (2*x + 2*xi).subs(rep)
2*y