Slide 1

Slide 1 text

FAST AND CORRECT AND GENERATING CODE WITH SYMPY Jim Crist ME@UMN // github.com/jcrist // jcrist.github.io

Slide 2

Slide 2 text

What is SymPy??? • A Computer Algebra System (CAS) written in pure Python • Allows you to create expressions, and do things with them • SymPy knows about all the math needed

Slide 3

Slide 3 text

Create Expressions >>> from sympy import * # Create Symbols >>> a, b, c = symbols('a, b, c') # Combine Symbols into expressions >>> expr = sin(a) + cos(b**2)*c >>> expr sin(a) + cos(b**2)*c

Slide 4

Slide 4 text

Manipulate Expressions # subs performs substitutions on expressions >>> expr = expr.subs(b, a**(1/2)) >>> expr sin(a) + sin(a)*c # simplify reduces the size of expressions >>> expr = expr.simplify() >>> expr sin(a)*(1 + c)

Slide 5

Slide 5 text

Solve Expressions # Create another symbol x >>> x = symbols('x') # Quadratic equation >>> lhs = a*x**2 + b*x + c >>> expr = Eq(lhs, 0) >>> expr a*x**2 + b*x + c == 0 # Solve returns solutions to expressions >>> solve(expr, x) [(-b + sqrt(-4*a*c + b**2))/(2*a), -(b + sqrt(-4*a*c + b**2))/(2*a)]

Slide 6

Slide 6 text

Submodules (just a few…) • Calculus • Linear Algebra • Set Theory • Combinatorics • Differential Geometry • Tensors • Physics • etc…

Slide 7

Slide 7 text

Better Presentations on learning SymPy Available: SciPy 2014 Tutorial

Slide 8

Slide 8 text

Not what this talk is about…

Slide 9

Slide 9 text

WHY USE SYMPY???

Slide 10

Slide 10 text

WHY USE SYMPY??? I

Slide 11

Slide 11 text

Expressions Can Get Big… • Inverted Pendulum, 1 Link

Slide 12

Slide 12 text

Expressions Can Get Big… • Inverted Pendulum, 3 Links: Rendered in size 2.5 font

Slide 13

Slide 13 text

Expressions Can Get Big… • Inverted Pendulum, 3 Links: Rendered in size 2.5 font

Slide 14

Slide 14 text

DERIVE EQUATIONS IN SYMPY Solution:

Slide 15

Slide 15 text

github.com/pydy/pydy

Slide 16

Slide 16 text

Added Bonus: Code Generation MAGIC Symbolic Expression Numeric Code

Slide 17

Slide 17 text

SymPy Expression Trees >>> Lambda((a, b, c), sin(a) + cos(b**2)*c) Created with Graphviz

Slide 18

Slide 18 text

SymPy Expression Trees Two Rules: 1. .expr.args holds node children 2. “args invariant”* >>> expr.func(*expr.args) == expr *Some exceptions…

Slide 19

Slide 19 text

Operations are just Tree Manipulations

Slide 20

Slide 20 text

Example: subs def crawl(expr, func, *args, **kwargs): """Crawl the expression tree, and apply func to every node""" val = func(expr, *args, **kwargs) if val is not None: return val new_args = (crawl(arg, func, *args, **kwargs) for arg in expr.args) return expr.func(*new_args) def sub_func(expr, sub_dict): """Perform direct matching substitution""" if expr in sub_dict: return sub_dict[expr] elif not expr.args: return expr # Compose the subs function subs = lambda x, sub_dict: crawl(x, sub_func, sub_dict)

Slide 21

Slide 21 text

Python Abstract Syntax Trees >>> lambda a, b, c: sin(a) + cos(b**2)*c Created with Graphviz

Slide 22

Slide 22 text

Optimization = Tree Manipulation • Loop Optimizations • Fusion • Fission • Peephole Optimizations • Pattern matching and replacement • Function Inlining • Inline code inside larger function

Slide 23

Slide 23 text

Optimization = Tree Manipulation • Loop Optimizations • Fusion (Tensor Contraction) • Fission • Peephole Optimizations • Pattern matching and replacement (subs, replace, xreplace) • Function Inlining • Inline code inside larger function (subs)

Slide 24

Slide 24 text

BUILDING A MATHEMATICS COMPILER

Slide 25

Slide 25 text

Need new tree elements • Routine • Argument • DataType • Assignment

Slide 26

Slide 26 text

Need transformations • Type Inferral (assumption system) • Indexed Operations → For Loops • Assignment Propagation

Slide 27

Slide 27 text

Need scoped code printer • Easy with Visitor Pattern

Slide 28

Slide 28 text

Visitor Pattern 1. .Printer has methods for each node type 2. .Printer._print dispatches to appropriate print method 3. Recursively call Printer._print for all args in tree

Slide 29

Slide 29 text

Example: _print_For class CCodePrinter(CodePrinter): ... def _print_For(self, expr): target = self._print(expr.target) start, stop, step = expr.iterable.args body = '\n'.join(self._print(i) for i in expr.body) return ('for ({target} = {start}; {target} < {stop}; ' '{target} += {step}) {{\n{body}\n}}').format( target=target, start=start, stop=stop, step=step, body=body)

Slide 30

Slide 30 text

Printers Symbolic Expression Numeric Code Generators Wrappers • C • Fortran • Javascript • Mathematica • Theano • C • Fortran • Cython • F2Py • Numpy ufuncs

Slide 31

Slide 31 text

Demo (try it at github.com/jcrist/codegen_talk)

Slide 32

Slide 32 text

Fast • Compile to native code • Can be smarter than a normal compiler • Domain knowledge >>> peephole optimizations • Change algorithmic complexity • ufuncs → Broadcasting and type conversion for free

Slide 33

Slide 33 text

Correct • No silly math/typing errors • Program declaratively • Validate expressions symbolically before compilation

Slide 34

Slide 34 text

The Future • More Optimizations • Horner’s Method • Common sub-expression elimination • BLAS/LAPACK method selection • Boolean Support • Expressive Iteration (map, reduce, filter, …) • More Modular • Templating • github.com/jcrist/symcc (shameless plug)

Slide 35

Slide 35 text

Questions???