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
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 iteritems(sets): 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 iteritems(incs): for inc_op in inc_ops: if inc_op not in done: rval.append(inc_op) return rval
def __init__(self, source, globals_dict, closure_dict, in_dims=None, out_dim=None): self.source = source self.globals = globals_dict self.closures = closure_dict # self.init: key=local variable name, value=initialization statement self.init = OrderedDict() self.temp_names = OrderedDict() # for comprehensions # parse and make code a = ast.parse(source) ff = Function_Finder() ff.visit(a) function_def = ff.fn_node try: self.arg_names = [arg.id for arg in function_def.args.args] except AttributeError: self.arg_names = [arg.arg for arg in function_def.args.args] if in_dims is None: in_dims = [None] * len(self.arg_names) self.arg_dims = in_dims self.out_dim = out_dim assert len(self.arg_names) == len(self.arg_dims) if isinstance(function_def, ast.FunctionDef): self.function_name = function_def.name self.body = self.visit_block(function_def.body) elif isinstance(function_def, ast.Lambda): if hasattr(function_def, 'targets'): self.function_name = function_def.targets[0].id else: self.function_name = "<lambda>" # wrap lambda expression to look like a one-line function r = ast.Return() r.value = function_def.body r.lineno = 1 r.col_offset = 4 self.body = self.visit_block([r]) else: raise ValueError( "Expected function definition or lambda function assignment, " "got " + str(type(function_def)))
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)
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 piecewise(data): """Create a piecewise constant function from a dictionary. Given an input of data={0: 0, 0.5: 1, 0.75: -1, 1: 0} this will generate a function that returns 0 up until t=0.5, then outputs a 1 until t=0.75, then a -1 until t=1, and then returns 0 after that. This is meant as a shortcut for:: def function(t): if t < 0.5: return 0 elif t < 0.75 return 1 elif t < 1: return -1 else: return 0 The keys in the dictionary must be times (floats or ints). The values in the data dictionary can be floats, lists, or functions that return floats or lists. All lists must be of the same length. For times before the first specified time, it will default to zero (of the correct length). This means the above example can be simplified to:: piecewise({0.5: 1, 0.75: -1, 1: 0}) Parameters ---------- data : dict The values to change to. Keys are the beginning time for the value. Values can be int, float, list, or functions that return those. Returns ------- function: A function that takes a variable t and returns the corresponding value from the dictionary. Examples -------- >>> func = piecewise({0.5: 1, 0.75: -1, 1: 0}) >>> func(0.2) [0] >>> func(0.58) [1] >>> func = piecewise({0.5: [1, 0], 0.75: [0, 1]}) >>> func(0.2) [0,0] >>> func(0.58) [1,0] >>> func(100) [0,1] >>> import math >>> func = piecewise({0: math.sin, 0.5: math.cos}) >>> func(0.499) [0.47854771647582706] >>> func(0.5) [0.8775825618903728] """ # first, sort the data (to simplify finding the right element # when calling the function) output_length = None # the dimensionality of the returned values for time in data: if not is_number(time): raise TypeError('Keys must be times (floats or ints), not "%s"' % repr(time.__class__)) # figure out the length of this item if callable(data[time]): length = np.asarray(data[time](0.0)).size else: data[time] = np.asarray(data[time]) length = data[time].size # make sure this is the same length as previous items if length != output_length and output_length is not None: raise ValueError('Invalid data for piecewise function: ' 'time %4g has %d items instead of %d' % (time, length, output_length)) output_length = length # make a default output of 0 when t before what was passed data[np.finfo(float).min] = np.zeros(output_length) ordered_data = OrderedDict(sorted(iteritems(data))) # build the function to return def piecewise_function(t, data=ordered_data): # get the t we'll use for output for time in (time for time in data if time <= t): out_t = time # if it's a function, call it if callable(data[out_t]): return np.asarray(data[out_t](t)) return data[out_t] return piecewise_function
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 get_closures(f): return OrderedDict( zip(f.__code__.co_freevars, (c.cell_contents for c in f.__closure__)))
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