def build_node(self, node): # Get input if node.output is None or is_callable(node.output): if node.size_in > 0: self.model.sig_in[node] = Signal( np.zeros(node.size_in), name="%s.signal" % node.label) # Reset input signal to 0 each timestep self.model.operators.append(Reset(self.model.sig_in[node])) # Provide output if node.output is None: self.model.sig_out[node] = self.model.sig_in[node] elif not is_callable(node.output): self.model.sig_out[node] = Signal(node.output, name=node.label) else: sig_in, sig_out = self.build_pyfunc(fn=node.output, t_in=True, n_in=node.size_in, n_out=node.size_out, label="%s.pyfn" % node.label) if sig_in is not None: self.model.operators.append(DotInc( self.model.sig_in[node], Signal(1.0, name="1"), sig_in, tag="%s input" % node.label)) if sig_out is not None: self.model.sig_out[node] = sig_out for probe in node.probes["output"]: self.build(probe, dimensions=self.model.sig_out[node].shape)
def build_node(node, model): # Get input if node.output is None or is_callable(node.output): if node.size_in > 0: model.sig_in[node] = Signal(np.zeros(node.size_in), name="%s.signal" % node.label) # Reset input signal to 0 each timestep model.operators.append(Reset(model.sig_in[node])) # Provide output if node.output is None: model.sig_out[node] = model.sig_in[node] elif not is_callable(node.output): model.sig_out[node] = Signal(node.output, name=node.label) else: sig_in, sig_out = build_pyfunc(fn=node.output, t_in=True, n_in=node.size_in, n_out=node.size_out, label="%s.pyfn" % node.label, model=model) if sig_in is not None: model.operators.append( DotInc(model.sig_in[node], Signal(1.0, name="1"), sig_in, tag="%s input" % node.label)) if sig_out is not None: model.sig_out[node] = sig_out for probe in node.probes["output"]: Builder.build(probe, dimensions=model.sig_out[node].shape, model=model) model.params[node] = None
def __init__(self, output=None, size_in=0, size_out=None, label="Node"): if output is not None and not is_callable(output): output = npext.array(output, min_dims=1, copy=False) self.output = output self.label = label self.size_in = size_in if output is not None: if isinstance(output, np.ndarray): shape_out = output.shape elif size_out is None and is_callable(output): t, x = np.asarray(0.0), np.zeros(size_in) args = [t, x] if size_in > 0 else [t] try: result = output(*args) except TypeError: raise TypeError( "The function '%s' provided to '%s' takes %d " "argument(s), where a function for this type " "of node is expected to take %d argument(s)" % ( output.__name__, self, output.__code__.co_argcount, len(args))) shape_out = (0,) if result is None \ else np.asarray(result).shape else: shape_out = (size_out,) # assume `size_out` is correct if len(shape_out) > 1: raise ValueError( "Node output must be a vector (got array shape %s)" % (shape_out,)) size_out_new = shape_out[0] if len(shape_out) == 1 else 1 if size_out is not None and size_out != size_out_new: raise ValueError( "Size of Node output (%d) does not match `size_out` (%d)" % (size_out_new, size_out)) size_out = size_out_new else: # output is None size_out = size_in self.size_out = size_out # Set up probes self.probes = {'output': []}
def piecewise_function(t, data=ordered_data): # get the t we'll use for output for time in (time for time in data.keys() if time <= t): out_t = time # if it's a function, call it if is_callable(data[out_t]): return np.asarray(data[out_t](t)) return data[out_t]
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.keys(): 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 is_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(data.items())) # 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.keys() if time <= t): out_t = time # if it's a function, call it if is_callable(data[out_t]): return np.asarray(data[out_t](t)) return data[out_t] return piecewise_function