Derivative(expr, v)
that symbolically represents taking a derivative of an expression expr
with respect to variable v
.x
(given), what your code actually has to do is consider the derivative in a reference coordinate system consisting of coordinates r
and s
and therefore needs to apply the chain rule identityWrite a ChainRuleMapper
that applies this identity.
from pymbolic import var
from pymbolic.primitives import Expression
from pymbolic.mapper import IdentityMapper
x = var("x")
r = var("r")
s = var("s")
class Derivative(Expression):
# ...
pass
To avoid conflicts with a Derivative
node type that's already part of pymbolic, we call our mapper method map_deriv
.
# Solution
class Derivative(Expression):
def __init__(self, expr, v):
self.expr = expr
self.v = v
def __getinitargs__(self):
return (self.expr, self.v)
mapper_method = "map_deriv"
expr = var("sqrt")(Derivative(27*x**2+var("exp")(x), x))
print(repr(expr))
class ChainRuleMapper(IdentityMapper):
# ...
pass
# Solution
class ChainRuleMapper(IdentityMapper):
def map_deriv(self, expr):
return sum(Derivative(expr, ref_sym)*Derivative(ref_sym, x) for ref_sym in [r,s])
Now let's test this mapper:
crm = ChainRuleMapper()
crm(expr)
In case you are wondering why we can only use the 'clumsy', parenthesis-heavy form of the printed expression, it's because we haven't told pymbolic how to write out the shorter form. Here's how that can be done:
from pymbolic.mapper.stringifier import StringifyMapper, PREC_PRODUCT
class MyStringifyMapper(StringifyMapper):
def map_deriv(self, expr, enclosing_prec):
return "d(%s)/d%s" % (
self.rec(expr.expr, PREC_PRODUCT),
self.rec(expr.v, PREC_PRODUCT))
def stringifier(self):
return MyStringifyMapper
Derivative.stringifier = stringifier
print(crm(expr))