I'm trying to create a custom symbol in sympy that behaves like r = √(x2 + y2 + z2) -- specifically, ∂r/∂x = x/r:
from sympy import Symbol, symbols
x, y, z = symbols("x y z")
class _r(Symbol):
def __new__(self):
r = super().__new__(self, "r")
return r
def diff(self, var):
assert var in [x, y, z]
return 1 / self * var
r = _r()
The first derivative works as intended:
>>> r.diff(x)
x/r
The second derivative should return -x2/r3 + 1/r, but sympy doesn't differentiate the r
symbol again:
>>> r.diff(x).diff(x)
1/r
I inspected the intermediate result and found the following:
>>> d = r.diff(x)
>>> type(d)
sympy.core.mul.Mul
>>> d.free_symbols
{r, x}
>>> for s in d.free_symbols:
>>> print(s, type(s))
r <class '__main__._r'>
x <class 'sympy.core.symbol.Symbol'>
So it does still recognize r
as my custom object, but somehow that gets lost when calling .diff
of the resulting Mul
object.
How do I get this to work? Am I even on the right track by subclassing Symbol
?
I'm trying to create a custom symbol in sympy that behaves like r = √(x2 + y2 + z2) -- specifically, ∂r/∂x = x/r:
from sympy import Symbol, symbols
x, y, z = symbols("x y z")
class _r(Symbol):
def __new__(self):
r = super().__new__(self, "r")
return r
def diff(self, var):
assert var in [x, y, z]
return 1 / self * var
r = _r()
The first derivative works as intended:
>>> r.diff(x)
x/r
The second derivative should return -x2/r3 + 1/r, but sympy doesn't differentiate the r
symbol again:
>>> r.diff(x).diff(x)
1/r
I inspected the intermediate result and found the following:
>>> d = r.diff(x)
>>> type(d)
sympy.core.mul.Mul
>>> d.free_symbols
{r, x}
>>> for s in d.free_symbols:
>>> print(s, type(s))
r <class '__main__._r'>
x <class 'sympy.core.symbol.Symbol'>
So it does still recognize r
as my custom object, but somehow that gets lost when calling .diff
of the resulting Mul
object.
How do I get this to work? Am I even on the right track by subclassing Symbol
?
You can probably have your display/representation cake and eat it too if you switch to using a pair of symbols and rely on .subs()
to switch between them
R = symbols("R") # your special symbol
r = sqrt(x**2 + y**2 + z**2) # logical equivalence
>>> r.diff(x)
x/sqrt(x**2 + y**2 + z**2)
>>> r.diff(x).diff(x)
-x**2/(x**2 + y**2 + z**2)**(3/2) + 1/sqrt(x**2 + y**2 + z**2)
>>> r.diff(x).diff(x).subs(r, R)
1/R - x**2/R**3
sympy.Symbol
. I myself have derived a class frompint.Quantity
, but they provide aregistry
to register the class that is created. I wonder ifsympy
offers a similar mechanism. – Dr. V Commented Jan 4 at 22:02sympy
can know thatr
is a function ofx
,y
anz
, and what that function is. – Dr. V Commented Jan 4 at 22:24.diff
. See the guide for making custom functions: docs.sympy.org/latest/guides/custom-functions.html – Oscar Benjamin Commented Jan 4 at 23:00diff(x)
is a standard sympydiff(x)
and it takes a derivative ofx/r
, which is1/r
. To check, changediff()
in the_r
class definition tordiff()
. Runingr.rdiff(x).rdiff(x)
will result in an errorAttributeError: 'Mul' object has no attribute 'rdiff'
. However,r.rdiff(x).diff(x)
will result in1/r
. – Man made of meat Commented Jan 5 at 7:09