made a neat modal system in gof

上级 bc3756f5
import unittest import unittest
import constructor_fodder as cf import constructor_fodder as cf
class Allocator: class Allocator:
def __init__(self, cls, ctor): def __init__(self, cls, ctor):
self.cls = cls self.cls = cls
......
import op, ext, lib, link, result, env, prog, features, opt, graph
import op, result, ext, link, env, features, toolbox, graph
from op import * from op import *
from result import *
from ext import * from ext import *
from lib import *
from link import * from link import *
from result import *
from env import * from env import *
from prog import *
from features import * from features import *
from opt import * from toolbox import *
import graph
# import op, ext, lib, link, result, env, prog, features, opt, graph
# from op import *
# from ext import *
# from lib import *
# from link import *
# from result import *
# from env import *
# from prog import *
# from features import *
# from opt import *
# import graph
...@@ -62,29 +62,44 @@ t2s = OpSubOptimizer(TransposeView, Sigmoid) ...@@ -62,29 +62,44 @@ t2s = OpSubOptimizer(TransposeView, Sigmoid)
s2t = OpSubOptimizer(Sigmoid, TransposeView) s2t = OpSubOptimizer(Sigmoid, TransposeView)
from constructor import Constructor # from constructor import Constructor
from allocators import BuildAllocator # from allocators import BuildAllocator
c = Constructor(BuildAllocator) # c = Constructor(BuildAllocator)
c.update(globals()) # c.update(globals())
globals().update(c) # globals().update(c)
# def inputs():
# x = (MyResult('x'))
# y = (MyResult('y'))
# z = (MyResult('z'))
# return x, y, z
class _test_all(unittest.TestCase): # def env(inputs, outputs, validate = True):
# return Env(inputs, outputs, features = [EquivTool], consistency_check = validate)
def inputs(self):
x = MyResult('x')
y = MyResult('y') import modes
z = MyResult('z') modes.make_constructors(globals(), name_filter = lambda x:x)
return x, y, z
def inputs():
x = modes.BuildMode(MyResult('x'))
y = modes.BuildMode(MyResult('y'))
z = modes.BuildMode(MyResult('z'))
return x, y, z
def env(self, inputs, outputs, validate = True): def env(inputs, outputs, validate = True):
return Env(inputs, outputs, features = [EquivTool], consistency_check = validate) inputs = [input.r for input in inputs]
outputs = [output.r for output in outputs]
return Env(inputs, outputs, features = [EquivTool], consistency_check = validate)
class _test_all(unittest.TestCase):
def test_0(self): def test_0(self):
x, y, z = self.inputs() x, y, z = inputs()
e = Add(AddInPlace(x, y), AddInPlace(x, y)) e = Add(AddInPlace(x, y), AddInPlace(x, y))
try: try:
g = self.env([x,y,z], [e]) g = env([x,y,z], [e])
except InconsistencyError, e: except InconsistencyError, e:
pass pass
else: else:
...@@ -94,68 +109,68 @@ class _test_all(unittest.TestCase): ...@@ -94,68 +109,68 @@ class _test_all(unittest.TestCase):
# the loop is needed because a2i will optimize in a random order and sometimes # the loop is needed because a2i will optimize in a random order and sometimes
# only one of them fails # only one of them fails
for i in xrange(100): for i in xrange(100):
x, y, z = self.inputs() x, y, z = inputs()
e = Add(Add(x, y), Add(y, x)) e = Add(Add(x, y), Add(y, x))
g = self.env([x,y,z], [e]) g = env([x,y,z], [e])
assert g.consistent() assert g.consistent()
a2i.optimize(g) a2i.optimize(g)
assert g.consistent() assert g.consistent()
assert str(g) != "[AddInPlace(AddInPlace(x, y), AddInPlace(y, x))]" assert str(g) != "[AddInPlace(AddInPlace(x, y), AddInPlace(y, x))]"
def test_2(self): def test_2(self):
x, y, z = self.inputs() x, y, z = inputs()
g = self.env([x,y,z], [Dot(AddInPlace(x, z), x)], False) g = env([x,y,z], [Dot(AddInPlace(x, z), x)], False)
assert not g.consistent() assert not g.consistent()
i2a.optimize(g) i2a.optimize(g)
assert g.consistent() assert g.consistent()
def test_3(self): def test_3(self):
for i in xrange(100): for i in xrange(100):
x, y, z = self.inputs() x, y, z = inputs()
e = Dot(Add(TransposeView(z), y), Add(z, x)) e = Dot(Add(TransposeView(z), y), Add(z, x))
g = self.env([x,y,z], [e]) g = env([x,y,z], [e])
assert g.consistent() assert g.consistent()
a2i.optimize(g) a2i.optimize(g)
assert g.consistent() assert g.consistent()
assert str(g) != "[Dot(AddInPlace(TransposeView(z), y), AddInPlace(z, x))]" assert str(g) != "[Dot(AddInPlace(TransposeView(z), y), AddInPlace(z, x))]"
def test_4(self): def test_4(self):
x, y, z = self.inputs() x, y, z = inputs()
e = Dot(AddInPlace(x,y), TransposeView(x)) e = Dot(AddInPlace(x,y), TransposeView(x))
g = self.env([x,y,z], [e], False) g = env([x,y,z], [e], False)
assert not g.consistent() assert not g.consistent()
g.replace(e.owner.inputs[1], Add(x,z)) g.replace(e.r.owner.inputs[1], Add(x,z).r)
assert g.consistent() assert g.consistent()
def test_5(self): def test_5(self):
x, y, z = self.inputs() x, y, z = inputs()
e = Dot(AddInPlace(x,y), TransposeView(TransposeView(TransposeView(TransposeView(Sigmoid(x)))))) e = Dot(AddInPlace(x,y), TransposeView(TransposeView(TransposeView(TransposeView(Sigmoid(x))))))
g = self.env([x,y,z], [e]) g = env([x,y,z], [e])
assert g.consistent() assert g.consistent()
g.replace(e.owner.inputs[1].owner.inputs[0], x, False) g.replace(e.r.owner.inputs[1].owner.inputs[0], x.r, False)
assert not g.consistent() assert not g.consistent()
def test_6(self): def test_6(self):
for i in xrange(100): for i in xrange(100):
x, y, z = self.inputs() x, y, z = inputs()
e = Dot(AddInPlace(x,Sigmoid(y)), Sigmoid(Sigmoid(Sigmoid(Sigmoid(Sigmoid(x)))))) e = Dot(AddInPlace(x,Sigmoid(y)), Sigmoid(Sigmoid(Sigmoid(Sigmoid(Sigmoid(x))))))
g = self.env([x,y,z], [e]) g = env([x,y,z], [e])
assert g.consistent() assert g.consistent()
s2t.optimize(g) s2t.optimize(g)
assert g.consistent() assert g.consistent()
assert str(g) != "[Dot(AddInPlace(x,TransposeView(y)), TransposeView(TransposeView(TransposeView(TransposeView(TransposeView(x))))))]" assert str(g) != "[Dot(AddInPlace(x,TransposeView(y)), TransposeView(TransposeView(TransposeView(TransposeView(TransposeView(x))))))]"
def test_7(self): def test_7(self):
x, y, z = self.inputs() x, y, z = inputs()
e = TransposeView(TransposeView(TransposeView(TransposeView(x)))) e = TransposeView(TransposeView(TransposeView(TransposeView(x))))
g = self.env([x,y,z], [e]) g = env([x,y,z], [e])
assert g.consistent() assert g.consistent()
chk = g.checkpoint() chk = g.checkpoint()
dtv_elim.optimize(g) dtv_elim.optimize(g)
assert str(g) == "[x]" assert str(g) == "[x]"
g.replace(g.equiv(e), Add(x,y)) g.replace(g.equiv(e.r), Add(x,y).r)
assert str(g) == "[Add(x, y)]" assert str(g) == "[Add(x, y)]"
g.replace(g.equiv(e), Dot(AddInPlace(x,y), TransposeView(x)), False) g.replace(g.equiv(e.r), Dot(AddInPlace(x,y), TransposeView(x)).r, False)
assert str(g) == "[Dot(AddInPlace(x, y), TransposeView(x))]" assert str(g) == "[Dot(AddInPlace(x, y), TransposeView(x))]"
assert not g.consistent() assert not g.consistent()
g.revert(chk) g.revert(chk)
...@@ -163,31 +178,31 @@ class _test_all(unittest.TestCase): ...@@ -163,31 +178,31 @@ class _test_all(unittest.TestCase):
assert str(g) == "[TransposeView(TransposeView(TransposeView(TransposeView(x))))]" assert str(g) == "[TransposeView(TransposeView(TransposeView(TransposeView(x))))]"
def test_8(self): def test_8(self):
x, y, z = self.inputs() x, y, z = inputs()
e = Dot(Dot(AddInPlace(x,y), AddInPlace(y,z)), Add(z,x)) e = Dot(Dot(AddInPlace(x,y), AddInPlace(y,z)), Add(z,x))
g = self.env([x,y,z], [e]) g = env([x,y,z], [e])
assert g.consistent() assert g.consistent()
a2i.optimize(g) a2i.optimize(g)
assert g.consistent() assert g.consistent()
assert str(g) != "[Dot(Dot(AddInPlace(x, y), AddInPlace(y, z)), AddInPlace(z, x))]" # we don't want to see that! assert str(g) != "[Dot(Dot(AddInPlace(x, y), AddInPlace(y, z)), AddInPlace(z, x))]" # we don't want to see that!
def test_9(self): def test_9(self):
x, y, z = self.inputs() x, y, z = inputs()
x.indestructible = True x.r.indestructible = True
e = AddInPlace(x, y) e = AddInPlace(x, y)
g = self.env([x,y,z], [e], False) g = env([x,y,z], [e], False)
assert not g.consistent() assert not g.consistent()
g.replace(e, Add(x, y)) g.replace(e.r, Add(x, y).r)
assert g.consistent() assert g.consistent()
def test_10(self): def test_10(self):
x, y, z = self.inputs() x, y, z = inputs()
x.indestructible = True x.r.indestructible = True
tv = TransposeView(x) tv = TransposeView(x)
e = AddInPlace(tv, y) e = AddInPlace(tv, y)
g = self.env([x,y,z], [e], False) g = env([x,y,z], [e], False)
assert not g.consistent() assert not g.consistent()
g.replace(tv, Sigmoid(x)) g.replace(tv.r, Sigmoid(x).r)
assert g.consistent() assert g.consistent()
......
import unittest
from result import ResultBase
from op import Op
from env import Env
from link import *
class Double(ResultBase):
def __init__(self, data, name = "oignon"):
assert isinstance(data, float)
ResultBase.__init__(self, role = None, data = data, name = name)
def __str__(self):
return self.name
def __repr__(self):
return self.name
class MyOp(Op):
nin = -1
def __init__(self, *inputs):
assert len(inputs) == self.nin
for input in inputs:
if not isinstance(input, Double):
raise Exception("Error 1")
self.inputs = inputs
self.outputs = [Double(0.0, self.__class__.__name__ + "_R")]
def perform(self):
self.outputs[0].data = self.impl(*[input.data for input in self.inputs])
class Unary(MyOp):
nin = 1
class Binary(MyOp):
nin = 2
class Add(Binary):
def impl(self, x, y):
return x + y
class Sub(Binary):
def impl(self, x, y):
return x - y
class Mul(Binary):
def impl(self, x, y):
return x * y
class Div(Binary):
def impl(self, x, y):
return x / y
import modes
modes.make_constructors(globals())
def inputs():
x = modes.BuildMode(Double(1.0, 'x'))
y = modes.BuildMode(Double(2.0, 'y'))
z = modes.BuildMode(Double(3.0, 'z'))
return x, y, z
def env(inputs, outputs, validate = True, features = []):
inputs = [input.r for input in inputs]
outputs = [output.r for output in outputs]
return Env(inputs, outputs, features = features, consistency_check = validate)
def perform_linker(env):
lnk = PerformLinker(env)
lnk.compile()
return lnk
class _test_PerformLinker(unittest.TestCase):
def test_0(self):
x, y, z = inputs()
e = mul(add(x, y), div(x, y))
perform_linker(env([x, y, z], [e])).run()
assert e.r.data == 1.5
if __name__ == '__main__':
unittest.main()
import unittest
from modes import *
from result import ResultBase
from op import Op
from env import Env
class Double(ResultBase):
def __init__(self, data, name = "oignon"):
assert isinstance(data, float)
ResultBase.__init__(self, role = None, data = data, name = name)
def __str__(self):
return self.name
def __repr__(self):
return self.name
def __add__(self, other):
return Add(self, other)
def convert(x):
if isinstance(x, float):
return Double(x)
elif isinstance(x, Double):
return x
raise Exception("Error 1")
class MyOp(Op):
nin = -1
def __init__(self, *inputs):
assert len(inputs) == self.nin
inputs = [convert(input) for input in inputs]
self.inputs = inputs
self.outputs = [Double(0.0, self.__class__.__name__ + "_R")]
def perform(self):
self.outputs[0].data = self.impl(*[input.data for input in self.inputs])
class Unary(MyOp):
nin = 1
class Binary(MyOp):
nin = 2
class Add(Binary):
def impl(self, x, y):
return x + y
class Sub(Binary):
def impl(self, x, y):
return x - y
class Mul(Binary):
def impl(self, x, y):
return x * y
class Div(Binary):
def impl(self, x, y):
return x / y
make_constructors(globals())
def inputs(mode):
x = mode(Double(1.0, 'x'))
y = mode(Double(2.0, 'y'))
z = mode(Double(3.0, 'z'))
return x, y, z
def env(inputs, outputs, validate = True):
inputs = [input.r for input in inputs]
outputs = [output.r for output in outputs]
return Env(inputs, outputs, features = [], consistency_check = validate)
class _test_Modes(unittest.TestCase):
def test_0(self):
x, y, z = inputs(BuildMode)
e = add(add(x, y), z)
g = env([x, y, z], [e])
assert str(g) == "[Add(Add(x, y), z)]"
assert e.r.data == 0.0
def test_1(self):
x, y, z = inputs(BuildEvalMode)
e = add(add(x, y), z)
g = env([x, y, z], [e])
assert str(g) == "[Add(Add(x, y), z)]"
assert e.r.data == 6.0
def test_2(self):
x, y, z = inputs(EvalMode)
e = add(add(x, y), z)
g = env([x, y, z], [e])
assert str(g) == "[Add_R]"
assert e.r.data == 6.0
def test_3(self):
x, y, z = inputs(BuildMode)
e = x + y + z
g = env([x, y, z], [e])
assert str(g) == "[Add(Add(x, y), z)]"
assert e.r.data == 0.0
def test_4(self):
x, y, z = inputs(BuildEvalMode)
e = x + 34.0
g = env([x, y, z], [e])
assert str(g) == "[Add(x, oignon)]"
assert e.r.data == 35.0
def test_5(self):
xb, yb, zb = inputs(BuildMode)
xe, ye, ze = inputs(EvalMode)
try:
e = xb + ye
except TypeError:
# Trying to add inputs from different modes is forbidden
pass
else:
raise Exception("Expected an error.")
if __name__ == '__main__':
unittest.main()
...@@ -44,21 +44,19 @@ class Op4(MyOp): ...@@ -44,21 +44,19 @@ class Op4(MyOp):
pass pass
from constructor import Constructor import modes
from allocators import BuildAllocator modes.make_constructors(globals())
c = Constructor(BuildAllocator)
c.update(globals())
for k, v in c.items():
globals()[k.lower()] = v
def inputs(): def inputs():
x = MyResult('x') x = modes.BuildMode(MyResult('x'))
y = MyResult('y') y = modes.BuildMode(MyResult('y'))
z = MyResult('z') z = modes.BuildMode(MyResult('z'))
return x, y, z return x, y, z
def env(inputs, outputs, validate = True): def env(inputs, outputs, validate = True):
inputs = [input.r for input in inputs]
outputs = [output.r for output in outputs]
return Env(inputs, outputs, features = [EquivTool], consistency_check = validate) return Env(inputs, outputs, features = [EquivTool], consistency_check = validate)
......
...@@ -42,30 +42,33 @@ class Add(MyOp): ...@@ -42,30 +42,33 @@ class Add(MyOp):
class Dot(MyOp): class Dot(MyOp):
nin = 2 nin = 2
from constructor import Constructor
from allocators import BuildAllocator
c = Constructor(BuildAllocator)
c.update(globals())
globals().update(c)
import modes
modes.make_constructors(globals())
def inputs(): def inputs():
x = MyResult('x') x = modes.BuildMode(MyResult('x'))
y = MyResult('y') y = modes.BuildMode(MyResult('y'))
z = MyResult('z') z = modes.BuildMode(MyResult('z'))
return x, y, z return x, y, z
def env(inputs, outputs, validate = True, features = []):
inputs = [input.r for input in inputs]
outputs = [output.r for output in outputs]
return Env(inputs, outputs, features = features, consistency_check = validate)
class _test_EquivTool(unittest.TestCase): class _test_EquivTool(unittest.TestCase):
def test_0(self): def test_0(self):
x, y, z = inputs() x, y, z = inputs()
sx = Sigmoid(x) sx = sigmoid(x)
e = Add(sx, Sigmoid(y)) e = add(sx, sigmoid(y))
g = Env([x, y, z], [e], features = [EquivTool]) g = env([x, y, z], [e], features = [EquivTool])
assert g.equiv(sx) is sx assert g.equiv(sx.r) is sx.r
g.replace(sx, Dot(x, z)) g.replace(sx.r, dot(x, z).r)
assert g.equiv(sx) is not sx assert g.equiv(sx.r) is not sx.r
assert isinstance(g.equiv(sx).owner, Dot.opclass) assert isinstance(g.equiv(sx.r).owner, Dot)
......
...@@ -3,6 +3,40 @@ ...@@ -3,6 +3,40 @@
from utils import AbstractFunctionError from utils import AbstractFunctionError
class Dispatcher(list):
all_dispatchers = {}
def __init__(self, name, description):
self.name = name
self.description = description
self.all_dispatchers[name] = self
def __call__(self, *inputs, **opts):
for candidate in self:
try:
return candidate(*inputs, **opts)
except TypeError:
continue
if opts:
s = " with options %s" % opts
else:
s = ""
raise OmegaTypeError("No candidate found for %s(%s) %s" \
% (self.name,
", ".join([input.__class__.__name__ for input in inputs]),
s))
def add_handler(self, x):
self.insert(0, x)
def fallback_handler(self, x):
self.append(x)
class Allocator: class Allocator:
def __init__(self, fn): def __init__(self, fn):
...@@ -56,50 +90,3 @@ class Constructor(dict): ...@@ -56,50 +90,3 @@ class Constructor(dict):
# class Constructor:
# def __init__(self):
# pass
# def add_module(self, module, module_name, accept=lambda x:issubclass(x, cf.base)):
# dct = {}
# for symbol in dir(module):
# if symbol[:2] == '__': continue
# obj = getattr(module, symbol)
# if accept(obj): dct[symbol] = Allocator(obj)
# class Dummy:pass
# self.__dict__[module_name] = Dummy()
# self.__dict__[module_name].__dict__.update(dct)
# def add_from_module(self, module, accept=lambda x:issubclass(x, cf.base)):
# for symbol in dir(module):
# if symbol[:2] == '__': continue
# obj = getattr(module, symbol)
# #print 'considering', symbol, obj
# if accept(obj): self.__dict__[symbol] = Allocator(obj)
# def add_globals_from_module(self, module, accept=lambda x:issubclass(x, cf.base)):
# for symbol in dir(module):
# if symbol[:2] == '__': continue
# obj = getattr(module, symbol)
# #print 'considering', symbol, obj
# if accept(obj):
# if hasattr(globals(), symbol):
# print 'Warning, overwriting global variable: %s' % symbol
# globals()[symbol] = Allocator(obj)
# if __name__=='__main__':
# c = Constructor()
# c.add_module(cf,'cf')
# aa,bb = c.cf.A(), c.cf.B()
# print aa,bb
# c.add_from_module(cf)
# a,b = c.A(), c.B()
# print a,b
# c.add_globals_from_module(cf)
# d,e = A(), B()
# print d,e
...@@ -91,7 +91,8 @@ def ops(i, o): ...@@ -91,7 +91,8 @@ def ops(i, o):
results, orphans = results_and_orphans(i, o) results, orphans = results_and_orphans(i, o)
for r in results: for r in results:
if r not in i and r not in orphans: if r not in i and r not in orphans:
ops.add(r.owner) if r.owner is not None:
ops.add(r.owner)
return ops return ops
......
import utils
from op import Op
__all__ = ['ModalConstructor',
'add_modal_members',
'ModalWrapper',
'BuildMode',
'EvalMode',
'BuildEvalMode',
'make_constructors',
]
class ModalConstructor:
def __init__(self, fn):
self.fn = fn
def __call__(self, *args):
modal_wrapper = None
fn_args = []
for arg in args:
if isinstance(arg, ModalWrapper):
if modal_wrapper is None:
modal_wrapper = arg.__class__
else:
if not isinstance(arg, modal_wrapper):
raise TypeError("Inconsistent modes.")
fn_args.append(arg.r)
else:
fn_args.append(arg)
op = self.fn(*fn_args)
if modal_wrapper:
modal_wrapper.filter(op)
if len(op.outputs) == 1:
return modal_wrapper(op.outputs[0])
else:
return [modal_wrapper(output) for output in op.outputs]
def add_modal_members(cls, *members):
def fn(member):
def ret(self, *args):
constructor = ModalConstructor(getattr(self.r.__class__, member))
return constructor(self, *args)
return ret
for member in members:
setattr(cls, member, fn(member))
class ModalWrapper:
def __init__(self, r):
self.r = r
@classmethod
def filter(cls, op):
raise AbstractFunctionError()
members1 = 'add sub mul div pow floordiv mod pow lshift rshift and or xor'.split(' ')
members = []
members += ["__%s__" % x for x in members1 + 'neg invert'.split(' ')]
members += ["__r%s__" % x for x in members1]
add_modal_members(ModalWrapper, *members)
class BuildMode(ModalWrapper):
@classmethod
def filter(cls, op):
pass
class EvalMode(ModalWrapper):
@classmethod
def filter(cls, op):
op.perform()
for output in op.outputs:
output._role = None
class BuildEvalMode(ModalWrapper):
@classmethod
def filter(cls, op):
op.perform()
def _is_op(x):
try: return issubclass(x, Op)
except: return False
def make_constructors(source,
dest = None,
name_filter = utils.camelcase_to_separated,
candidate_filter = _is_op):
if dest is None:
dest = source
for symbol, value in source.items():
if candidate_filter(value):
dest[name_filter(symbol)] = ModalConstructor(value)
return dest
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# import op # import op
# import result # import result
import re
class OmegaError(Exception): pass class OmegaError(Exception): pass
...@@ -42,8 +44,21 @@ def all_bases_collect(cls, raw_name): ...@@ -42,8 +44,21 @@ def all_bases_collect(cls, raw_name):
return rval return rval
def camelcase_to_separated(string, sep = "_"):
return re.sub('(.)([A-Z])', '\\1%s\\2' % sep, string).lower()
def to_return_values(values):
if len(values) == 1:
return values[0]
else:
return values
def from_return_values(values):
if isinstance(values, (list, tuple)):
return values
else:
return [values]
def partial(func, *args, **keywords): def partial(func, *args, **keywords):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论