def compress(cls, operators): sets = OrderedDict() incs = OrderedDict() rval = [] for op in operators: if isinstance(op, cls): if op.as_update: rval.append(op) else: assert op.sets or op.incs if op.sets: sets.setdefault(op.sets[0], []).append(op) if op.incs: incs.setdefault(op.incs[0], []).append(op) else: rval.append(op) done = set() for view, set_ops in sets.items(): set_op, = set_ops done.add(set_op) for inc_op in incs.get(view, []): set_op.As.extend(inc_op.As) set_op.Xs.extend(inc_op.Xs) done.add(inc_op) rval.append(set_op) for view, inc_ops in incs.items(): for inc_op in inc_ops: if inc_op not in done: rval.append(inc_op) return rval
class Effect(object): """Parses an Action effect given a set of module outputs. Parameters ---------- sources : list of string The names of valid sources of information (SPA module outputs) sinks : list of string The names of valid places to send information (SPA module inputs) effect: string The action to implement. This is a set of assignment statements which can be parsed into a VectorList. The following are valid effects: "motor=A" "motor=A*B, memory=vision+DOG" "motor=0.5*(memory*A + vision*B)" """ def __init__(self, sources, sinks, effect): self.effect = OrderedDict() # Splits by ',' and separates into lvalue=rvalue. We cannot simply use # split, because the rvalue may contain commas in the case of dot(*,*). # However, *? is lazy, and * is greedy, making this regex work. for lvalue, rvalue in re.findall("(.*?)=([^=]*)(?:,|$)", effect): sink = lvalue.strip() if sink not in sinks: raise NameError("Left-hand module '%s' from effect '%s=%s' " "is not defined." % (lvalue, lvalue, rvalue)) if sink in self.effect: raise ValueError("Left-hand module '%s' from effect '%s=%s' " "is assigned to multiple times in '%s'." % (lvalue, lvalue, rvalue, effect)) self.effect[sink] = Expression(sources, rvalue) def __str__(self): return ", ".join("%s=%s" % x for x in self.effect.items())
def plan_SimPyFunc(self, ops): # TODO: test with a hybrid program (Python and OCL) # group nonlinearities unique_ops = OrderedDict() for op in ops: # assert op.n_args in (1, 2), op.n_args op_key = (op.fn, op.t_in, op.x is not None) if op_key not in unique_ops: unique_ops[op_key] = {'in': [], 'out': []} unique_ops[op_key]['in'].append(op.x) unique_ops[op_key]['out'].append(op.output) # make plans plans = [] for (fn, t_in, x_in), signals in unique_ops.items(): fn_name = (fn.__name__ if inspect.isfunction(fn) else fn.__class__.__name__) if fn_name == "<lambda>": fn_name += "%d" % len(plans) # check signal input and output shape (implicitly checks # for indexing errors) vector_dims = lambda shape, dim: len( shape) == 1 and shape[0] == dim unit_stride = lambda es: len(es) == 1 and es[0] == 1 if x_in: in_dim = signals['in'][0].size for sig_in in signals['in']: assert sig_in.size == in_dim assert vector_dims(sig_in.shape, in_dim) assert unit_stride(sig_in.elemstrides) else: in_dim = None # if any functions have no output, must do them in Python if any(s is None for s in signals['out']): assert all(s is None for s in signals['out']) warnings.warn( "Function '%s' could not be converted to OCL since it has " "no outputs." % (fn_name), RuntimeWarning) plans.append(self._plan_pythonfn( fn, t_in, signals, fn_name=fn_name)) continue out_dim = signals['out'][0].size for sig_out in signals['out']: assert sig_out.size == out_dim assert vector_dims(sig_out.shape, out_dim) assert unit_stride(sig_out.elemstrides) # try to get OCL code try: in_dims = [1] if t_in else [] in_dims += [in_dim] if x_in else [] ocl_fn = OCL_Function(fn, in_dims=in_dims, out_dim=out_dim) input_names = ocl_fn.translator.arg_names inputs = [] if t_in: # append time inputs.append(self.all_data[ [self.sidx[self._time] for i in signals['out']]]) if x_in: # append x inputs.append(self.all_data[ [self.sidx[i] for i in signals['in']]]) output = self.all_data[[self.sidx[i] for i in signals['out']]] plan = plan_direct(self.queue, ocl_fn.code, ocl_fn.init, input_names, inputs, output, tag=fn_name) plans.append(plan) except Exception as e: if self.ocl_only: raise warnings.warn( "Function '%s' could not be converted to OCL due to %s%s" % (fn_name, e.__class__.__name__, e.args), RuntimeWarning) # not successfully translated to OCL, so do it in Python plans.append(self._plan_pythonfn( fn, t_in, signals, fn_name=fn_name)) return plans
def plan_SimPyFunc(self, ops): # TODO: test with a hybrid program (Python and OCL) # group nonlinearities unique_ops = OrderedDict() for op in ops: # assert op.n_args in (1, 2), op.n_args op_key = (op.fn, op.t_in, op.x is not None) if op_key not in unique_ops: unique_ops[op_key] = {'in': [], 'out': []} unique_ops[op_key]['in'].append(op.x) unique_ops[op_key]['out'].append(op.output) # make plans plans = [] for (fn, t_in, x_in), signals in unique_ops.items(): fn_name = (fn.__name__ if inspect.isfunction(fn) else fn.__class__.__name__) if fn_name == "<lambda>": fn_name += "%d" % len(plans) # check signal input and output shape (implicitly checks # for indexing errors) vector_dims = lambda shape, dim: len(shape) == 1 and shape[0 ] == dim unit_stride = lambda es: len(es) == 1 and es[0] == 1 if x_in: in_dim = signals['in'][0].size for sig_in in signals['in']: assert sig_in.size == in_dim assert vector_dims(sig_in.shape, in_dim) assert unit_stride(sig_in.elemstrides) else: in_dim = None # if any functions have no output, must do them in Python if any(s is None for s in signals['out']): assert all(s is None for s in signals['out']) warnings.warn( "Function '%s' could not be converted to OCL since it has " "no outputs." % (fn_name), RuntimeWarning) plans.append( self._plan_pythonfn(fn, t_in, signals, fn_name=fn_name)) continue out_dim = signals['out'][0].size for sig_out in signals['out']: assert sig_out.size == out_dim assert vector_dims(sig_out.shape, out_dim) assert unit_stride(sig_out.elemstrides) # try to get OCL code try: in_dims = [1] if t_in else [] in_dims += [in_dim] if x_in else [] ocl_fn = OCL_Function(fn, in_dims=in_dims, out_dim=out_dim) input_names = ocl_fn.translator.arg_names inputs = [] if t_in: # append time inputs.append(self.all_data[[ self.sidx[self._time] for i in signals['out'] ]]) if x_in: # append x inputs.append( self.all_data[[self.sidx[i] for i in signals['in']]]) output = self.all_data[[self.sidx[i] for i in signals['out']]] plan = plan_direct(self.queue, ocl_fn.code, ocl_fn.init, input_names, inputs, output, tag=fn_name) plans.append(plan) except Exception as e: if self.ocl_only: raise warnings.warn( "Function '%s' could not be converted to OCL due to %s%s" % (fn_name, e.__class__.__name__, e.args), RuntimeWarning) # not successfully translated to OCL, so do it in Python plans.append( self._plan_pythonfn(fn, t_in, signals, fn_name=fn_name)) return plans