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.)