Search code examples
pythonsympysymbolic-math

sympy diff without resubstituting?


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.


Solution

  • 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