from __future__ import annotations
from metadsl import *
from metadsl_core import *
from metadsl_visualize import *
import metadsl_core.vec
set_rule(all_rules)
metadsl
Demo¶In this notebook we show a few examples of using metadsl
. The outputs are interactive widgets that show the progress of replacing the expressions. You can drag the slider to move from the original expression to the final replaced one
We can create a vector type and then index it, to see the conversion progress:
Vec.create(Integer.from_int(1), Integer.from_int(2))[Integer.from_int(0)]
VBox(children=(IntSlider(value=0, max=3), Output()))
If we look at how this is implemented, we see how we define a rule to replace indexing a vector:
metadsl_core.vec.getitem??
Signature: metadsl_core.vec.getitem(i: 'int', xs: 'typing.Sequence[T]') -> 'R[T]' Call signature: metadsl_core.vec.getitem(expr: object) -> Iterable[metadsl.rules.Replacement] Type: MatchRule String form: metadsl_core.vec.getitem File: ~/p/metadsl/metadsl_core/vec.py Source: @register # type: ignore @rule def getitem(i: int, xs: typing.Sequence[T]) -> R[T]: return (Vec[T].create(*xs)[Integer.from_int(i)], lambda: xs[i]) Class docstring: Creates a replacement rule given a function that maps from wildcard inputs to two things, a template expression tree and a replacement thunk. If the template matches an expression, it will be replaced with the result of the thunk, replacing the input args with the nodes at their locations in the template. You can also return None from the rule to signal that it won't match.
Now we can try creating some NumPy arrays and indexing them. We see that through the replacement system we figure out if we are indexing with a tuple or an integer. This is an easier place to compile to different backends (like LLVM) than just the raw NumPy calls:
arange(10)[5]
VBox(children=(IntSlider(value=0, max=3), Output()))
arange(10)[(2,)]
VBox(children=(IntSlider(value=0, max=3), Output()))
Now we can show one way of compiling these calls, by replacing them with the corresponding NumPy calls, to compute the results:
unbox_ndarray_compat(arange(10)[5])
VBox(children=(IntSlider(value=0, max=3), Output()))
unbox_ndarray_compat(arange(10)[(2,)])
VBox(children=(IntSlider(value=0, max=3), Output()))
In this demo, we show how we can break up the NumPy API into different layers, all of which are extensible:
The key is that all these layers are composable, so you could have different frontends for any of them or add your own. This is all done through a typed replacement system that is compatible with static analysis using MyPy.