Comments (3)
Sure, I think that could work. It's easy to define your own node types and to code term rewriting/traversals to do the operator squashing "fusion" (see the mini-tutorial in the docs). And there's also arithmetic between nodes if you need it.
from pymbolic.
Thanks for the pointer. I played around with it a little bit, and it seems to work roughly the way I would expect. So far I did this:
"""
Testing:
https://documen.tician.de/pymbolic/
"""
import pymbolic as pmbl
from pymbolic.mapper import IdentityMapper
from pymbolic.primitives import Expression
import numpy as np
class AutoInspectable(object):
"""
Helper to provide automatic defaults for pymbolic expressions
"""
def init_arg_names(self):
return tuple(self._initkw().keys())
def __getinitargs__(self):
return tuple(self._initkw().values())
def _initkw(self):
import inspect
from collections import OrderedDict
sig = inspect.signature(self.__class__)
initkw = OrderedDict()
for name, info in sig.parameters.items():
if not hasattr(self, name):
raise NotImplementedError((
'Unable to introspect init args because the class '
'did not have attributes with the same names as the '
'constructor arguments'))
initkw[name] = getattr(self, name)
return initkw
class AutoExpression(AutoInspectable, Expression):
pass
class Warp(AutoExpression):
def __init__(self, sub_data, transform):
self.sub_data = sub_data
self.transform = transform
mapper_method = "map_warp"
class ChanCat(AutoExpression):
def __init__(self, components):
self.components = components
mapper_method = "map_chancat"
class RawImage(AutoExpression):
def __init__(self, data):
self.data = data
mapper_method = "map_raw"
class WarpFusionMapper(IdentityMapper):
def map_warp(self, expr):
if isinstance(expr.sub_data, Warp):
# Fuse neighboring warps
t1 = expr.transform
t2 = expr.sub_data.transform
new_tf = t1 @ t2
new_subdata = self.rec(expr.sub_data.sub_data)
new = Warp(new_subdata, new_tf)
return new
elif isinstance(expr.sub_data, ChanCat):
# A warp followed by a ChanCat becomes a ChanCat followed by that
# warp
tf = expr.transform
new_components = []
for comp in expr.sub_data.components:
new_comp = Warp(comp, tf)
new_components.append(new_comp)
new = ChanCat(new_components)
new = self.rec(new)
return new
else:
return expr
def map_chancat(self, expr):
# ChanCat is associative
new_components = []
def _flatten(comps):
for c in comps:
if isinstance(c, ChanCat):
yield from _flatten(c.components)
else:
yield c
new_components = [self.rec(c) for c in _flatten(expr.components)]
new = ChanCat(new_components)
return new
def map_raw(self, expr):
return expr
class Transform:
# temporary transform class for easier to read outputs in POC
def __init__(self, f):
self.f = f
def __matmul__(self, other):
return Transform(self.f * other.f)
def __str__(self):
return 'Tranform({})'.format(self.f)
def __repr__(self):
return 'Tranform({})'.format(self.f)
raw1 = RawImage('image1')
w1_a = Warp(raw1, Transform(2))
w1_b = Warp(w1_a, Transform(3))
raw2 = RawImage('image2')
w2_a = Warp(raw2, Transform(5))
w2_b = Warp(w2_a, Transform(7))
raw3 = RawImage('image3')
w3_a = Warp(raw3, Transform(11))
w3_b = Warp(w3_a, Transform(13))
cat1 = ChanCat([w1_b, w2_b])
warp_cat = Warp(cat1, Transform(17))
cat2 = ChanCat([warp_cat, w3_b])
mapper = WarpFusionMapper()
print('cat2 = {!r}'.format(cat2))
result1 = mapper(cat2)
print('result1 = {!r}'.format(result1))
result2 = mapper(result1)
print('result2 = {!r}'.format(result2))
result3 = mapper(result2)
print('result3 = {!r}'.format(result3))
This gives me:
cat2 = ChanCat([Warp(ChanCat([Warp(Warp(RawImage('image1'), Tranform(2)), Tranform(3)), Warp(Warp(RawImage('image2'), Tranform(5)), Tranform(7))]), Tranform(17)), Warp(Warp(RawImage('image3'), Tranform(11)), Tranform(13))])
result1 = ChanCat([ChanCat([Warp(Warp(RawImage('image1'), Tranform(2)), Tranform(51)), Warp(Warp(RawImage('image2'), Tranform(5)), Tranform(119))]), Warp(RawImage('image3'), Tranform(143))])
result2 = ChanCat([Warp(RawImage('image1'), Tranform(102)), Warp(RawImage('image2'), Tranform(595)), Warp(RawImage('image3'), Tranform(143))])
result3 = ChanCat([Warp(RawImage('image1'), Tranform(102)), Warp(RawImage('image2'), Tranform(595)), Warp(RawImage('image3'), Tranform(143))])
Each call to the mapper seems to only some of the possible reductions on the tree. I have to call it twice for it to finish fusing and shuffling everything. Calling it the third time doesn't change anything, which is expected.
Is there a recommended way to accomplish "full simplification?". Additionally, if you have time to look over my implementation to check to see if I'm adhering to best practices, or if I'm using the library in a way I shouldn't be, I'd appreciate it.
from pymbolic.
Is there a recommended way to accomplish "full simplification?"
I think this depends on how you write the individual map_...
routines. Potentially, the output of self.rec(...)
will allow for further simplification, but you'd need to check for that.
from pymbolic.
Related Issues (20)
- Cached mappers can't handle lists HOT 8
- Minimum python version for running tests is unexpectedly 3.10 HOT 2
- Test missing assertions HOT 3
- Pymbolic to SymEngine conversion error when using FloorDiv. HOT 6
- ParseError when parsing assignment expression HOT 4
- pymbolic interoperabiity with python ast described in the pymbolic documentation raises an exception under python 3.8.2 HOT 2
- Symengine version mismatch in CI HOT 9
- TypeError for foreign unhashable types HOT 4
- Mapper for deriving subexpressions as a list HOT 1
- [parser] Cannot parse boolean literals HOT 2
- Use a better parser HOT 3
- Method for removing the `__getinitargs__` and `init_arg_names` boilerplate. HOT 1
- Symengine conversion fails due to potentially spurious isinstance check HOT 2
- [Parser] Incorrect if-else precedence
- StringifyMapper: Incorrect result for side-by-side product nodes HOT 7
- Stop auto-flattening HOT 3
- Equality comparison of DAGs can have exponential complexity
- EvaluationMapper can't handle math functions HOT 1
- Memoizing results of traversals HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pymbolic.