Exemplo n.º 1
0
    def sample(self, n, d=None, rng=np.random):
        samples = np.array(self.samples)
        shape = (n, ) if d is None else (n, d)

        if d is None:
            samples = samples.squeeze()

        if d is not None and samples.ndim == 1:
            samples = samples[..., np.newaxis]

        if samples.shape[0] != shape[0]:
            raise ValidationError("Wrong number of samples requested; got "
                                  "%d, should be %d" % (n, samples.shape[0]),
                                  attr='samples',
                                  obj=self)
        elif d is None and len(samples.shape) != 1:
            raise ValidationError("Wrong sample dimensionality requested; got "
                                  "'None', should be %d" %
                                  (samples.shape[1], ),
                                  attr='samples',
                                  obj=self)
        elif d is not None and samples.shape[1] != shape[1]:
            raise ValidationError("Wrong sample dimensionality requested; got "
                                  "%d, should be %d" % (d, samples.shape[1]),
                                  attr='samples',
                                  obj=self)

        return samples
Exemplo n.º 2
0
    def coerce(self, instance, data):
        data = super(PiecewiseDataParam, self).coerce(instance, data)

        size_out = None
        for time, value in iteritems(data):
            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
Exemplo n.º 3
0
    def __init__(self,
                 n_filters,
                 input_shape,
                 kernel_size=(3, 3),
                 strides=(1, 1),
                 padding="valid",
                 channels_last=True,
                 init=sirsim.dists.Uniform(-1, 1)):
        super(Convolution, self).__init__()

        self.n_filters = n_filters
        self.channels_last = channels_last  # must be set before input_shape
        self.input_shape = input_shape
        self.kernel_size = kernel_size
        self.strides = strides
        self.padding = padding
        self.init = init

        if len(kernel_size) != self.dimensions:
            raise ValidationError(
                "Kernel dimensions (%d) do not match input dimensions (%d)" %
                (len(kernel_size), self.dimensions),
                attr="kernel_size")
        if len(strides) != self.dimensions:
            raise ValidationError(
                "Stride dimensions (%d) do not match input dimensions (%d)" %
                (len(strides), self.dimensions),
                attr="strides")
        if not isinstance(init, Distribution):
            if init.shape != self.kernel_shape:
                raise ValidationError(
                    "Kernel shape %s does not match expected shape %s" %
                    (init.shape, self.kernel_shape),
                    attr="init")
Exemplo n.º 4
0
    def coerce_ndarray(self, instance, ndarray):  # noqa: C901
        if isinstance(ndarray, np.ndarray):
            ndarray = ndarray.view()
        else:
            try:
                ndarray = np.array(ndarray, dtype=np.float64)
            except (ValueError, TypeError):
                raise ValidationError(
                    "Must be a float NumPy array (got type %r)"
                    % type(ndarray).__name__, attr=self.name, obj=instance)

        if self.readonly:
            ndarray.setflags(write=False)

        if self.shape is None:
            return ndarray

        if '...' in self.shape:
            # Convert '...' to the appropriate number of '*'s
            nfixed = len(self.shape) - 1
            n = ndarray.ndim - nfixed
            if n < 0:
                raise ValidationError("ndarray must be at least %dD (got %dD)"
                                      % (nfixed, ndarray.ndim),
                                      attr=self.name, obj=instance)

            i = self.shape.index('...')
            shape = list(self.shape[:i]) + (['*'] * n)
            if i < len(self.shape) - 1:
                shape.extend(self.shape[i+1:])
        else:
            shape = self.shape

        if ndarray.ndim != len(shape):
                raise ValidationError("ndarray must be %dD (got %dD)"
                                      % (len(shape), ndarray.ndim),
                                      attr=self.name, obj=instance)

        for i, attr in enumerate(shape):
            assert is_integer(attr) or is_string(attr), (
                "shape can only be an int or str representing an attribute")
            if attr == '*':
                continue

            desired = attr if is_integer(attr) else getattr(instance, attr)

            if not is_integer(desired):
                raise ValidationError(
                    "%s not yet initialized; cannot determine if shape is "
                    "correct. Consider using a distribution instead." % attr,
                    attr=self.name, obj=instance)

            if ndarray.shape[i] != desired:
                raise ValidationError("shape[%d] should be %d (got %d)"
                                      % (i, desired, ndarray.shape[i]),
                                      attr=self.name, obj=instance)
        return ndarray
Exemplo n.º 5
0
 def coerce(self, instance, value):
     if isinstance(value, DefaultType):
         raise ValidationError("Default is not a valid value. To reset a "
                               "parameter, use 'del'.",
                               attr=self.name, obj=instance)
     if self.readonly and instance in self.data:
         raise ReadonlyError(attr=self.name, obj=instance)
     if not self.optional and value is None:
         raise ValidationError("Parameter is not optional; cannot set to "
                               "None", attr=self.name, obj=instance)
     return value
Exemplo n.º 6
0
 def check_rule(self, instance, rule):
     if not isinstance(rule, LearningRuleType):
         raise ValidationError(
             "'%s' must be a learning rule type or a dict or "
             "list of such types." % rule,
             attr=self.name,
             obj=instance)
     if rule.modifies not in ('encoders', 'decoders', 'weights'):
         raise ValidationError("Unrecognized target %r" % rule.modifies,
                               attr=self.name,
                               obj=instance)
Exemplo n.º 7
0
 def coerce(self, instance, value):
     value = super(TupleParam, self).coerce(instance, value)
     try:
         value = tuple(value)
     except TypeError:
         raise ValidationError("Value must be castable to a tuple",
                               attr=self.name, obj=instance)
     if value is not None:
         if self.length is not None and len(value) != self.length:
             raise ValidationError("Must be %d items (got %d)"
                                   % (self.length, len(value)),
                                   attr=self.name, obj=instance)
     return value
Exemplo n.º 8
0
    def coerce(self, instance, value):
        value = super(ShapeParam, self).coerce(instance, value)
        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
Exemplo n.º 9
0
    def coerce(self, conn, transform):
        if not isinstance(transform, Transform):
            transform = Dense((conn.size_out, conn.size_mid), transform)

        if transform.size_in != conn.size_mid:
            if isinstance(transform, Dense) and transform.ndim < 2:
                # we provide a different error message in this case;
                # the transform is not changing the dimensionality of the
                # signal, so the blame most likely lies with the function
                raise ValidationError(
                    "Function output size is incorrect; should return a "
                    "vector of size %d" % conn.size_mid,
                    attr=self.name,
                    obj=conn)
            else:
                raise ValidationError(
                    "Transform input size (%d) not equal to %s output size "
                    "(%d)" % (transform.size_in, type(
                        conn.pre_obj).__name__, conn.size_mid),
                    attr=self.name,
                    obj=conn)

        if transform.size_out != conn.size_out:
            raise ValidationError(
                "Transform output size (%d) not equal to connection "
                "output size (%d)" % (transform.size_out, conn.size_out),
                attr=self.name,
                obj=conn)

        # we don't support repeated indices on 2D transforms because it makes
        # the matrix multiplication more complicated (we'd need to expand
        # the weight matrix for the duplicated rows/columns). it could be done
        # if there were a demand at some point.
        if isinstance(transform, Dense) and len(transform.init_shape) == 2:

            def repeated_inds(x):
                return (not isinstance(x, slice)
                        and np.unique(x).size != len(x))

            if repeated_inds(conn.pre_slice):
                raise ValidationError(
                    "Input object selection has repeated indices",
                    attr=self.name,
                    obj=conn)
            if repeated_inds(conn.post_slice):
                raise ValidationError(
                    "Output object selection has repeated indices",
                    attr=self.name,
                    obj=conn)

        return super(ConnectionTransformParam, self).coerce(conn, transform)
Exemplo n.º 10
0
 def coerce(self, conn, distorarray):
     """Eval points are only valid when pre is an ensemble."""
     if distorarray is not None and not isinstance(conn.pre, Ensemble):
         msg = ("eval_points are only valid on connections from ensembles "
                "(got type '%s')" % type(conn.pre).__name__)
         raise ValidationError(msg, attr=self.name, obj=conn)
     return super(EvalPointsParam, self).coerce(conn, distorarray)
Exemplo n.º 11
0
 def coerce(self, conn, solver):
     solver = super(ConnectionSolverParam, self).coerce(conn, solver)
     if solver is not None:
         if solver.weights and not isinstance(conn.pre_obj, Ensemble):
             raise ValidationError(
                 "weight solvers only work for connections from ensembles "
                 "(got %r)" % type(conn.pre_obj).__name__,
                 attr=self.name,
                 obj=conn)
         if solver.weights and not isinstance(conn.post_obj, Ensemble):
             raise ValidationError(
                 "weight solvers only work for connections to ensembles "
                 "(got %r)" % type(conn.post_obj).__name__,
                 attr=self.name,
                 obj=conn)
     return solver
Exemplo n.º 12
0
    def coerce(self, conn, function):
        function = super(ConnectionFunctionParam, self).coerce(conn, function)

        if function is None:
            function_info = FunctionInfo(function=None, size=None)
        elif isinstance(function, FunctionInfo):
            function_info = function
        elif is_array_like(function):
            array = np.array(function, copy=False, dtype=np.float64)
            self.check_array(conn, array)
            function_info = FunctionInfo(function=array, size=array.shape[1])
        elif callable(function):
            function_info = FunctionInfo(function=function,
                                         size=self.determine_size(
                                             conn, function))
            # TODO: necessary?
            super(ConnectionFunctionParam, self).coerce(conn, function_info)
        else:
            raise ValidationError("Invalid connection function type %r "
                                  "(must be callable or array-like)" %
                                  type(function).__name__,
                                  attr=self.name,
                                  obj=conn)

        self.check_function_can_be_applied(conn, function_info)

        return function_info
Exemplo n.º 13
0
    def add_agent_output(self):
        """Adds a node that collects the agent output of all ensembles.

        Direct agent output is useful for plotting the spike raster of
        all agents in the ensemble array.

        This node is accessible through the 'agent_output' attribute
        of this ensemble array.
        """
        if self.agent_output is not None:
            warnings.warn("agent_output already exists. Returning.")
            return self.agent_output

        if isinstance(self.ea_ensembles[0].agent_type, sirsim.Direct):
            raise ValidationError(
                "Ensembles use Direct agent type. "
                "Cannot get agent output from Direct agents.",
                attr='ea_ensembles[0].agent_type',
                obj=self)

        self.agent_output = sirsim.Node(size_in=self.n_agents_per_ensemble *
                                        self.n_ensembles,
                                        label="agent_output")

        for i, ens in enumerate(self.ea_ensembles):
            sirsim.Connection(
                ens.agents,
                self.agent_output[i * self.n_agents_per_ensemble:(i + 1) *
                                  self.n_agents_per_ensemble],
                synapse=None)
        return self.agent_output
Exemplo n.º 14
0
    def __init__(self, shape, init=1.0):
        super(Dense, self).__init__()

        self.shape = shape

        if is_array_like(init):
            init = np.asarray(init, dtype=np.float64)

            # check that the shape of init is compatible with the given shape
            # for this transform
            expected_shape = None
            if shape[0] != shape[1]:
                # init must be 2D if transform is not square
                expected_shape = shape
            elif init.ndim == 1:
                expected_shape = (shape[0], )
            elif init.ndim >= 2:
                expected_shape = shape

            if expected_shape is not None and init.shape != expected_shape:
                raise ValidationError(
                    "Shape of initial value %s does not match expected "
                    "shape %s" % (init.shape, expected_shape),
                    attr="init")

        self.init = init
Exemplo n.º 15
0
 def coerce(self, instance, sirsim_obj):
     sirsim_objects = (SirsimObject, ObjView, sirsim.ensemble.Agents,
                       sirsim.connection.LearningRule)
     if not isinstance(sirsim_obj, sirsim_objects):
         raise ValidationError("'%s' is not a Sirsim object" % sirsim_obj,
                               attr=self.name,
                               obj=instance)
     if self.nonzero_size_in and sirsim_obj.size_in < 1:
         raise ValidationError("'%s' must have size_in > 0." % sirsim_obj,
                               attr=self.name,
                               obj=instance)
     if self.nonzero_size_out and sirsim_obj.size_out < 1:
         raise ValidationError("'%s' must have size_out > 0." % sirsim_obj,
                               attr=self.name,
                               obj=instance)
     return super(SirsimObjectParam, self).coerce(instance, sirsim_obj)
Exemplo n.º 16
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)
Exemplo n.º 17
0
    def make_step(self,
                  shape_in,
                  shape_out,
                  dt,
                  rng,
                  y0=None,
                  dtype=np.float64,
                  method='zoh'):
        """Returns a `.Step` instance that implements the linear filter."""
        assert shape_in == shape_out

        num, den = self.num, self.den
        if self.analog:
            num, den, _ = cont2discrete((num, den), dt, method=method)
            num = num.flatten()

        if den[0] != 1.:
            raise ValidationError("First element of the denominator must be 1",
                                  attr='den',
                                  obj=self)
        num = num[1:] if num[0] == 0 else num
        den = den[1:]  # drop first element (equal to 1)
        num, den = num.astype(dtype), den.astype(dtype)

        output = np.zeros(shape_out, dtype=dtype)
        if len(num) == 1 and len(den) == 0:
            return LinearFilter.NoDen(num, den, output)
        elif len(num) == 1 and len(den) == 1:
            return LinearFilter.Simple(num, den, output, y0=y0)
        return LinearFilter.General(num, den, output, y0=y0)
Exemplo n.º 18
0
        def __init__(self, num, den, output, y0=None):
            if len(num) != 1:
                raise ValidationError("'num' must be length 1 (got %d)" %
                                      len(num),
                                      attr='num',
                                      obj=self)
            if len(den) != 1:
                raise ValidationError("'den' must be length 1 (got %d)" %
                                      len(den),
                                      attr='den',
                                      obj=self)

            super(LinearFilter.Simple, self).__init__(num, den, output)
            self.b = num[0]
            self.a = den[0]
            if y0 is not None:
                self.output[...] = y0
Exemplo n.º 19
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
Exemplo n.º 20
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)
Exemplo n.º 21
0
 def __init__(self, num, den, output):
     if len(den) > 0:
         raise ValidationError("'den' must be empty (got length %d)" %
                               len(den),
                               attr='den',
                               obj=self)
     super(LinearFilter.NoDen, self).__init__(num, den, output)
     self.b = num[0]
Exemplo n.º 22
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)
Exemplo n.º 23
0
 def coerce(self, conn, sirsim_obj):
     if isinstance(sirsim_obj, Connection):
         raise ValidationError(
             "Cannot connect to or from connections. "
             "Did you mean to connect to the connection's learning rule?",
             attr=self.name,
             obj=conn)
     return super(PrePostParam, self).coerce(conn, sirsim_obj)
Exemplo n.º 24
0
 def coerce(self, instance, string):
     string = super(EnumParam, self).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
Exemplo n.º 25
0
    def __init__(self,
                 n_agents,
                 n_ensembles,
                 ens_dimensions=1,
                 agent_nodes=False,
                 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(EnsembleArray, self).__init__(label, seed, add_to_container)

        for param in ens_kwargs:
            if is_iterable(ens_kwargs[param]):
                ens_kwargs[param] = sirsim.dists.Samples(ens_kwargs[param])

        self.config[sirsim.Ensemble].update(ens_kwargs)

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

        self.n_agents_per_ensemble = n_agents
        self.n_ensembles = n_ensembles
        self.dimensions_per_ensemble = ens_dimensions

        # These may be set in add_agent_input and add_agent_output
        self.agent_input, self.agent_output = None, None

        self.ea_ensembles = []

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

            for i in range(n_ensembles):
                e = sirsim.Ensemble(n_agents,
                                    self.dimensions_per_ensemble,
                                    label="%s%d" % (label_prefix, i))
                sirsim.Connection(self.input[i * ens_dimensions:(i + 1) *
                                             ens_dimensions],
                                  e,
                                  synapse=None)
                self.ea_ensembles.append(e)

        # if agent_nodes:
        #     self.add_agent_input()
        #     self.add_agent_output()
        #     warnings.warn(
        #         "'agent_nodes' argument will be removed. Use "
        #         "'add_agent_input' and 'add_agent_output' methods instead.",
        #         DeprecationWarning)

        self.add_output('output', function=None)
Exemplo n.º 26
0
    def sample(self, n, d=None, rng=np.random):
        if d is not None and self.dimensions != d:
            raise ValidationError("Options must be of dimensionality %d "
                                  "(got %d)" % (d, self.dimensions),
                                  attr='options',
                                  obj=self)

        i = np.searchsorted(np.cumsum(self.p), rng.rand(n))
        return self.options[i]
Exemplo n.º 27
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)
Exemplo n.º 28
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)
Exemplo n.º 29
0
    def coerce_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
Exemplo n.º 30
0
    def coerce(self, node, output):
        output = super(OutputParam, self).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):
            # 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.coerce_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.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("Invalid node output type %r" %
                                  type(output).__name__,
                                  attr=self.name,
                                  obj=node)

        return output