# Common Operations¶

## What common operations are supported?¶

Just normal mappers:

• Evaluation
• Turning expressions into 'human-readable' strings
• Performing substitution
• Taking derivatives
• Finding variables on which an expression depends
• Code Generation

Also:

• Parsing (i.e. turning a string into an expression)

## Finding Independent Variables¶

In [3]:
from pymbolic.mapper.dependency import DependencyMapper

depmap = DependencyMapper()
depmap(expr)

Out[3]:
{Variable('x'), Variable('y')}
In [ ]:
##


## Code generation¶

In [4]:
from pymbolic.mapper.c_code import CCodeMapper

ccm = CCodeMapper()
x = parse("x")
ccm((x+4)**17)

Out[4]:
'pow(x + 4, 17)'

(We're using parse here just to give us a Variable("x") object.)

## Common subexpressions¶

Often, some parts of an expression occur multiple times in a bigger expression.

In [5]:
u = (x+4)**3

h = parse("h")

expr = u + 2*u*h + 4*u*h**2
ccm(expr)

Out[5]:
'pow(x + 4, 3) + 4 * pow(x + 4, 3) * h * h + 2 * pow(x + 4, 3) * h'

Obviously, that doesn't lead to great code. In particular, the redundancy is carried through to the code side.

There is a mechanism to prevent this redundancy. Individual parts of an expression can be tagged as "common subexpressions".

In [6]:
from pymbolic.primitives import CommonSubexpression as CSE

u = CSE((x+4)**3)

h = parse("h")

expr = u + 2*u*h + 4*u*h**2

result = ccm(expr)

for name, value in ccm.cse_name_list:
print(name, "=", value)

print(result)

_cse0 = pow(x + 4, 3)
_cse0 + 4 * _cse0 * h * h + 2 * _cse0 * h


(These names can be customized, in case you're wondering.)