Example #1
0
    def coerce(self, instance, data):
        data = super().coerce(instance, data)

        size_out = None
        for time, value in data.items():
            if not is_number(time):
                raise ValidationError("Keys must be times (floats or ints), "
                                      "not %r" % type(time).__name__,
                                      attr='data',
                                      obj=instance)

            # figure out the length of this item
            if callable(value):
                try:
                    value = np.ravel(value(time))
                except Exception:
                    raise ValidationError(
                        "callable object for time step %.3f "
                        "should return a numerical constant" % time,
                        attr='data',
                        obj=instance)
            else:
                value = np.ravel(value)
                data[time] = value
            size = value.size

            # make sure this is the same size as previous items
            if size != size_out and size_out is not None:
                raise ValidationError("time %g has size %d instead of %d" %
                                      (time, size, size_out),
                                      attr='data',
                                      obj=instance)
            size_out = size

        return data
Example #2
0
    def coerce(self, instance, num):
        if num is not None:
            if is_array(num) and num.shape == ():
                num = num.item()  # convert scalar array to Python object

            if not is_number(num):
                raise ValidationError(
                    f"Must be a number; got '{num}'", attr=self.name, obj=instance
                )
            low_comp = 0 if self.low_open else -1
            if self.low is not None and compare(num, self.low) <= low_comp:
                eq_phrase = "" if self.low_open else " or equal to"
                raise ValidationError(
                    f"Value must be greater than{eq_phrase} {self.low} (got {num})",
                    attr=self.name,
                    obj=instance,
                )
            high_comp = 0 if self.high_open else 1
            if self.high is not None and compare(num, self.high) >= high_comp:
                eq_phrase = "" if self.high_open else " or equal to"
                raise ValidationError(
                    f"Value must be less than{eq_phrase} {self.high} (got {num})",
                    attr=self.name,
                    obj=instance,
                )
        return super().coerce(instance, num)
Example #3
0
    def parse(self, text):
        """Evaluate a text string and return the corresponding SemanticPointer.

        This uses the Python ``eval()`` function, so any Python operators that
        have been defined for SemanticPointers are valid (``+``, ``-``, ``*``,
        ``~``, ``()``). Any terms do not exist in the vocabulary will be
        automatically generated. Valid semantic pointer terms must start
        with a capital letter.

        If the expression returns a scalar (int or float), a scaled version
        of the identity SemanticPointer will be returned.
        """

        # The following line does everything.  Note that self is being
        # passed in as the locals dictionary, and thanks to the __getitem__
        # implementation, this will automatically create new semantic
        # pointers as needed.
        try:
            value = eval(text, {}, self)
        except NameError:
            raise SpaParseError(
                "Semantic pointers must start with a capital letter.")

        if is_number(value):
            value = value * self.identity
        if not isinstance(value, pointer.SemanticPointer):
            raise SpaParseError(
                "The result of parsing '%s' is not a SemanticPointer" % text)
        return value
Example #4
0
    def coerce(self, instance, num):
        if num is not None:
            if is_array(num) and num.shape == ():
                num = num.item()  # convert scalar array to Python object

            if not is_number(num):
                raise ValidationError("Must be a number; got '%s'" % num,
                                      attr=self.name,
                                      obj=instance)
            low_comp = 0 if self.low_open else -1
            if self.low is not None and compare(num, self.low) <= low_comp:
                raise ValidationError(
                    "Value must be greater than %s%s (got %s)" %
                    ("" if self.low_open else "or equal to ", self.low, num),
                    attr=self.name,
                    obj=instance,
                )
            high_comp = 0 if self.high_open else 1
            if self.high is not None and compare(num, self.high) >= high_comp:
                raise ValidationError(
                    "Value must be less than %s%s (got %s)" %
                    ("" if self.high_open else "or equal to ", self.high, num),
                    attr=self.name,
                    obj=instance,
                )
        return super().coerce(instance, num)
Example #5
0
File: vocab.py Project: nengo/nengo
    def parse(self, text):
        """Evaluate a text string and return the corresponding SemanticPointer.

        This uses the Python ``eval()`` function, so any Python operators that
        have been defined for SemanticPointers are valid (``+``, ``-``, ``*``,
        ``~``, ``()``). Any terms do not exist in the vocabulary will be
        automatically generated. Valid semantic pointer terms must start
        with a capital letter.

        If the expression returns a scalar (int or float), a scaled version
        of the identity SemanticPointer will be returned.
        """

        # The following line does everything.  Note that self is being
        # passed in as the locals dictionary, and thanks to the __getitem__
        # implementation, this will automatically create new semantic
        # pointers as needed.
        try:
            value = eval(text, {}, self)
        except NameError:
            raise SpaParseError(
                "Semantic pointers must start with a capital letter.")

        if is_number(value):
            value = value * self.identity
        if not isinstance(value, pointer.SemanticPointer):
            raise SpaParseError(
                "The result of parsing '%s' is not a SemanticPointer" % text)
        return value
Example #6
0
    def coerce(self, instance, data):
        data = super().coerce(instance, data)

        size_out = None
        for time, value in data.items():
            if not is_number(time):
                raise ValidationError("Keys must be times (floats or ints), "
                                      "not %r" % type(time).__name__,
                                      attr='data', obj=instance)

            # figure out the length of this item
            if callable(value):
                try:
                    value = np.ravel(value(time))
                except Exception:
                    raise ValidationError("callable object for time step %.3f "
                                          "should return a numerical constant"
                                          % time, attr='data', obj=instance)
            else:
                value = np.ravel(value)
                data[time] = value
            size = value.size

            # make sure this is the same size as previous items
            if size != size_out and size_out is not None:
                raise ValidationError("time %g has size %d instead of %d" %
                                      (time, size, size_out),
                                      attr='data', obj=instance)
            size_out = size

        return data
Example #7
0
    def __mul__(self, other):
        """Multiplication of two SemanticPointers is circular convolution.

        If multiplied by a scalar, we do normal multiplication.
        """
        if isinstance(other, SemanticPointer):
            return self.convolve(other)
        elif is_number(other):
            return SemanticPointer(data=self.v * other)
        else:
            raise NotImplementedError(
                "Can only multiply by SemanticPointers or scalars")
 def _parse_var(self, var):
     if is_number(var):
         return NumExp(var)
     elif isinstance(var, str):
         return '"%s"' % var
     elif isinstance(var, (list, np.ndarray)):
         if isinstance(var, np.ndarray):
             var = var.tolist()
         self._check_vector_length(len(var))
         return [self._parse_var(v) for v in var]
     else:
         return var
Example #9
0
    def __imul__(self, other):
        """Multiplication of two SemanticPointers is circular convolution.

        If mutliplied by a scaler, we do normal multiplication.
        """
        if isinstance(other, SemanticPointer):
            self.v = np.fft.ifft(np.fft.fft(self.v) * np.fft.fft(other.v)).real
        elif is_number(other):
            self.v *= other
        else:
            raise NotImplementedError(
                "Can only multiply by SemanticPointers or scalars")
        return self
Example #10
0
 def __mul__(self, other):
     if isinstance(other, Symbol):
         if other.symbol == '1':
             return self
         if self.symbol == '1':
             return other
         return Symbol('(%s * %s)' % (self.symbol, other.symbol))
     if is_number(other):
         if other == 1:
             return self
         if self.symbol == '1':
             return Symbol('%g' % other)
         return Symbol('(%s * %g)' % (self.symbol, other))
     return NotImplemented
Example #11
0
 def __mul__(self, other):
     if isinstance(other, Symbol):
         if other.symbol == "1":
             return self
         if self.symbol == "1":
             return other
         return Symbol("(%s * %s)" % (self.symbol, other.symbol))
     if is_number(other):
         if other == 1:
             return self
         if self.symbol == "1":
             return Symbol("%g" % other)
         return Symbol("(%s * %g)" % (self.symbol, other))
     return NotImplemented
Example #12
0
 def __mul__(self, other):
     if isinstance(other, Symbol):
         if other.symbol == '1':
             return self
         if self.symbol == '1':
             return other
         return Symbol('(%s * %s)' % (self.symbol, other.symbol))
     if is_number(other):
         if other == 1:
             return self
         if self.symbol == '1':
             return Symbol('%g' % other)
         return Symbol('(%s * %g)' % (self.symbol, other))
     return NotImplemented
Example #13
0
    def on_add(self, spa):
        """Form the connections into the BG to compute the utilty values.

        Each action's condition variable contains the set of computations
        needed for that action's utility value, which is the input to the
        basal ganglia.
        """
        Module.on_add(self, spa)
        self.spa = spa

        self.actions.process(spa)  # parse the actions

        for i, action in enumerate(self.actions.actions):
            cond = action.condition.expression
            # the basal ganglia hangles the condition part of the action;
            # the effect is handled by the thalamus

            # Note: A Source is an output from a module, and a Symbol is
            # text that can be parsed to be a SemanticPointer

            for c in cond.items:
                if isinstance(c, DotProduct):
                    if (isinstance(c.item1, Source) and c.item1.inverted) or (
                        isinstance(c.item2, Source) and c.item2.inverted
                    ):
                        raise NotImplementedError(
                            "Inversion in subexpression '%s' from action '%s' "
                            "is not supported by the Basal Ganglia." % (c, action)
                        )
                    if isinstance(c.item1, Source):
                        if isinstance(c.item2, Source):
                            # dot product between two different sources
                            self.add_compare_input(i, c.item1, c.item2, c.scale)
                        else:
                            self.add_dot_input(i, c.item1, c.item2, c.scale)
                    else:
                        # enforced in DotProduct constructor
                        assert isinstance(c.item2, Source)
                        self.add_dot_input(i, c.item2, c.item1, c.scale)
                elif isinstance(c, Source):
                    self.add_scalar_input(i, c)
                elif is_number(c):
                    self.add_bias_input(i, c)
                else:
                    raise NotImplementedError(
                        "Subexpression '%s' from action '%s' is not supported "
                        "by the Basal Ganglia." % (c, action)
                    )
Example #14
0
    def coerce(self, instance, data):
        data = super().coerce(instance, data)

        size_out = None
        for time, value in data.items():
            if not is_number(time):
                raise ValidationError(
                    f"Keys must be times (floats or ints), not '{type(time).__name__}'",
                    attr="data",
                    obj=instance,
                )

            # figure out the length of this item
            if callable(value):
                try:
                    value = np.ravel(value(time))
                except Exception as e:
                    raise ValidationError(
                        f"callable object for time step {time:0.3f} "
                        "should return a numerical constant",
                        attr="data",
                        obj=instance,
                    ) from e
            else:
                value = np.ravel(value)
                data[time] = value
            size = value.size

            # make sure this is the same size as previous items
            if size != size_out and size_out is not None:
                raise ValidationError(
                    f"time {time} has size {size} instead of {size_out}",
                    attr="data",
                    obj=instance,
                )
            size_out = size

        return data
Example #15
0
    def coerce(self, instance, num):
        if num is not None:
            if is_array(num) and num.shape == ():
                num = num.item()  # convert scalar array to Python object

            if not is_number(num):
                raise ValidationError("Must be a number; got '%s'" % num,
                                      attr=self.name, obj=instance)
            low_comp = 0 if self.low_open else -1
            if self.low is not None and compare(num, self.low) <= low_comp:
                raise ValidationError(
                    "Value must be greater than %s%s (got %s)" % (
                        "" if self.low_open else "or equal to ",
                        self.low,
                        num), attr=self.name, obj=instance)
            high_comp = 0 if self.high_open else 1
            if self.high is not None and compare(num, self.high) >= high_comp:
                raise ValidationError(
                    "Value must be less than %s%s (got %s)" % (
                        "" if self.high_open else "or equal to ",
                        self.high,
                        num), attr=self.name, obj=instance)
        return super().coerce(instance, num)
Example #16
0
def piecewise(data):
    """Create a piecewise constant function from a dictionary.

    .. deprecated:: 2.5.1
       Use `nengo.processes.Piecewise` instead.

    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]

    """

    warnings.warn(
        "The `piecewise` function is deprecated. Use the Piecewise "
        "process instead.", DeprecationWarning)

    # 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 ValidationError(
                "Keys must be times (floats or ints), not %r" %
                type(time).__name__,
                attr='data')

        # 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 ValidationError("time %g has %d items instead of %d" %
                                  (time, length, output_length),
                                  attr='data')
        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 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
Example #17
0
 def _is_number_or_scalar(x):
     return is_number(x) or (is_array(x) and x.ndim == 0)
Example #18
0
def _plan_template(  # noqa: C901
    queue,
    name,
    core_text,
    declares="",
    tag=None,
    blockify=True,
    inputs=None,
    outputs=None,
    parameters=None,
):
    """Template for making a plan for vector nonlinearities.
    This template assumes that all inputs and outputs are vectors.
    Parameters
    ----------
    blockify : bool
        If true, divide the inputs up into blocks with a maximum size.
    inputs: dictionary of CLRaggedArrays
        Inputs to the function. RaggedArrays must be a list of vectors.
    outputs: dictionary of CLRaggedArrays
        Outputs of the function. RaggedArrays must be a list of vectors.
    parameters: dictionary of CLRaggedArrays
        Parameters to the function. Each RaggedArray element must be a vector
        of the same length of the inputs, or a scalar (to be broadcasted).
        Providing a float instead of a RaggedArray makes that parameter
        constant.
    """
    inputs = {} if inputs is None else inputs
    outputs = {} if outputs is None else outputs
    parameters = {} if parameters is None else parameters

    input0 = list(inputs.values())[0]  # input to use as reference for lengths

    # split parameters into static and updated params
    static_params = {}  # static params (hard-coded)
    params = {}  # variable params (updated)
    for k, v in parameters.items():
        if isinstance(v, CLRaggedArray):
            params[k] = v
        elif is_number(v):
            static_params[k] = ("float", float(v))
        else:
            raise ValueError(
                "Parameter %r must be CLRaggedArray or float (got %s)" %
                (k, type(v)))

    avars = {}
    bw_per_call = 0
    for vname, v in list(inputs.items()) + list(outputs.items()) + list(
            params.items()):
        assert vname not in avars, "Name clash"
        assert len(v) == len(input0)
        assert (v.shape0s == input0.shape0s).all()
        assert (v.stride0s == v.shape1s).all()  # rows contiguous
        assert (v.stride1s == 1).all()  # columns contiguous
        assert (v.shape1s == 1).all()  # vectors only

        offset = "%(name)s_starts[gind1]" % {"name": vname}
        avars[vname] = (v.ctype, offset)
        bw_per_call += v.nbytes

    ivars = {k: avars[k] for k in inputs}
    ovars = {k: avars[k] for k in outputs}
    pvars = {k: avars[k] for k in params}

    fn_name = str(name)
    textconf = dict(
        fn_name=fn_name,
        declares=declares,
        core_text=core_text,
        ivars=ivars,
        ovars=ovars,
        pvars=pvars,
        static_params=static_params,
    )

    text = """
    ////////// MAIN FUNCTION //////////
    __kernel void ${fn_name}(
% for name, [type, offset] in ivars.items():
        __global const int *${name}_starts,
        __global const ${type} *${name}_buf,
% endfor
% for name, [type, offset] in ovars.items():
        __global const int *${name}_starts,
        __global ${type} *${name}_buf,
% endfor
% for name, [type, offset] in pvars.items():
        __global const int *${name}_starts,
        __global const int *${name}_shape0s,
        __global const ${type} *${name}_buf,
% endfor
        __global const int *sizes
    )
    {
        const int gind0 = get_global_id(0);
        const int gind1 = get_global_id(1);
        if (gind1 >= ${N} || gind0 >= sizes[gind1])
            return;
% for name, [type, offset] in ivars.items():
        ${type} ${name} = ${name}_buf[${offset} + gind0];
% endfor
% for name, [type, offset] in ovars.items():
        ${type} ${name};
% endfor
% for name, [type, offset] in pvars.items():
        const ${type} ${name} = ${name}_buf[${offset} + gind0];
% endfor
% for name, [type, value] in static_params.items():
        const ${type} ${name} = ${value};
% endfor
        //////////////////////////////////////////////////
        //vvvvv USER DECLARATIONS BELOW vvvvv
        ${declares}
        //^^^^^ USER DECLARATIONS ABOVE ^^^^^
        //////////////////////////////////////////////////
        /////vvvvv USER COMPUTATIONS BELOW vvvvv
        ${core_text}
        /////^^^^^ USER COMPUTATIONS ABOVE ^^^^^
% for name, [type, offset] in ovars.items():
        ${name}_buf[${offset} + gind0] = ${name};
% endfor
    }
    """

    if blockify:
        # blockify to help with heterogeneous sizes

        # find best block size
        block_sizes = [16, 32, 64, 128, 256, 512, 1024]
        N = np.inf
        for block_size_i in block_sizes:
            sizes_i, inds_i, _ = blockify_vector(block_size_i, input0)
            if len(sizes_i) < N:
                N = len(sizes_i)
                block_size = block_size_i
                sizes = sizes_i
                inds = inds_i

        clsizes = to_device(queue, sizes)
        get_starts = lambda ras: [
            to_device(queue, starts)
            for starts in blockify_vectors(block_size, ras)[2]
        ]
        Istarts = get_starts(inputs.values())
        Ostarts = get_starts(outputs.values())
        Pstarts = get_starts(params.values())
        Pshape0s = [to_device(queue, x.shape0s[inds]) for x in params.values()]

        lsize = None
        gsize = (block_size, len(sizes))

        full_args = []
        for vstarts, v in zip(Istarts, inputs.values()):
            full_args.extend([vstarts, v.cl_buf])
        for vstarts, v in zip(Ostarts, outputs.values()):
            full_args.extend([vstarts, v.cl_buf])
        for vstarts, vshape0s, v in zip(Pstarts, Pshape0s, params.values()):
            full_args.extend([vstarts, vshape0s, v.cl_buf])
        full_args.append(clsizes)
    else:
        # Allocate more than enough kernels in a matrix
        lsize = None
        gsize = (input0.shape0s.max(), len(input0))

        full_args = []
        for v in inputs.values():
            full_args.extend([v.cl_starts, v.cl_buf])
        for v in outputs.values():
            full_args.extend([v.cl_starts, v.cl_buf])
        for vname, v in params.items():
            full_args.extend([v.cl_starts, v.cl_shape0s, v.cl_buf])
        full_args.append(input0.cl_shape0s)

    textconf["N"] = gsize[1]
    text = as_ascii(Template(text, output_encoding="ascii").render(**textconf))
    fns = cl.Program(queue.context, text).build()
    _fn = getattr(fns, fn_name)
    _fn.set_args(*[arr.data for arr in full_args])

    plan = Plan(queue, _fn, gsize, lsize=lsize, name=name, tag=tag)
    plan.full_args = tuple(full_args)  # prevent garbage-collection
    plan.bw_per_call = bw_per_call
    plan.description = "groups: %d; items: %d; items/group: %0.1f [%d, %d]" % (
        gsize[1],
        input0.sizes.sum(),
        input0.sizes.mean(),
        input0.sizes.min(),
        input0.sizes.max(),
    )
    return plan
Example #19
0
 def coerce(self, instance, synapse):  # pylint: disable=arguments-renamed
     synapse = Lowpass(synapse) if is_number(synapse) else synapse
     self.check_type(instance, synapse, Synapse)
     return super().coerce(instance, synapse)
Example #20
0
def piecewise(data):
    """Create a piecewise constant function from a dictionary.

    .. deprecated:: 2.5.1
       Use `nengo.processes.Piecewise` instead.

    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]

    """

    warnings.warn("The `piecewise` function is deprecated. Use the Piecewise "
                  "process instead.", DeprecationWarning)

    # 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 ValidationError("Keys must be times (floats or ints), not %r"
                                  % type(time).__name__, attr='data')

        # 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 ValidationError("time %g has %d items instead of %d" %
                                  (time, length, output_length), attr='data')
        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 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
Example #21
0
 def __add__(self, other):
     if is_number(other):
         other = Symbol('%g' % other)
     if isinstance(other, Symbol):
         return Symbol('(%s + %s)' % (self.symbol, other.symbol))
     return NotImplemented
Example #22
0
 def __mul__(self, other):
     if isinstance(other, Source):
         return Convolution(self, other)
     elif is_number(other) or isinstance(other, Symbol):
         return Source(self.name, self.transform * other, self.inverted)
     return NotImplemented
Example #23
0
 def coerce(self, instance, synapse):
     synapse = Lowpass(synapse) if is_number(synapse) else synapse
     self.check_type(instance, synapse, Synapse)
     return super().coerce(instance, synapse)
Example #24
0
 def __mul__(self, other):
     if isinstance(other, Source):
         return Convolution(self, other)
     elif is_number(other) or isinstance(other, Symbol):
         return Source(self.name, self.transform*other, self.inverted)
     return NotImplemented
Example #25
0
 def coerce(self, instance, synapse):
     synapse = Lowpass(synapse) if is_number(synapse) else synapse
     self.check_type(instance, synapse, Synapse)
     return super().coerce(instance, synapse)
Example #26
0
 def __add__(self, other):
     if is_number(other):
         other = Symbol('%g' % other)
     if isinstance(other, Symbol):
         return Symbol('(%s + %s)' % (self.symbol, other.symbol))
     return NotImplemented