#!/usr/bin/env python
# coding: utf-8
# # Defining Custom Node Types
# Mathematical expressions are only the first step. Most of the time, in mathematical software, the interesting aspects are special "things" that are strung together by expressions.
#
# So it would be helpful to be able to define our own expression types:
# In[2]:
import pymbolic.primitives as p
x = p.Variable("x")
# In[3]:
class DerivativeOperator(p.Expression):
def __init__(self, operand):
self.operand = operand
def __getinitargs__(self):
return (self.operand,)
mapper_method = "map_derivative_operator"
# `__getinitargs__` tells `pymbolic` what the arguments of the constructor were. This is used for printing and comparisons.
# In[4]:
u = x/DerivativeOperator((x + 23)**0.5)
u
# We can then also define custom mappers (let's call ours `DerivDoubler`) that operate on these node types:
# In[5]:
from pymbolic.mapper import IdentityMapper
# In[6]:
class DerivDoubler(IdentityMapper):
def map_derivative_operator(self, expr):
return 2*DerivativeOperator(self.rec(expr.operand))
# Now apply it:
# In[7]:
dd = DerivDoubler()
dd(u)
# In[ ]: