class Test: ab = ObsoleteParam("ab", "msg")
class Connection(NengoObject): """Connects two objects together. The connection between the two object is unidirectional, transmitting information from the first argument, ``pre``, to the second argument, ``post``. Almost any Nengo object can act as the pre or post side of a connection. Additionally, you can use Python slice syntax to access only some of the dimensions of the pre or post object. For example, if ``node`` has ``size_out=2`` and ``ensemble`` has ``size_in=1``, we could not create the following connection:: nengo.Connection(node, ensemble) But, we could create either of these two connections:: nengo.Connection(node[0], ensemble) nengo.Connection(node[1], ensemble) Parameters ---------- pre : Ensemble or Neurons or Node The source Nengo object for the connection. post : Ensemble or Neurons or Node or Probe The destination object for the connection. synapse : Synapse or None, optional Synapse model to use for filtering (see `~nengo.synapses.Synapse`). If *None*, no synapse will be used and information will be transmitted without any delay (if supported by the backend---some backends may introduce a single time step delay). Note that at least one connection must have a synapse that is not *None* if components are connected in a cycle. Furthermore, a synaptic filter with a zero time constant is different from a *None* synapse as a synaptic filter will always add a delay of at least one time step. function : callable or (n_eval_points, size_mid) array_like, optional Function to compute across the connection. Note that ``pre`` must be an ensemble to apply a function across the connection. If an array is passed, the function is implicitly defined by the points in the array and the provided ``eval_points``, which have a one-to-one correspondence. transform : (size_out, size_mid) array_like, optional Linear transform mapping the pre output to the post input. This transform is in terms of the sliced size; if either pre or post is a slice, the transform must be shaped according to the sliced dimensionality. Additionally, the function is applied before the transform, so if a function is computed across the connection, the transform must be of shape ``(size_out, size_mid)``. solver : Solver, optional Solver instance to compute decoders or weights (see `~nengo.solvers.Solver`). If ``solver.weights`` is True, a full connection weight matrix is computed instead of decoders. learning_rule_type : LearningRuleType or iterable of LearningRuleType, optional Modifies the decoders or connection weights during simulation. eval_points : (n_eval_points, size_in) array_like or int, optional Points at which to evaluate ``function`` when computing decoders, spanning the interval (-pre.radius, pre.radius) in each dimension. If None, will use the eval_points associated with ``pre``. scale_eval_points : bool, optional Indicates whether the evaluation points should be scaled by the radius of the pre Ensemble. label : str, optional A descriptive label for the connection. seed : int, optional The seed used for random number generation. Attributes ---------- is_decoded : bool True if and only if the connection is decoded. This will not occur when ``solver.weights`` is True or both pre and post are `~nengo.ensemble.Neurons`. function : callable The given function. function_size : int The output dimensionality of the given function. If no function is specified, function_size will be 0. label : str A human-readable connection label for debugging and visualization. If not overridden, incorporates the labels of the pre and post objects. learning_rule_type : instance or list or dict of LearningRuleType, optional The learning rule types. post : Ensemble or Neurons or Node or Probe or ObjView The given post object. post_obj : Ensemble or Neurons or Node or Probe The underlying post object, even if ``post`` is an ``ObjView``. post_slice : slice or list or None The slice associated with ``post`` if it is an ObjView, or None. pre : Ensemble or Neurons or Node or ObjView The given pre object. pre_obj : Ensemble or Neurons or Node The underlying pre object, even if ``post`` is an ``ObjView``. pre_slice : slice or list or None The slice associated with ``pre`` if it is an ObjView, or None. seed : int The seed used for random number generation. solver : Solver The Solver instance that will be used to compute decoders or weights (see ``nengo.solvers``). synapse : Synapse The Synapse model used for filtering across the connection (see ``nengo.synapses``). transform : (size_out, size_mid) array_like Linear transform mapping the pre function output to the post input. Properties ---------- size_in : int The number of output dimensions of the pre object. Also the input size of the function, if one is specified. size_mid : int The number of output dimensions of the function, if specified. If the function is not specified, then ``size_in == size_mid``. size_out : int The number of input dimensions of the post object. Also the number of output dimensions of the transform. """ probeable = ("output", "input", "weights") pre = PrePostParam("pre", nonzero_size_out=True) post = PrePostParam("post", nonzero_size_in=True) synapse = SynapseParam("synapse", default=Lowpass(tau=0.005)) function_info = ConnectionFunctionParam("function", default=None, optional=True) transform = ConnectionTransformParam("transform", default=1.0) solver = ConnectionSolverParam("solver", default=LstsqL2()) learning_rule_type = ConnectionLearningRuleTypeParam("learning_rule_type", default=None, optional=True) eval_points = EvalPointsParam("eval_points", default=None, optional=True, sample_shape=("*", "size_in")) scale_eval_points = BoolParam("scale_eval_points", default=True) modulatory = ObsoleteParam( "modulatory", "Modulatory connections have been removed. " "Connect to a learning rule instead.", since="v2.1.0", url="https://github.com/nengo/nengo/issues/632#issuecomment-71663849", ) _param_init_order = [ "pre", "post", "synapse", "eval_points", "function_info", "transform", "solver", "learning_rule_type", ] def __init__( self, pre, post, synapse=Default, function=Default, transform=Default, solver=Default, learning_rule_type=Default, eval_points=Default, scale_eval_points=Default, label=Default, seed=Default, modulatory=Unconfigurable, ): super().__init__(label=label, seed=seed) self.pre = pre self.post = post self.synapse = synapse self.eval_points = eval_points # Must be set before function self.scale_eval_points = scale_eval_points self.function_info = function self.transform = transform # Must be set after function self.solver = solver # Must be set before learning rule self.learning_rule_type = learning_rule_type # set after transform self.modulatory = modulatory def __str__(self): return self._str(include_id=False) def __repr__(self): return self._str(include_id=True) def _str(self, include_id): desc = "<Connection " if include_id: desc += "at 0x%x " % id(self) if self.label is None: desc += "from %s to %s%s" % ( self.pre, self.post, ("" if self.function is None else " computing '%s'" % (function_name(self.function))), ) else: desc += self.label desc += ">" return desc @property def function(self): return self.function_info.function @function.setter def function(self, function): self.function_info = function @property def is_decoded(self): return not (self.solver.weights or (isinstance(self.pre_obj, Neurons) and isinstance(self.post_obj, Neurons))) @property def _label(self): if self.label is not None: return self.label return "from %s to %s%s" % ( self.pre, self.post, " computing '%s'" % function_name(self.function) if self.function is not None else "", ) @property def learning_rule(self): """(LearningRule or iterable) Connectable learning rule object(s).""" if self.learning_rule_type is None: return None types = self.learning_rule_type if isinstance(types, dict): learning_rule = type(types)() # dict of same type for k, v in types.items(): learning_rule[k] = LearningRule(self, v) elif is_iterable(types): learning_rule = [LearningRule(self, v) for v in types] elif isinstance(types, LearningRuleType): learning_rule = LearningRule(self, types) else: raise ValidationError( "Invalid type %r" % type(types).__name__, attr="learning_rule_type", obj=self, ) return learning_rule @property def post_obj(self): return self.post.obj if isinstance(self.post, ObjView) else self.post @property def post_slice(self): return self.post.slice if isinstance(self.post, ObjView) else slice(None) @property def pre_obj(self): return self.pre.obj if isinstance(self.pre, ObjView) else self.pre @property def pre_slice(self): return self.pre.slice if isinstance(self.pre, ObjView) else slice(None) @property def size_in(self): """(int) The number of output dimensions of the pre object. Also the input size of the function, if one is specified. """ return self.pre.size_out @property def size_mid(self): """(int) The number of output dimensions of the function, if specified. If the function is not specified, then ``size_in == size_mid``. """ size = self.function_info.size return self.size_in if size is None else size @property def size_out(self): """(int) The number of input dimensions of the post object. Also the number of output dimensions of the transform. """ return self.post.size_in
class Connection(NengoObject): """Connects two objects together. The connection between the two object is unidirectional, transmitting information from the first argument, ``pre``, to the second argument, ``post``. Almost any Nengo object can act as the pre or post side of a connection. Additionally, you can use Python slice syntax to access only some of the dimensions of the pre or post object. For example, if ``node`` has ``size_out=2`` and ``ensemble`` has ``size_in=1``, we could not create the following connection:: nengo.Connection(node, ensemble) But, we could create either of these two connections:: nengo.Connection(node[0], ensemble) nengo.Connection(node[1], ensemble) Parameters ---------- pre : Ensemble or Neurons or Node The source Nengo object for the connection. post : Ensemble or Neurons or Node or Probe The destination object for the connection. synapse : Synapse, optional \ (Default: ``nengo.synapses.Lowpass(tau=0.005)``) Synapse model to use for filtering (see `~nengo.synapses.Synapse`). function : callable, optional (Default: None) Function to compute across the connection. Note that ``pre`` must be an ensemble to apply a function across the connection. transform : (post.size_in, pre.size_out) array_like, optional \ (Default: ``np.array(1.0)``) Linear transform mapping the pre output to the post input. This transform is in terms of the sliced size; if either pre or post is a slice, the transform must be shaped according to the sliced dimensionality. Additionally, the function is applied before the transform, so if a function is computed across the connection, the transform must be of shape ``(len(function(np.zeros(post.size_in))), pre.size_out)``. solver : Solver, optional (Default: ``nengo.solvers.LstsqL2()``) Solver instance to compute decoders or weights (see `~nengo.solvers.Solver`). If ``solver.weights`` is True, a full connection weight matrix is computed instead of decoders. learning_rule_type : LearningRuleType or iterable of LearningRuleType, \ optional (Default: None) Modifies the decoders or connection weights during simulation. eval_points : (n_eval_points, pre.size_out) array_like or int, optional \ (Default: None) Points at which to evaluate ``function`` when computing decoders, spanning the interval (-pre.radius, pre.radius) in each dimension. If None, will use the eval_points associated with ``pre``. scale_eval_points : bool, optional (Default: True) Indicates whether the evaluation points should be scaled by the radius of the pre Ensemble. label : str, optional (Default: None) A descriptive label for the connection. seed : int, optional (Default: None) The seed used for random number generation. Attributes ---------- is_decoded : bool True if and only if the connection is decoded. This will not occur when ``solver.weights`` is True or both pre and post are `~nengo.ensemble.Neurons`. function : callable The given function. function_size : int The output dimensionality of the given function. If no function is specified, function_size will be 0. label : str A human-readable connection label for debugging and visualization. If not overridden, incorporates the labels of the pre and post objects. learning_rule_type : instance or list or dict of LearningRuleType, optional The learning rule types. post : Ensemble or Neurons or Node or Probe or ObjView The given post object. post_obj : Ensemble or Neurons or Node or Probe The underlying post object, even if ``post`` is an ``ObjView``. post_slice : slice or list or None The slice associated with ``post`` if it is an ObjView, or None. pre : Ensemble or Neurons or Node or ObjView The given pre object. pre_obj : Ensemble or Neurons or Node The underlying pre object, even if ``post`` is an ``ObjView``. pre_slice : slice or list or None The slice associated with ``pre`` if it is an ObjView, or None. seed : int The seed used for random number generation. solver : Solver The Solver instance that will be used to compute decoders or weights (see ``nengo.solvers``). synapse : Synapse The Synapse model used for filtering across the connection (see ``nengo.synapses``). transform : (size_mid, size_out) array_like Linear transform mapping the pre function output to the post input. """ probeable = ('output', 'input', 'weights') pre = PrePostParam('pre', nonzero_size_out=True) post = PrePostParam('post', nonzero_size_in=True) synapse = SynapseParam('synapse', default=Lowpass(tau=0.005)) function_info = ConnectionFunctionParam('function', default=None, optional=True) transform = TransformParam('transform', default=np.array(1.0)) solver = ConnectionSolverParam('solver', default=LstsqL2()) learning_rule_type = ConnectionLearningRuleTypeParam('learning_rule_type', default=None, optional=True) eval_points = EvalPointsParam('eval_points', default=None, optional=True, sample_shape=('*', 'size_in')) scale_eval_points = BoolParam('scale_eval_points', default=True) modulatory = ObsoleteParam( 'modulatory', "Modulatory connections have been removed. " "Connect to a learning rule instead.", since="v2.1.0", url="https://github.com/nengo/nengo/issues/632#issuecomment-71663849") def __init__(self, pre, post, synapse=Default, function=Default, transform=Default, solver=Default, learning_rule_type=Default, eval_points=Default, scale_eval_points=Default, label=Default, seed=Default, modulatory=Unconfigurable): super(Connection, self).__init__(label=label, seed=seed) self.pre = pre self.post = post self.synapse = synapse self.transform = transform self.scale_eval_points = scale_eval_points self.eval_points = eval_points # Must be set before function self.function_info = function # Must be set after transform self.solver = solver # Must be set before learning rule self.learning_rule_type = learning_rule_type # set after transform self.modulatory = modulatory def __str__(self): return "<Connection %s>" % self._str def __repr__(self): return "<Connection at 0x%x %s>" % (id(self), self._str) @property def _str(self): if self.label is not None: return self.label desc = "" if self.function is None else " computing '%s'" % (getattr( self.function, '__name__', str(self.function))) return "from %s to %s%s" % (self.pre, self.post, desc) @property def function(self): return self.function_info.function @function.setter def function(self, function): self.function_info = function @property def is_decoded(self): return not (self.solver.weights or (isinstance(self.pre_obj, Neurons) and isinstance(self.post_obj, Neurons))) @property def _label(self): if self.label is not None: return self.label return "from %s to %s%s" % (self.pre, self.post, " computing '%s'" % self.function.__name__ if self.function is not None else "") @property def learning_rule(self): """(LearningRule or iterable) Connectable learning rule object(s).""" if self.learning_rule_type is not None and self._learning_rule is None: types = self.learning_rule_type if isinstance(types, dict): self._learning_rule = types.__class__() # dict of same type for k, v in iteritems(types): self._learning_rule[k] = LearningRule(self, v) elif is_iterable(types): self._learning_rule = [LearningRule(self, v) for v in types] elif isinstance(types, LearningRuleType): self._learning_rule = LearningRule(self, types) else: raise ValidationError("Invalid type %r" % types.__class__.__name__, attr='learning_rule_type', obj=self) return self._learning_rule @property def post_obj(self): return self.post.obj if isinstance(self.post, ObjView) else self.post @property def post_slice(self): return (self.post.slice if isinstance(self.post, ObjView) else slice(None)) @property def pre_obj(self): return self.pre.obj if isinstance(self.pre, ObjView) else self.pre @property def pre_slice(self): return self.pre.slice if isinstance(self.pre, ObjView) else slice(None) @property def size_in(self): """(int) The number of output dimensions of the pre object. Also the input size of the function, if one is specified. """ return self.pre.size_out @property def size_mid(self): """(int) The number of output dimensions of the function, if specified. If the function is not specified, then ``size_in == size_mid``. """ size = self.function_info.size return self.size_in if size is None else size @property def size_out(self): """(int) The number of input dimensions of the post object. Also the number of output dimensions of the transform. """ return self.post.size_in
class Connection(NengoObject): """Connects two objects together. Almost any Nengo object can act as the pre or post side of a connection. Additionally, you can use Python slice syntax to access only some of the dimensions of the pre or post object. For example, if ``node`` has ``size_out=2`` and ``ensemble`` has ``size_in=1``, we could not create the following connection:: nengo.Connection(node, ensemble) But, we could create either of these two connections. nengo.Connection(node[0], ensemble) nengo.Connection(ndoe[1], ensemble) Parameters ---------- pre : Ensemble or Neurons or Node The source Nengo object for the connection. post : Ensemble or Neurons or Node or Probe The destination object for the connection. label : string A descriptive label for the connection. dimensions : int The number of output dimensions of the pre object, including `function`, but not including `transform`. eval_points : (n_eval_points, pre_size) array_like or int Points at which to evaluate `function` when computing decoders, spanning the interval (-pre.radius, pre.radius) in each dimension. synapse : float, optional Post-synaptic time constant (PSTC) to use for filtering. transform : (post_size, pre_size) array_like, optional Linear transform mapping the pre output to the post input. This transform is in terms of the sliced size; if either pre or post is a slice, the transform must be of shape (len(pre_slice), len(post_slice)). solver : Solver Instance of a Solver class to compute decoders or weights (see `nengo.solvers`). If solver.weights is True, a full connection weight matrix is computed instead of decoders. function : callable, optional Function to compute using the pre population (pre must be Ensemble). eval_points : (n_eval_points, pre_size) array_like or int, optional Points at which to evaluate `function` when computing decoders, spanning the interval (-pre.radius, pre.radius) in each dimension. scale_eval_points : bool Indicates whether the eval_points should be scaled by the radius of the pre Ensemble. Defaults to True. learning_rule_type : instance or list or dict of LearningRuleType, optional Methods of modifying the connection weights during simulation. Attributes ---------- dimensions : int The number of output dimensions of the pre object, including `function`, but before applying the `transform`. function : callable The given function. function_size : int The output dimensionality of the given function. Defaults to 0. label : str A human-readable connection label for debugging and visualization. Incorporates the labels of the pre and post objects. learning_rule : LearningRule or collection of LearningRule The LearningRule objects corresponding to `learning_rule_type`, and in the same format. Use these to probe the learning rules. learning_rule_type : instance or list or dict of LearningRuleType, optional The learning rule types. post : Ensemble or Neurons or Node or Probe The given pre object. pre : Ensemble or Neurons or Node The given pre object. transform : (post_size, pre_size) array_like Linear transform mapping the pre output to the post input. seed : int The seed used for random number generation. """ pre = NengoObjectParam(nonzero_size_out=True) post = NengoObjectParam(nonzero_size_in=True) synapse = SynapseParam(default=Lowpass(0.005)) transform = TransformParam(default=np.array(1.0)) solver = ConnectionSolverParam(default=LstsqL2()) function_info = ConnectionFunctionParam(default=None, optional=True) learning_rule_type = ConnectionLearningRuleTypeParam( default=None, optional=True) eval_points = EvalPointsParam( default=None, optional=True, sample_shape=('*', 'size_in')) scale_eval_points = BoolParam(default=True) seed = IntParam(default=None, optional=True) modulatory = ObsoleteParam("Modulatory connections have been removed. " "Connect to a learning rule instead.", "https://github.com/nengo/nengo/issues/632" "#issuecomment-71663849") def __init__(self, pre, post, synapse=Default, transform=Default, solver=Default, learning_rule_type=Default, function=Default, eval_points=Default, scale_eval_points=Default, seed=Default, modulatory=Unconfigurable): self.pre = pre self.post = post self.solver = solver # Must be set before learning rule self.learning_rule_type = learning_rule_type self.synapse = synapse self.transform = transform self.scale_eval_points = scale_eval_points self.eval_points = eval_points # Must be set before function self.function_info = function # Must be set after transform self.seed = seed self.modulatory = modulatory @property def function(self): return self.function_info.function @function.setter def function(self, function): self.function_info = function @property def probeable(self): probeables = ["output", "input", "transform"] if isinstance(self.pre, Ensemble): probeables += ["decoders"] return probeables @property def pre_obj(self): return self.pre.obj if isinstance(self.pre, ObjView) else self.pre @property def pre_slice(self): return self.pre.slice if isinstance(self.pre, ObjView) else slice(None) @property def post_obj(self): return self.post.obj if isinstance(self.post, ObjView) else self.post @property def post_slice(self): return (self.post.slice if isinstance(self.post, ObjView) else slice(None)) @property def size_in(self): """Output size of sliced `pre`; input size of the function.""" return self.pre.size_out @property def size_mid(self): """Output size of the function; input size of the transform. If the function is None, then `size_in == size_mid`. """ size = self.function_info.size return self.size_in if size is None else size @property def size_out(self): """Output size of the transform; input size to the sliced post.""" return self.post.size_in @property def _label(self): return "from %s to %s%s" % ( self.pre, self.post, " computing '%s'" % self.function.__name__ if self.function is not None else "") def __str__(self): return "<Connection %s>" % self._label def __repr__(self): return "<Connection at 0x%x %s>" % (id(self), self._label) @property def learning_rule(self): if self.learning_rule_type is not None and self._learning_rule is None: types = self.learning_rule_type if isinstance(types, dict): self._learning_rule = types.__class__() # dict of same type for k, v in iteritems(types): self._learning_rule[k] = LearningRule(self, v) elif is_iterable(types): self._learning_rule = [LearningRule(self, v) for v in types] elif isinstance(types, LearningRuleType): self._learning_rule = LearningRule(self, types) else: raise ValueError("Invalid type for `learning_rule_type`: %s" % (types.__class__.__name__)) return self._learning_rule