Ejemplo n.º 1
0
 def combine(self, obj):
     """Combine in series with another LinearFilter."""
     if not isinstance(obj, LinearFilter):
         raise ValidationError("Can only combine with other LinearFilters",
                               attr="obj")
     if self.analog != obj.analog:
         raise ValidationError("Cannot combine analog and digital filters",
                               attr="obj")
     num = np.polymul(self.num, obj.num)
     den = np.polymul(self.den, obj.den)
     return LinearFilter(
         num,
         den,
         analog=self.analog,
         default_size_in=self.default_size_in,
         default_size_out=self.default_size_out,
         default_dt=self.default_dt,
         seed=self.seed,
     )
Ejemplo n.º 2
0
    def coerce(self, node, func):
        """
        Performs validation on the function passed to TensorNode, and sets
        ``size_out`` if necessary.

        Parameters
        ----------
        node : `.TensorNode`
            The node whose ``tensor_func`` parameter is being set.
        func : callable
            The function being assigned to the TensorNode.

        Returns
        -------
        output : callable
            The function after validation is applied.
        """

        output = super(TensorFuncParam, self).coerce(node, func)

        if node.size_out is None:
            if not callable(func):
                raise ValidationError("TensorNode output must be a function",
                                      attr=self.name,
                                      obj=node)

            with tf.Graph().as_default():
                t, x = tf.constant(0.0), tf.zeros((1, node.size_in))
                args = (t, x) if node.size_in > 0 else (t, )
                try:
                    result = func(*args)
                except Exception as e:
                    raise ValidationError(
                        "Calling TensorNode function with arguments %s "
                        "produced an error:\n%s" % (args, e),
                        attr=self.name,
                        obj=node)

            validate_output(result)

            node.size_out = result.get_shape()[1].value

        return output
Ejemplo n.º 3
0
 def determine_size(self, instance, function):
     args = self.function_args(instance, function)
     value, invoked = checked_call(function, *args)
     if not invoked:
         raise ValidationError(
             "function '%s' must accept a single np.array argument" % function,
             attr=self.name,
             obj=instance,
         )
     return np.asarray(value).size
Ejemplo n.º 4
0
 def check_type(self, instance, value, type_):
     if value is not None and not isinstance(value, type_):
         if isinstance(type_, tuple):
             type_str = " or ".join((t.__name__ for t in type_))
         else:
             type_str = type_.__name__
         raise ValidationError("Must be of type %r (got type %r)." %
                               (type_str, type(value).__name__),
                               attr=self.name,
                               obj=instance)
Ejemplo n.º 5
0
 def check_pre(self, conn, rule):
     pre = conn.pre_obj
     if rule.modifies in ("decoders", "weights"):
         # pre object must be neural
         if not isinstance(pre, (Ensemble, Neurons)):
             raise ValidationError(
                 "'pre' must be of type 'Ensemble' or 'Neurons' for "
                 f"learning rule '{rule}' (got type '{type(pre).__name__}')",
                 attr=self.name,
                 obj=conn,
             )
         if isinstance(pre, Ensemble) and isinstance(
                 pre.neuron_type, Direct):
             raise ValidationError(
                 "'pre' cannot have neuron type 'Direct'. Connections from "
                 "'Direct' ensembles do not have decoders or weights.",
                 attr=self.name,
                 obj=conn,
             )
Ejemplo n.º 6
0
 def check_ndarray(self, node, output):
     if len(output.shape) > 1:
         raise ValidationError(
             "Node output must be a vector (got shape %s)" %
             (output.shape, ),
             attr=self.name,
             obj=node,
         )
     if node.size_in != 0:
         raise ValidationError("output must be callable if size_in != 0",
                               attr=self.name,
                               obj=node)
     if node.size_out is not None and node.size_out != output.size:
         raise ValidationError(
             "Size of Node output (%d) does not match "
             "size_out (%d)" % (output.size, node.size_out),
             attr=self.name,
             obj=node,
         )
Ejemplo n.º 7
0
    def __init__(self, x, p):
        super(PDF, self).__init__()

        psum = np.sum(p)
        if np.abs(psum - 1) > 1e-8:
            raise ValidationError(
                "PDF must sum to one (sums to %f)" % psum, attr='p', obj=self)

        self.x = x
        self.p = p
        if len(self.x) != len(self.p):
            raise ValidationError(
                "`x` and `p` must be the same length", attr='p', obj=self)

        # make cumsum = [0] + cumsum, cdf = 0.5 * (cumsum[:-1] + cumsum[1:])
        cumsum = np.cumsum(p)
        cumsum *= 0.5
        cumsum[1:] = cumsum[:-1] + cumsum[1:]
        self.cdf = cumsum
Ejemplo n.º 8
0
    def __set__(self, node, output):
        super(OutputParam, self).validate(node, output)

        size_in_set = node.size_in is not None
        node.size_in = node.size_in if size_in_set else 0

        # --- Validate and set the new size_out
        if output is None:
            if node.size_out is not None:
                warnings.warn("'Node.size_out' is being overwritten with "
                              "'Node.size_in' since 'Node.output=None'")
            node.size_out = node.size_in
        elif isinstance(output, Process):
            if not size_in_set:
                node.size_in = output.default_size_in
            if node.size_out is None:
                node.size_out = output.default_size_out
        elif callable(output):
            # We trust user's size_out if set, because calling output
            # may have unintended consequences (e.g., network communication)
            if node.size_out is None:
                result = self.validate_callable(node, output)
                node.size_out = 0 if result is None else result.size
        elif is_array_like(output):
            # Make into correctly shaped numpy array before validation
            output = npext.array(output,
                                 min_dims=1,
                                 copy=False,
                                 dtype=np.float64)
            self.validate_ndarray(node, output)
            if not np.all(np.isfinite(output)):
                raise ValidationError("Output value must be finite.",
                                      attr=self.name,
                                      obj=node)
            node.size_out = output.size
        else:
            raise ValidationError("Invalid node output type %r" %
                                  type(output).__name__,
                                  attr=self.name,
                                  obj=node)

        # --- Set output
        self.data[node] = output
Ejemplo n.º 9
0
    def validate_callable(self, node, output):
        t, x = 0.0, np.zeros(node.size_in)
        args = (t, x) if node.size_in > 0 else (t, )
        result, invoked = checked_call(output, *args)
        if not invoked:
            msg = ("output function '%s' is expected to accept exactly "
                   "%d argument" % (output, len(args)))
            msg += (' (time, as a float)' if len(args) == 1 else
                    's (time, as a float and data, as a NumPy array)')
            raise ValidationError(msg, attr=self.name, obj=node)

        if result is not None:
            result = np.asarray(result)
            if len(result.shape) > 1:
                raise ValidationError("Node output must be a vector (got shape"
                                      " %s)" % (result.shape, ),
                                      attr=self.name,
                                      obj=node)
        return result
Ejemplo n.º 10
0
 def coerce(self, instance, size_in):
     if is_string(size_in):
         if size_in not in self.valid_strings:
             raise ValidationError(
                 "%r is not a valid string value (must be one of %s)"
                 % (size_in, self.strings), attr=self.name, obj=instance)
         return size_in
     else:
         return super(LearningRuleTypeSizeInParam, self).coerce(
             instance, size_in)  # IntParam validation
Ejemplo n.º 11
0
 def __get__(self, instance, type_):
     if instance is None:
         # Return self so default can be inspected
         return self
     if not self.configurable and instance not in self.data:
         raise ValidationError(
             "Unconfigurable parameters have no defaults. Please ensure the"
             " value of the parameter is set before trying to access it.",
             attr=self.name, obj=instance)
     return self.data.get(instance, self.default)
Ejemplo n.º 12
0
    def coerce(self, node, output):  # pylint: disable=arguments-renamed
        output = super().coerce(node, output)

        size_in_set = node.size_in is not None
        node.size_in = node.size_in if size_in_set else 0

        # --- Validate and set the new size_out
        if output is None:
            if node.size_out is not None:
                warnings.warn("'Node.size_out' is being overwritten with "
                              "'Node.size_in' since 'Node.output=None'")
            node.size_out = node.size_in
        elif isinstance(output, Process):
            if not size_in_set:
                node.size_in = output.default_size_in
            if node.size_out is None:
                node.size_out = output.default_size_out
        elif callable(output):
            self.check_callable_args_list(node, output)
            # We trust user's size_out if set, because calling output
            # may have unintended consequences (e.g., network communication)
            if node.size_out is None:
                node.size_out = self.check_callable_output(node, output)
        elif is_array_like(output):
            # Make into correctly shaped numpy array before validation
            output = npext.array(output,
                                 min_dims=1,
                                 copy=False,
                                 dtype=rc.float_dtype)
            self.check_ndarray(node, output)
            if not np.all(np.isfinite(output)):
                raise ValidationError("Output value must be finite.",
                                      attr=self.name,
                                      obj=node)
            node.size_out = output.size
        else:
            raise ValidationError(
                f"Invalid node output type '{type(output).__name__}'",
                attr=self.name,
                obj=node,
            )

        return output
Ejemplo n.º 13
0
    def add_input_mapping(self, name, input_vectors, input_scales=1.0):
        """Adds a set of input vectors to the associative memory network.

        Creates a transform with the given input vectors between the
        a named input node and associative memory element input to enable the
        inputs to be mapped onto ensembles of the Associative Memory.

        Parameters
        ----------
        name: str
            Name to use for the input node. This name will be used as the name
            of the attribute for the associative memory network.
        input_vectors: array_like
            The list of vectors to be compared against.
        input_scales: float or array_like, optional
            Scaling factor to apply on each of the input vectors. Note that it
            is possible to scale each vector independently.
        """
        # --- Put arguments in canonical form
        n_vectors, d_vectors = input_vectors.shape
        if is_iterable(input_vectors):
            input_vectors = np.array(input_vectors, ndmin=2)
        if not is_iterable(input_scales):
            input_scales = input_scales * np.ones((1, n_vectors))
        else:
            input_scales = np.array(input_scales, ndmin=2)

        # --- Check some preconditions
        if input_scales.shape[1] != n_vectors:
            raise ValidationError("Number of input_scale values (%d) does not "
                                  "match number of input vectors (%d)."
                                  % (input_scales.shape[1], n_vectors),
                                  attr='input_scales')
        if hasattr(self, name):
            raise ValidationError("Name '%s' already exists as a node in the "
                                  "associative memory." % name, attr='name')

        # --- Finally, make the input node and connect it
        in_node = nengo.Node(size_in=d_vectors, label=name)
        setattr(self, name, in_node)
        nengo.Connection(in_node, self.elem_input,
                         synapse=None,
                         transform=input_vectors * input_scales.T)
Ejemplo n.º 14
0
 def __init__(self, initial_state=None):
     super().__init__()
     self.initial_state = initial_state
     if self.initial_state is not None:
         for name, value in self.initial_state.items():
             if name not in self.state:
                 raise ValidationError(
                     "State variable %r not recognized; should be one of %s"
                     % (name, ", ".join(repr(k) for k in self.state)),
                     attr="initial_state",
                     obj=self,
                 )
             if not (isinstance(value, Distribution) or is_array_like(value)):
                 raise ValidationError(
                     "State variable %r must be a distribution or array-like"
                     % (name,),
                     attr="initial_state",
                     obj=self,
                 )
Ejemplo n.º 15
0
 def coerce(self, instance, string):
     string = super().coerce(instance, string)
     string = string.lower() if self.lower else string
     if string not in self.value_set:
         raise ValidationError(
             "String %r must be one of %s" % (string, list(self.values)),
             attr=self.name,
             obj=instance,
         )
     return string
Ejemplo n.º 16
0
    def __init__(self, options, weights=None):
        super(Choice, self).__init__()
        self.options = options
        self.weights = weights

        weights = (np.ones(len(self.options)) if self.weights is None else
                   self.weights)
        if len(weights) != len(self.options):
            raise ValidationError(
                "Number of weights (%d) must match number of options (%d)"
                % (len(weights), len(self.options)), attr='weights', obj=self)
        if not all(weights >= 0):
            raise ValidationError("All weights must be non-negative",
                                  attr='weights', obj=self)
        total = float(weights.sum())
        if total <= 0:
            raise ValidationError("Sum of weights must be positive (got %f)"
                                  % total, attr='weights', obj=self)
        self.p = weights / total
Ejemplo n.º 17
0
    def coerce(self, instance, value):
        value = super().coerce(instance, value)
        if value is not None:
            for i, v in enumerate(value):
                if not is_integer(v):
                    raise ValidationError(
                        "Element %d must be an int (got type %r)" %
                        (i, type(v).__name__),
                        attr=self.name,
                        obj=instance,
                    )
                if self.low is not None and v < self.low:
                    raise ValidationError(
                        "Element %d must be >= %d (got %d)" % (i, self.low, v),
                        attr=self.name,
                        obj=instance,
                    )

        return value
Ejemplo n.º 18
0
    def check_function_can_be_applied(self, conn, function_info):
        function, size = function_info
        type_pre = type(conn.pre_obj).__name__

        if function is not None:
            if not isinstance(conn.pre_obj, (Node, Ensemble)):
                raise ValidationError(
                    "function can only be set for connections from an Ensemble"
                    " or Node (got type %r)" % type_pre,
                    attr=self.name,
                    obj=conn,
                )

            if isinstance(conn.pre_obj, Node) and conn.pre_obj.output is None:
                raise ValidationError(
                    "Cannot apply functions to passthrough nodes",
                    attr=self.name,
                    obj=conn,
                )
Ejemplo n.º 19
0
    def sample(self, n, d=None, rng=np.random):
        if d is not None and self.dimensions != d:
            raise ValidationError(
                f"Options must be of dimensionality {d} (got {self.dimensions})",
                attr="options",
                obj=self,
            )

        i = np.searchsorted(np.cumsum(self.p), rng.rand(n))
        return self.options[i]
Ejemplo n.º 20
0
    def __init__(
        self,
        n_neurons,
        n_ensembles,
        ens_dimensions=1,
        label=None,
        seed=None,
        add_to_container=None,
        **ens_kwargs,
    ):
        if "dimensions" in ens_kwargs:
            raise ValidationError(
                "'dimensions' is not a valid argument to EnsembleArray. "
                "To set the number of ensembles, use 'n_ensembles'. To set "
                "the number of dimensions per ensemble, use 'ens_dimensions'.",
                attr="dimensions",
                obj=self,
            )

        super().__init__(label, seed, add_to_container)

        for param, value in ens_kwargs.items():
            if is_iterable(value):
                ens_kwargs[param] = Samples(value)

        self.config[Ensemble].update(ens_kwargs)

        label_prefix = "" if label is None else label + "_"

        self.n_neurons_per_ensemble = n_neurons
        self.n_ensembles = n_ensembles
        self.dimensions_per_ensemble = ens_dimensions

        # These may be set in add_neuron_input and add_neuron_output
        self.neuron_input, self.neuron_output = None, None

        self.ea_ensembles = []

        with self:
            self.input = Node(size_in=self.dimensions, label="input")

            for i in range(n_ensembles):
                e = Ensemble(
                    n_neurons,
                    self.dimensions_per_ensemble,
                    label=f"{label_prefix}{i}",
                )
                Connection(
                    self.input[i * ens_dimensions : (i + 1) * ens_dimensions],
                    e,
                    synapse=None,
                )
                self.ea_ensembles.append(e)

        self.add_output("output", function=None)
Ejemplo n.º 21
0
def validate_output(output, minibatch_size=None, output_d=None, dtype=None):
    """
    Performs validation on the output of a TensorNode ``tensor_func``.

    Parameters
    ----------
    output : ``tf.Tensor`` or ``tf.TensorSpec``
        Output from the ``tensor_func``.
    minibatch_size : int
        Expected minibatch size for the simulation.
    output_d
        Expected output dimensionality for the function.
    dtype
        Expected dtype of the function output.
    """

    if not isinstance(output, (tf.Tensor, tf.TensorSpec)):
        raise ValidationError(
            "TensorNode function must return a Tensor (got %s)" % type(output),
            attr="tensor_func",
        )

    if minibatch_size is not None and output.shape[0] != minibatch_size:
        raise ValidationError(
            "TensorNode output should have batch size %d (got %d)"
            % (minibatch_size, output.shape[0]),
            attr="tensor_func",
        )

    if output_d is not None and np.prod(output.shape[1:]) != output_d:
        raise ValidationError(
            "TensorNode output should have size %d (got shape %s with size %d)"
            % (minibatch_size, output.shape[1:], np.prod(output.shape[1:])),
            attr="tensor_func",
        )

    if dtype is not None and output.dtype != dtype:
        raise ValidationError(
            "TensorNode output should have dtype %s "
            "(got %s)" % (dtype, output.dtype),
            attr="tensor_func",
        )
Ejemplo n.º 22
0
 def coerce(self, instance, nengo_obj):
     nengo_objects = (
         NengoObject,
         ObjView,
         nengo.ensemble.Neurons,
         nengo.connection.LearningRule,
     )
     if not isinstance(nengo_obj, nengo_objects):
         raise ValidationError("'%s' is not a Nengo object" % nengo_obj,
                               attr=self.name,
                               obj=instance)
     if self.nonzero_size_in and nengo_obj.size_in < 1:
         raise ValidationError("'%s' must have size_in > 0." % nengo_obj,
                               attr=self.name,
                               obj=instance)
     if self.nonzero_size_out and nengo_obj.size_out < 1:
         raise ValidationError("'%s' must have size_out > 0." % nengo_obj,
                               attr=self.name,
                               obj=instance)
     return super().coerce(instance, nengo_obj)
Ejemplo n.º 23
0
 def coerce(self, instance, value):
     if not (isinstance(value, SparseMatrix) or
             (scipy_sparse is not None
              and isinstance(value, scipy_sparse.spmatrix))):
         raise ValidationError(
             "Must be `nengo.transforms.SparseMatrix` or "
             "`scipy.sparse.spmatrix`, got %s" % type(value),
             attr="init",
             obj=instance,
         )
     return super().coerce(instance, value)
Ejemplo n.º 24
0
    def mul_encoders(self, Y, E, copy=False):
        """Helper function that projects signal ``Y`` onto encoders ``E``.

        Parameters
        ----------
        Y : ndarray
            The signal of interest.
        E : (dimensions, n_neurons) array_like or None
            Array of encoders. If None, ``Y`` will be returned unchanged.
        copy : bool, optional (Default: False)
            Whether a copy of ``Y`` should be returned if ``E`` is None.
        """
        if self.weights and E is None:
            raise ValidationError(
                "Encoders must be provided for weight solver", attr='E')
        if not self.weights and E is not None:
            raise ValidationError(
                "Encoders must be 'None' for decoder solver", attr='E')

        return np.dot(Y, E) if E is not None else Y.copy() if copy else Y
Ejemplo n.º 25
0
    def validate(self, instance, vocab):
        super(VocabularyParam, self).validate(instance, vocab)

        if vocab is not None and not isinstance(vocab, Vocabulary):
            raise ValidationError(
                "Must be of type 'Vocabulary' (got type %r)." %
                vocab.__class__.__name__,
                attr=self.name,
                obj=instance)

        return vocab
Ejemplo n.º 26
0
    def check_array(self, conn, ndarray):
        if not isinstance(conn.eval_points, np.ndarray):
            raise ValidationError(
                "In order to set 'function' to specific points, 'eval_points' "
                "must be also be set to specific points.",
                attr=self.name,
                obj=conn)

        if ndarray.ndim != 2:
            raise ValidationError("array must be 2D (got %dD)" % ndarray.ndim,
                                  attr=self.name,
                                  obj=conn)

        if ndarray.shape[0] != conn.eval_points.shape[0]:
            raise ValidationError(
                "Number of evaluation points must match number "
                "of function points (%d != %d)" %
                (ndarray.shape[0], conn.eval_points.shape[0]),
                attr=self.name,
                obj=conn)
Ejemplo n.º 27
0
    def coerce(self, instance, function):
        function_info = super(DeltaRuleFunctionParam, self).coerce(
            instance, function)

        function, size = function_info
        if function is not None and size != self.function_test_size:
            raise ValidationError(
                "Function '%s' input and output sizes must be equal" %
                function, attr=self.name, obj=instance)

        return function_info
Ejemplo n.º 28
0
 def validate(self, instance, num):
     if num is not None:
         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)
     super(NumberParam, self).validate(instance, num)
Ejemplo n.º 29
0
 def coerce(self, conn, solver):
     if solver is ConnectionDefault:
         solver = Config.default(Connection, 'solver')
     solver = super().coerce(conn, solver)
     if solver is not None and solver.weights:
         raise ValidationError(
             "weight solvers only work for ensemble to "
             "ensemble connections, not probes",
             attr=self.name,
             obj=conn)
     return solver
Ejemplo n.º 30
0
 def coerce(self, instance, nengo_obj):  # pylint: disable=arguments-renamed
     nengo_objects = (
         NengoObject,
         ObjView,
         nengo.ensemble.Neurons,
         nengo.connection.LearningRule,
     )
     if not isinstance(nengo_obj, nengo_objects):
         raise ValidationError(f"'{nengo_obj}' is not a Nengo object",
                               attr=self.name,
                               obj=instance)
     if self.nonzero_size_in and nengo_obj.size_in < 1:
         raise ValidationError(f"'{nengo_obj}' must have size_in > 0.",
                               attr=self.name,
                               obj=instance)
     if self.nonzero_size_out and nengo_obj.size_out < 1:
         raise ValidationError(f"'{nengo_obj}' must have size_out > 0.",
                               attr=self.name,
                               obj=instance)
     return super().coerce(instance, nengo_obj)