moving from specs to refresh, passing tests in compile.py

上级 b747a0cb
...@@ -18,6 +18,7 @@ def experimental_linker(env, target = None): ...@@ -18,6 +18,7 @@ def experimental_linker(env, target = None):
py_ops = set() py_ops = set()
thunks = [] thunks = []
computed_results = []
for op in order: for op in order:
try: try:
...@@ -34,6 +35,7 @@ def experimental_linker(env, target = None): ...@@ -34,6 +35,7 @@ def experimental_linker(env, target = None):
result = op._perform result = op._perform
py_ops.add(op) py_ops.add(op)
thunks.append((result, op._perform_inplace)) thunks.append((result, op._perform_inplace))
computed_results.extend(op.outputs)
def ret(): def ret():
for thunk, fallback in thunks: for thunk, fallback in thunks:
...@@ -41,6 +43,8 @@ def experimental_linker(env, target = None): ...@@ -41,6 +43,8 @@ def experimental_linker(env, target = None):
thunk() thunk()
except NotImplementedError: except NotImplementedError:
fallback() fallback()
for r in computed_results:
r.state = gof.result.Computed
if not target: if not target:
return ret return ret
...@@ -48,38 +52,6 @@ def experimental_linker(env, target = None): ...@@ -48,38 +52,6 @@ def experimental_linker(env, target = None):
raise NotImplementedError("Cannot write thunk representation to a file.") raise NotImplementedError("Cannot write thunk representation to a file.")
# def experimental_linker(env, target = None):
# def fetch(op):
# try:
# factory = op.c_thunk_factory()
# # print "yea %s" % op
# thunk = factory()
# return lambda: cutils.run_cthunk(thunk)
# except NotImplementedError:
# # print "nope %s" % op
# return op._perform
# order = env.toposort()
# for op in order:
# op.refresh()
# # for op in order:
# # print op
# # print 'ispecs: ', [input.spec for input in op.inputs]
# # print 'ospecs: ', [output.spec for output in op.outputs]
# thunks = [fetch(op) for op in order]
# def ret():
# # print "=================================================="
# # for thunk, op in zip(thunks, order):
# # print op
# # print 'in: ', [id(input.data) for input in op.inputs]
# # print 'out:', [id(output.data) for output in op.outputs]
# # thunk()
# for thunk in thunks:
# thunk()
# if not target:
# return ret
# else:
# raise NotImplementedError("Cannot write thunk representation to a file.")
class profile_linker: class profile_linker:
def __init__(self, env): def __init__(self, env):
self.order = env.toposort() self.order = env.toposort()
...@@ -201,10 +173,9 @@ def to_func(inputs, outputs): ...@@ -201,10 +173,9 @@ def to_func(inputs, outputs):
def single(*outputs, **kwargs): def single(*outputs, **kwargs):
return prog(gof.graph.inputs(outputs), outputs, **kwargs) return prog(gof.graph.inputs(outputs), outputs, **kwargs)
class _test_single_build_mode(unittest.TestCase):
class _test_single(unittest.TestCase):
def setUp(self): def setUp(self):
core.build_eval_mode() core.build_mode()
numpy.random.seed(44) numpy.random.seed(44)
def tearDown(self): def tearDown(self):
core.pop_mode() core.pop_mode()
...@@ -215,27 +186,44 @@ class _test_single(unittest.TestCase): ...@@ -215,27 +186,44 @@ class _test_single(unittest.TestCase):
c = core.add(a,b) c = core.add(a,b)
self.failUnless(c.data is None) self.failUnless(c.data is None)
self.failUnless(c.state is Empty) self.failUnless(c.state is gof.result.Empty)
p = single(c)
self.failUnless(c.data is not None)
self.failUnless(c.state is gof.result.Allocated)
self.failUnless(not core._approx_eq(c, a.data + b.data))
p()
self.failUnless(c.state is gof.result.Computed)
self.failUnless(core._approx_eq(c, a.data + b.data))
new_a = numpy.random.rand(2,2) new_a = numpy.random.rand(2,2)
new_b = numpy.random.rand(2,2) new_b = numpy.random.rand(2,2)
a.data = new_a a.data[:] = new_a
b.data = new_b b.data[:] = new_b
p = single(c)
p() p()
self.failUnless(core._approx_eq(c, new_a + new_b)) self.failUnless(core._approx_eq(c, new_a + new_b))
def test_get_element(self): def test_get_element(self):
core.build_eval_mode()
a_data = numpy.random.rand(2,2) a_data = numpy.random.rand(2,2)
a = core.Numpy2(data=a_data) a = core.Numpy2(data=a_data)
a_i = a[0,0] pos = core.input((0,0))
a_i = core.get_slice(a, pos)
p = single(a_i) p = single(a_i)
#p()
#print 'aaaa', a_i.owner.out, a_i.owner, a_i.data, pos.data
#print 'pre p()'
for i in 0,1: for i in 0,1:
for j in 0,1: for j in 0,1:
pos.data = (i,j)
p() p()
#print 'asdf', i,j,a_i.data
#print a_i.owner.inputs[1].data
#a_i.owner.inputs[1].data = [i,j]
self.failUnless(a_data[i,j] == a_i.data) self.failUnless(a_data[i,j] == a_i.data)
core.pop_mode()
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -86,12 +86,13 @@ def _compile_dir(): ...@@ -86,12 +86,13 @@ def _compile_dir():
class Numpy2(ResultBase): class Numpy2(ResultBase):
"""Result storing a numpy ndarray""" """Result storing a numpy ndarray"""
__slots__ = ['_dtype', '_shape', ] __slots__ = ['_dtype', '_shape', '_order']
class ShapeUnknown: pass # TODO: use this as the shape of uncomputed ndarrays of unknown shape class ShapeUnknown: pass # TODO: use this as the shape of uncomputed ndarrays of unknown shape
class StateError(Exception): pass class StateError(Exception): pass
def __init__(self, role=None, data=None, constant=False): def __init__(self, role=None, data=None, constant=False):
self._order = 'C'
if isinstance(data, (tuple, list)): # unallocated setup if isinstance(data, (tuple, list)): # unallocated setup
shape, dtype = data shape, dtype = data
ResultBase.__init__(self, role, data=None, constant=constant) ResultBase.__init__(self, role, data=None, constant=constant)
...@@ -104,30 +105,23 @@ class Numpy2(ResultBase): ...@@ -104,30 +105,23 @@ class Numpy2(ResultBase):
# ResultBase # ResultBase
# #
def data_filter(self, data): def data_filter(self, data):
#TODO: decide which of these implementations is better return numpy.asarray(data)
if 0:
if isinstance(data, numpy.ndarray):
return data
raise TypeError('failed to filter data to ndarray', data)
else:
return numpy.asarray(data)
################################ ################################
# Numpy2 specific functionality # Numpy2 specific functionality
# #
__array__ = property(lambda self: self.data.__array__ ) __array__ = property(lambda self: self.data.__array__)
__array_struct__ = property(lambda self: self.data.__array_struct__ ) __array_struct__ = property(lambda self: self.data.__array_struct__)
def data_alloc(self): def data_alloc(self):
return numpy.ndarray(self.shape, self.dtype) return numpy.ndarray(shape=self.shape, dtype=self.dtype, order=self._order)
# self._dtype is used when self.data hasn't been set yet # self._dtype is used when self.data hasn't been set yet
def __dtype_get(self): def __dtype_get(self):
if self.data is None: if self.data is not None:
return self._dtype self._dtype = self.data.dtype
else: return self._dtype
return self.data.dtype
def __dtype_set(self, dtype): def __dtype_set(self, dtype):
if self.data is None: if self.data is None:
self._dtype = dtype self._dtype = dtype
...@@ -137,10 +131,9 @@ class Numpy2(ResultBase): ...@@ -137,10 +131,9 @@ class Numpy2(ResultBase):
# self._shape is used when self.data hasn't been set yet # self._shape is used when self.data hasn't been set yet
def __shape_get(self): def __shape_get(self):
if self.data is None: if self.data is not None:
return self._shape self._shape = self.data.shape
else: return self._shape
return self.data.shape
def __shape_set(self, shape): def __shape_set(self, shape):
if self.data is None: if self.data is None:
self._shape = shape self._shape = shape
...@@ -187,6 +180,7 @@ class Numpy2(ResultBase): ...@@ -187,6 +180,7 @@ class Numpy2(ResultBase):
self.data.itemset(value) # for scalars self.data.itemset(value) # for scalars
else: else:
self.data[:] = value # for matrices self.data[:] = value # for matrices
self.state = gof.result.Computed
class _test_Numpy2(unittest.TestCase): class _test_Numpy2(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -355,6 +349,7 @@ def cgen(name, behavior, names, vals, converters = None): ...@@ -355,6 +349,7 @@ def cgen(name, behavior, names, vals, converters = None):
def cgetspecs(names, vals, converters): def cgetspecs(names, vals, converters):
d = {} d = {}
assert len(names) == len(vals)
for name, value in zip(names, vals): for name, value in zip(names, vals):
d[name] = value.data d[name] = value.data
specs = weave.ext_tools.assign_variable_types(names, d, type_converters = converters) #, auto_downcast = 0) specs = weave.ext_tools.assign_variable_types(names, d, type_converters = converters) #, auto_downcast = 0)
...@@ -365,6 +360,7 @@ def cgen(name, behavior, names, vals, converters = None): ...@@ -365,6 +360,7 @@ def cgen(name, behavior, names, vals, converters = None):
for converter in converters: for converter in converters:
assert isinstance(converter, type_spec.omega_type_converter_extension) assert isinstance(converter, type_spec.omega_type_converter_extension)
d, specs = cgetspecs(names, vals, converters) d, specs = cgetspecs(names, vals, converters)
template = {} template = {}
...@@ -420,22 +416,38 @@ def cgen(name, behavior, names, vals, converters = None): ...@@ -420,22 +416,38 @@ def cgen(name, behavior, names, vals, converters = None):
return d, names, code, struct + static, converters return d, names, code, struct + static, converters
class omega_op(gof.PythonOp): class Numpy2Op(gof.lib.PythonOp):
"""What can we do given we are interacting with Numpy2 inputs and outputs"""
def refresh(self, alloc = True):
shape = self.refresh_shape()
dtype = self.refresh_dtype()
out = self.out
if out.data is not None \
and out.shape == shape \
and out.dtype == dtype:
return
alloc |= out.data is not None
if alloc: out.data = None
out.shape = shape
out.dtype = dtype
if alloc: out.alloc()
class omega_op(Numpy2Op):
forbid_broadcast = False forbid_broadcast = False
@staticmethod @staticmethod
def __clsinit__(cls, name, bases, dct): def __clsinit__(cls, name, bases, dct):
for fname in ['grad', 'c_impl']: for fname in ['grad', 'c_impl', 'impl']:
if hasattr(cls, fname): if hasattr(cls, fname):
gof.make_static(cls, fname) gof.make_static(cls, fname)
# make impl a static method
gof.PythonOp.__clsinit__(cls, name, bases, dct)
def __new__(cls, *inputs): def __new__(cls, *inputs):
inputs = [wrap(input) for input in inputs] inputs = [wrap(input) for input in inputs]
return gof.PythonOp.__new__(cls, *inputs) return Numpy2Op.__new__(cls, *inputs)
def gen_outputs(self): def gen_outputs(self):
return [Numpy2() for i in xrange(self.nout)] return [Numpy2() for i in xrange(self.nout)]
...@@ -662,7 +674,7 @@ class elemwise(omega_op): ...@@ -662,7 +674,7 @@ class elemwise(omega_op):
# make impl, grad, etc. static methods # make impl, grad, etc. static methods
omega_op.__clsinit__(cls, name, bases, dct) omega_op.__clsinit__(cls, name, bases, dct)
def _specs(self): def TOGO_specs(self):
try: try:
return self.specs(*[input.spec for input in self.inputs]) return self.specs(*[input.spec for input in self.inputs])
except NotImplementedError: except NotImplementedError:
...@@ -706,14 +718,55 @@ class elemwise(omega_op): ...@@ -706,14 +718,55 @@ class elemwise(omega_op):
else: else:
return res return res
def alloc(self, except_list = []): def TOGO_alloc(self, except_list = []):
dmap = self.destroy_map() dmap = self.destroy_map()
vmap = self.view_map()
gof.PythonOp.alloc(self, except_list = except_list + dmap.keys()) gof.PythonOp.alloc(self, except_list = except_list + dmap.keys())
for output, (input, ) in dmap.items(): for output, (input, ) in dmap.items():
if output not in except_list: if output not in except_list:
output.set_value(input.data) output.set_value(input.data)
def refresh_shape(self):
"""Make the output have the right stuff"""
if len(self.outputs) > 1:
raise NotImplementedError('multiple outputs')
dmap = self.destroy_map()
vmap = self.view_map()
if dmap != {} or vmap != {}:
raise NotImplementedError('destroys or views confuse things',
self.__class__, dmap, vmap)
# take the shape of the leftmost loop_variable input
inames, onames = self.variable_names()
linames, lonames = self.loop_variables()
unknown_output_names = [n for n in onames if n not in lonames]
if len(unknown_output_names):
raise Exception("cannot infer a specification automatically for variables " \
"%s.{%s} because it is not part of the elementwise loop - "\
"please override the specs method" %
(self.__class__.__name__, str(unknown_output_names)))
# shape is leftmost loop-variable input
input_loop_shapes = [i.shape for n,i in zip(inames, self.inputs) if n in linames]
if len(input_loop_shapes) == 0:
raise Exception("cannot infer a specification automatically for output variables " \
"because there is no input loop variable ")
for i in xrange(1,len(input_loop_shapes)):
if input_loop_shapes[i] != input_loop_shapes[0]:
raise Exception("Input loop variables have different shapes", self.__class__)
return input_loop_shapes[0]
def refresh_dtype(self):
return upcast(*[i.dtype for i in self.inputs if hasattr(i, 'dtype')])
@classmethod
def set_impl(cls, impl):
gof.lib.make_static(cls, 'impl')
@staticmethod @staticmethod
def is_loop_var(name): def is_loop_var(name):
return name.endswith("_i") return name.endswith("_i")
...@@ -1134,9 +1187,22 @@ class dot(omega_op): ...@@ -1134,9 +1187,22 @@ class dot(omega_op):
impl = numpy.dot impl = numpy.dot
def grad(x, y, gz): def grad(x, y, gz):
return dot(gz, transpose(y)), dot(transpose(x), gz) return dot(gz, transpose(y)), dot(transpose(x), gz)
def specs(x, y): def refresh(self, alloc=False):
shape = dot._output_shape(x[2], y[2]) x,y = self.inputs
return (numpy.ndarray, upcast(x[1], y[1]), shape) shape = self._output_shape(x.shape, y.shape)
dtype = upcast(x.dtype, y.dtype)
if self.out.data is not None \
and self.out.shape == shape \
and self.out.dtype == dtype:
return #everything is ok
if alloc or self.out.data is not None: #data should be allocated
self.out.data = None
self.out.shape = shape
self.out.dtype = dtype
self.out.alloc()
else:
self.out.shape = shape
self.out.dtype = dtype
def c_support_code(self): def c_support_code(self):
return blas.cblas_header_text() return blas.cblas_header_text()
def c_libs(self): def c_libs(self):
...@@ -1297,8 +1363,8 @@ class _testCase_dot(unittest.TestCase): ...@@ -1297,8 +1363,8 @@ class _testCase_dot(unittest.TestCase):
self.fail() self.fail()
class gemm(omega_op): class gemm(omega_op):
def destroy_map(self): return {self.out:[self.inputs[0]]} def destroy_map(self):
return {self.out:[self.inputs[0]]}
def impl(z, a, x, y, b): def impl(z, a, x, y, b):
if b == 0.0: if b == 0.0:
if a == 1.0: if a == 1.0:
...@@ -1318,15 +1384,14 @@ class gemm(omega_op): ...@@ -1318,15 +1384,14 @@ class gemm(omega_op):
z *= b z *= b
z += a * numpy.dot(x,y) z += a * numpy.dot(x,y)
return z[:] return z[:]
def grad(z, a, x, y, b, gz): def grad(z, a, x, y, b, gz):
raise NotImplemented raise NotImplemented
def refresh(self, alloc = False):
def specs(z, a, x, y, b): z,a,x,y,b = self.inputs
assert z[2] == dot._output_shape(x[2], y[2]) self.out.shape = z.shape
return z self.out.dtype = z.dtype
def alloc(self, except_list): if alloc:
self.outputs[0].data = self.inputs[0].data self.out.data = z.data
def c_support_code(self): def c_support_code(self):
return blas.cblas_header_text() return blas.cblas_header_text()
def c_libs(self): def c_libs(self):
...@@ -1355,9 +1420,12 @@ class transpose(omega_op): ...@@ -1355,9 +1420,12 @@ class transpose(omega_op):
impl = numpy.transpose impl = numpy.transpose
def grad(x, gz): def grad(x, gz):
return transpose_copy(gz) return transpose_copy(gz)
def specs(x): def refresh_shape(self):
# todo: handle all tensors! rval = list(self.inputs[0].shape)
return (numpy.ndarray, x[1], (x[2][1], x[2][0])) rval.reverse()
return rval
def refresh_dtype(self):
return self.inputs[0].dtype
def c_impl((x, ), (xt, )): def c_impl((x, ), (xt, )):
return """ return """
const int l = x->nd; const int l = x->nd;
...@@ -1635,8 +1703,8 @@ class sum(elemwise): ...@@ -1635,8 +1703,8 @@ class sum(elemwise):
impl = numpy.sum impl = numpy.sum
def grad(x, gz): def grad(x, gz):
return fill(x, gz) return fill(x, gz)
def specs(x): def refresh_shape(self):
return (numpy.ndarray, x[1], ()) return ()
def c_init((x, ), (sum, )): def c_init((x, ), (sum, )):
return "sum_dtype* sump = ((sum_dtype*)PyArray_DATA(sum)); sump[0] = 0;" return "sum_dtype* sump = ((sum_dtype*)PyArray_DATA(sum)); sump[0] = 0;"
def c_foreach((x_i, ), (sum, )): def c_foreach((x_i, ), (sum, )):
...@@ -1654,8 +1722,18 @@ class zeros_like(elemwise): ...@@ -1654,8 +1722,18 @@ class zeros_like(elemwise):
class get_slice(omega_op): class get_slice(omega_op):
def view_map(self): return {self.out: [self.inputs[0]]} def view_map(self): return {self.out: [self.inputs[0]]}
def impl(x, item): return x.__getitem__(item) def impl(x, item):
rval = x.__getitem__(item)
#print 'get_slice running', rval
return rval
def grad(x, gz): raise NotImplemented def grad(x, gz): raise NotImplemented
def refresh_shape(self):
x,item = self.inputs
rval = x.data.__getitem__(item.data).shape
#print 'refresh_shape', rval
return rval
def refresh_dtype(self):
return self.inputs[0].data.dtype
class _testCase_slicing(unittest.TestCase): class _testCase_slicing(unittest.TestCase):
def setUp(self): def setUp(self):
......
...@@ -350,7 +350,7 @@ class DestroyHandler(features.Listener, features.Constraint, features.Orderings) ...@@ -350,7 +350,7 @@ class DestroyHandler(features.Listener, features.Constraint, features.Orderings)
class NewPythonOp(Op): class NewPythonOp(Op):
__env_require__ = DestroyHandler __env_require__ = DestroyHandler, ForbidConstantOverwrite
def view_map(self): def view_map(self):
return {} return {}
...@@ -358,7 +358,6 @@ class NewPythonOp(Op): ...@@ -358,7 +358,6 @@ class NewPythonOp(Op):
def destroy_map(self): def destroy_map(self):
return {} return {}
class PythonOp(NewPythonOp): class PythonOp(NewPythonOp):
__metaclass__ = ClsInit __metaclass__ = ClsInit
...@@ -369,10 +368,9 @@ class PythonOp(NewPythonOp): ...@@ -369,10 +368,9 @@ class PythonOp(NewPythonOp):
def __clsinit__(cls, name, bases, dct): def __clsinit__(cls, name, bases, dct):
# make impl a static method # make impl a static method
cls.set_impl(cls.impl) cls.set_impl(cls.impl)
make_static(cls, 'specs')
def __new__(cls, *inputs, **kwargs): def __new__(cls, *inputs, **kwargs):
op = Op.__new__(cls) op = NewPythonOp.__new__(cls)
op.__init__(*inputs) op.__init__(*inputs)
mode = kwargs.get('mode', None) or current_mode() mode = kwargs.get('mode', None) or current_mode()
if mode == 'eval': if mode == 'eval':
...@@ -471,40 +469,6 @@ class PythonOp(NewPythonOp): ...@@ -471,40 +469,6 @@ class PythonOp(NewPythonOp):
def impl(*args): def impl(*args):
raise NotImplementedError("This op has no implementation.") raise NotImplementedError("This op has no implementation.")
def _specs(self):
try:
return self.specs(*[input.spec for input in self.inputs])
except NotImplementedError:
raise NotImplementedError("%s cannot infer the specs of its outputs" % self.__class__.__name__)
def specs(*inputs):
raise NotImplementedError
def refresh(self, except_list = []):
for input in self.inputs:
input.refresh()
change = self._propagate_specs()
if change:
self.alloc(except_list)
return change
def _propagate_specs(self):
specs = self._specs()
if self.nout == 1:
specs = [specs]
change = False
for output, spec in zip(self.outputs, specs):
if output.spec != spec:
output.spec = spec
change = True
return change
def alloc(self, except_list = []):
for output in self.outputs:
if output not in except_list:
output.alloc()
__env_require__ = ForbidConstantOverwrite
def __copy__(self): def __copy__(self):
""" """
...@@ -577,3 +541,41 @@ class DummyOp(NewPythonOp): ...@@ -577,3 +541,41 @@ class DummyOp(NewPythonOp):
DummyRemover = opt.OpRemover(DummyOp) DummyRemover = opt.OpRemover(DummyOp)
if 0:
class RefreshableOp(NewPythonOp):
def _specs(self):
try:
return self.specs(*[input.spec for input in self.inputs])
except NotImplementedError:
raise NotImplementedError("%s cannot infer the specs of its outputs" % self.__class__.__name__)
def specs(*inputs):
raise NotImplementedError
def refresh(self):
"""Update and allocate outputs if necessary"""
for input in self.inputs:
input.refresh()
change = self._propagate_specs()
if change:
self.alloc(except_list)
return change
def _propagate_specs(self):
specs = self._specs()
if self.nout == 1:
specs = [specs]
change = False
for output, spec in zip(self.outputs, specs):
if output.spec != spec:
output.spec = spec
change = True
return change
def alloc(self, except_list = []):
for output in self.outputs:
if output not in except_list:
output.alloc()
...@@ -93,11 +93,11 @@ class ResultBase(object): ...@@ -93,11 +93,11 @@ class ResultBase(object):
def __init__(self, role): self.old_role = role def __init__(self, role): self.old_role = role
def __nonzero__(self): return False def __nonzero__(self): return False
class BrokenLinkError(Exception): class BrokenLinkError(Exception):
"""Exception thrown when an owner is a BrokenLink""" """The owner is a BrokenLink"""
class AbstractFunction(Exception): class StateError(Exception):
"""Exception thrown when an abstract function is called""" """The state of the Result is a problem"""
__slots__ = ['_role', 'constant', '_data', 'state'] __slots__ = ['_role', 'constant', '_data', 'state']
...@@ -111,7 +111,7 @@ class ResultBase(object): ...@@ -111,7 +111,7 @@ class ResultBase(object):
else: else:
try: try:
self._data[0] = self.data_filter(data) self._data[0] = self.data_filter(data)
except ResultBase.AbstractFunction: except AbstractFunctionError:
self._data[0] = data self._data[0] = data
self.state = Computed self.state = Computed
...@@ -175,10 +175,13 @@ class ResultBase(object): ...@@ -175,10 +175,13 @@ class ResultBase(object):
self._data[0] = None self._data[0] = None
self.state = Empty self.state = Empty
return return
if data is self or data is self._data[0]: return
try: try:
self._data[0] = self.data_filter(data) self._data[0] = self.data_filter(data)
except ResultBase.AbstractFunction: #use default behaviour except AbstractFunctionError: #use default behaviour
self._data[0] = data self._data[0] = data
if isinstance(data, ResultBase):
raise Exception()
self.state = Computed self.state = Computed
data = property(__get_data, __set_data, data = property(__get_data, __set_data,
...@@ -193,14 +196,19 @@ class ResultBase(object): ...@@ -193,14 +196,19 @@ class ResultBase(object):
the contents of self._data remain sensible. the contents of self._data remain sensible.
""" """
raise ResultBase.AbstractFunction() raise AbstractFunctionError()
# #
# alloc # alloc
# #
def alloc(self): def alloc(self):
"""Create self.data from data_alloc, and set state to Allocated""" """Create self.data from data_alloc, and set state to Allocated
Graph routines like the linker will ask Ops to allocate outputs. The
Ops, in turn, usually call this function. Results that are involved in
destroy maps and view maps are exceptions to the usual case.
"""
self.data = self.data_alloc() #might raise exception self.data = self.data_alloc() #might raise exception
self.state = Allocated self.state = Allocated
...@@ -211,7 +219,7 @@ class ResultBase(object): ...@@ -211,7 +219,7 @@ class ResultBase(object):
implementation will be used in alloc() to produce a data object. implementation will be used in alloc() to produce a data object.
""" """
raise ResultBase.AbstractFunction() raise AbstractFunctionError()
# #
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论