Example #1
0
    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)
Example #2
0
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
Example #3
0
    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': []}
Example #4
0
    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]
Example #5
0
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