def validate(self, instance, ndarray): ndim = len(self.shape) try: ndarray = np.asarray(ndarray, dtype=np.float64) except TypeError: raise ValueError("Must be a float NumPy array (got type '%s')" % ndarray.__class__.__name__) if ndarray.ndim != ndim: raise ValueError("ndarray must be %dD (got %dD)" % (ndim, ndarray.ndim)) for i, attr in enumerate(self.shape): assert is_integer(attr) or is_string(attr), ( "shape can only be an int or str representing an attribute") if attr == '*': continue if is_integer(attr): desired = attr elif is_string(attr): desired = getattr(instance, attr) if ndarray.shape[i] != desired: raise ValueError("shape[%d] should be %d (got %d)" % (i, desired, ndarray.shape[i])) return ndarray
def validate(self, instance, ndarray): ndim = len(self.shape) try: ndarray = np.asarray(ndarray, dtype=np.float64) except TypeError: raise ValueError("Must be a float NumPy array (got type '%s')" % ndarray.__class__.__name__) if ndarray.ndim != ndim: raise ValueError("ndarray must be %dD (got %dD)" % (ndim, ndarray.ndim)) for i, attr in enumerate(self.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 ValueError("%s not yet initialized; cannot determine " "if shape is correct. Consider using a " "distribution instead." % attr) if ndarray.shape[i] != desired: raise ValueError("shape[%d] should be %d (got %d)" % (i, desired, ndarray.shape[i])) return ndarray
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
def validate(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)" % ndarray.__class__.__name__, attr=self.name, obj=instance, ) if self.readonly: ndarray.setflags(write=False) 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
def validate(self, instance, ndarray): # noqa: C901 if isinstance(ndarray, np.ndarray): ndarray = ndarray.view() else: try: ndarray = np.array(ndarray, dtype=np.float64) except TypeError: raise ValueError( "Must be a float NumPy array (got type '%s')" % ndarray.__class__.__name__) if self.readonly: ndarray.setflags(write=False) if '...' in self.shape: nfixed = len(self.shape) - 1 n = ndarray.ndim - nfixed if n < 0: raise ValueError("ndarray must be at least %dD (got %dD)" % (nfixed, ndarray.ndim)) 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 ValueError("ndarray must be %dD (got %dD)" % (len(shape), ndarray.ndim)) 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 ValueError("%s not yet initialized; cannot determine " "if shape is correct. Consider using a " "distribution instead." % attr) if ndarray.shape[i] != desired: raise ValueError("shape[%d] should be %d (got %d)" % (i, desired, ndarray.shape[i])) return ndarray
def __init__( self, dimensions, strict=True, max_similarity=0.1, pointer_gen=None, name=None, algebra=None): if algebra is None: algebra = HrrAlgebra() self.algebra = algebra if not is_integer(dimensions) or dimensions < 1: raise ValidationError("dimensions must be a positive integer", attr='dimensions', obj=self) if pointer_gen is None: pointer_gen = UnitLengthVectors(dimensions) elif isinstance(pointer_gen, np.random.RandomState): pointer_gen = UnitLengthVectors(dimensions, pointer_gen) if not is_iterable(pointer_gen) or is_string(pointer_gen): raise ValidationError( "pointer_gen must be iterable or RandomState", attr='pointer_gen', obj=self) self.dimensions = dimensions self.strict = strict self.max_similarity = max_similarity self._key2idx = {} self._keys = [] self._vectors = np.zeros((0, dimensions), dtype=float) self.pointer_gen = pointer_gen self.name = name
def __init__(self, dimensions, randomize=True, unitary=False, max_similarity=0.1, include_pairs=False, rng=None): if not is_integer(dimensions) or dimensions < 1: raise ValidationError("dimensions must be a positive integer", attr='dimensions', obj=self) self.dimensions = dimensions self.randomize = randomize self.unitary = unitary self.max_similarity = max_similarity self.pointers = {} self.keys = [] self.key_pairs = None self.vectors = np.zeros((0, dimensions), dtype=float) self.vector_pairs = None self._include_pairs = None self.include_pairs = include_pairs self._identity = None self.rng = rng self.readonly = False self.parent = None
def __init__(self, obj, key=slice(None)): self.obj = obj # Node.size_in != size_out, so one of these can be invalid # NumPy <= 1.8 raises a ValueError instead of an IndexError. try: self.size_in = np.arange(self.obj.size_in)[key].size except (IndexError, ValueError): self.size_in = None try: self.size_out = np.arange(self.obj.size_out)[key].size except (IndexError, ValueError): self.size_out = None if self.size_in is None and self.size_out is None: raise IndexError("Invalid slice '%s' of %s" % (key, self.obj)) if is_integer(key): # single slices of the form [i] should be cast into # slice objects for convenience if key == -1: # special case because slice(-1, 0) gives the empty list self.slice = slice(key, None) else: self.slice = slice(key, key + 1) else: self.slice = key
def __init__(self, dimensions, randomize=True, unitary=False, max_similarity=0.1, include_pairs=False, rng=None): if not is_integer(dimensions): raise TypeError('dimensions must be an integer') if dimensions < 1: raise ValueError('dimensions must be positive') self.dimensions = dimensions self.randomize = randomize self.unitary = unitary self.max_similarity = max_similarity self.pointers = {} self.keys = [] self.key_pairs = None self.vectors = np.zeros((0, dimensions), dtype=float) self.vector_pairs = None self._include_pairs = None self.include_pairs = include_pairs self._identity = None self.rng = rng
def __init__( self, stim_provider, items, contexts, n_pos, rng=None, extra_pos=3): super(Vocabularies, self).__init__() vocabs = Config.default(spa.Network, 'vocabs') if vocabs is None: vocabs = VocabularyMap(rng=rng) self.vocabs = vocabs self.items = items if is_integer(contexts): contexts = spa.Vocabulary(contexts, rng=rng) self.contexts = contexts self.positions = spa.Vocabulary(self.items.dimensions, rng=rng) self.items.populate(';'.join(stim_provider.get_all_items())) if stim_provider.n_distractors_per_epoch > 0: self.items.populate(';'.join(stim_provider.get_all_distractors())) for i in range(self.items.dimensions): self.contexts.populate('CTX' + str(i)) for i in range(n_pos + extra_pos): self.positions.populate('P' + str(i))
def __init__(self, obj, key=slice(None)): self.obj = obj if is_integer(key): # single slices of the form [i] should be cast into # slice objects for convenience if key == -1: # special case because slice(-1, 0) gives the empty list key = slice(key, None) else: key = slice(key, key + 1) self.slice = key # Node.size_in != size_out, so one of these can be invalid try: self.size_in = np.arange(self.obj.size_in)[self.slice].size except IndexError: self.size_in = None try: self.size_out = np.arange(self.obj.size_out)[self.slice].size except IndexError: self.size_out = None if self.size_in is None and self.size_out is None: raise ValidationError("Invalid slice '%s' of %s" % (self.slice, self.obj), attr='key')
def validate(self, instance, ndarray): # noqa: C901 if isinstance(ndarray, np.ndarray): ndarray = ndarray.view() else: try: ndarray = np.array(ndarray, dtype=np.float64) except TypeError: raise ValueError("Must be a float NumPy array (got type '%s')" % ndarray.__class__.__name__) if self.readonly: ndarray.setflags(write=False) if '...' in self.shape: nfixed = len(self.shape) - 1 n = ndarray.ndim - nfixed if n < 0: raise ValueError("ndarray must be at least %dD (got %dD)" % (nfixed, ndarray.ndim)) 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 ValueError("ndarray must be %dD (got %dD)" % (len(shape), ndarray.ndim)) 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 ValueError("%s not yet initialized; cannot determine " "if shape is correct. Consider using a " "distribution instead." % attr) if ndarray.shape[i] != desired: raise ValueError("shape[%d] should be %d (got %d)" % (i, desired, ndarray.shape[i])) return ndarray
def sample(self, n, d=1, rng=np.random): """Samples ``n`` points in ``d`` dimensions.""" if d == 1: # Tile the points optimally. TODO: refactor return np.linspace(1. / n, 1, n)[:, None] if d is None or not is_integer(d) or d < 1: # TODO: this should be raised when the ensemble is created raise ValueError("d (%d) must be positive integer" % d) return _rd_generate(n, d)
def validate(self, instance, value): super(ShapeParam, self).validate(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)
def __pow__(self, other): if not is_integer(other): return NotImplemented n, d = self.tf if other > 0: return LinearSystem(normalize(n**other, d**other), self.analog) elif other < 0: return LinearSystem(normalize(d**-other, n**-other), self.analog) else: assert other == 0 return LinearSystem(1., self.analog)
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)
def BoxFilter(width, normalized=True): """A discrete box-filter with a given ``width``, and optionally unit area. This filter is also known as a "box blur", and has the effect of smoothing out the input signal by taking its rolling mean over a finite number of time-steps. Its properties are qualitatively similar to the continuous-time :func:`.Lowpass`. Parameters ---------- width : ``integer`` Width of the box-filter (in time-steps). normalized : ``boolean``, optional If ``True``, then the height of the box-filter is ``1/width``, otherwise ``1``. Defaults to ``True``. Returns ------- sys : :class:`.LinearSystem` Digital system implementing the box-filter. See Also -------- :attr:`.z` :func:`.Lowpass` Examples -------- Simulate a Nengo network using a box filter of 10 ms for a synapse: >>> from nengolib.synapses import BoxFilter >>> import nengo >>> with nengo.Network() as model: >>> stim = nengo.Node(output=lambda _: np.random.randn(1)) >>> p_stim = nengo.Probe(stim) >>> p_box = nengo.Probe(stim, synapse=BoxFilter(10)) >>> with nengo.Simulator(model) as sim: >>> sim.run(.1) >>> import matplotlib.pyplot as plt >>> plt.step(sim.trange(), sim.data[p_stim], label="Noisy Input", alpha=.5) >>> plt.step(sim.trange(), sim.data[p_box], label="Box-Filtered") >>> plt.xlabel("Time (s)") >>> plt.legend() >>> plt.show() """ if not is_integer(width) or width <= 0: raise ValueError("width (%s) must be positive integer" % (width, )) den = DiscreteDelay(width - 1) amplitude = 1. / width if normalized else 1. # 1 + 1/z + ... + 1/z^(steps) = (z^steps + z^(steps-1) + ... + 1)/z^steps return amplitude * sum(z**k for k in range(width)) * den
def sample(self, num, d=None, rng=np.random): num, d = self._sample_shape(num, d) if d == 1: # Tile the points optimally. TODO: refactor return np.linspace(1./num, 1, num)[:, None] if d is None or not is_integer(d) or d < 1: # TODO: this should be raised when the ensemble is created raise ValueError("d (%d) must be positive integer" % d) if d > 40: warnings.warn("i4_sobol_generate does not support d > 40; " "falling back to monte-carlo method", UserWarning) return np.random.uniform(size=(num, d)) return i4_sobol_generate(d, num, skip=0)
def DiscreteDelay(steps): """A discrete (pure) time-delay: ``z**-steps``. Also equivalent to ``(~z)**steps`` or ``1/z**steps``. Parameters ---------- steps : ``integer`` Number of time-steps to delay the input signal. Returns ------- sys : :class:`.LinearSystem` Digital filter implementing the pure delay exactly. See Also -------- :attr:`.z` :func:`.PadeDelay` Notes ----- A single step of the delay will be removed if using the ``filt`` method. This is done for subtle reasons of consistency with Nengo. The correct delay will appear when passed to :class:`nengo.Connection`. Examples -------- Simulate a Nengo network using a discrete delay of half a second for a synapse: >>> from nengolib.synapses import DiscreteDelay >>> import nengo >>> with nengo.Network() as model: >>> stim = nengo.Node(output=lambda t: np.sin(2*np.pi*t)) >>> p_stim = nengo.Probe(stim) >>> p_delay = nengo.Probe(stim, synapse=DiscreteDelay(500)) >>> with nengo.Simulator(model) as sim: >>> sim.run(1.) >>> import matplotlib.pyplot as plt >>> plt.plot(sim.trange(), sim.data[p_stim], label="Stimulus") >>> plt.plot(sim.trange(), sim.data[p_delay], label="Delayed") >>> plt.xlabel("Time (s)") >>> plt.legend() >>> plt.show() """ if not is_integer(steps) or steps < 0: raise ValueError("steps (%s) must be non-negative integer" % (steps, )) return z**-steps
def __init__(self, data, rng=None): if is_integer(data): if data < 1: raise Exception("number of dimensions must be a positive int") self.randomize(data, rng=rng) else: try: len(data) except: raise Exception("Must specify either the data or the length " "for a SemanticPointer.") self.v = np.array(data, dtype=float) if len(self.v.shape) != 1: raise Exception("data must be a vector")
def sample(self, n, d=1, rng=np.random): """Samples ``n`` points in ``d`` dimensions.""" if d == 1: # Tile the points optimally. TODO: refactor return np.linspace(1. / n, 1, n)[:, None] if d is None or not is_integer(d) or d < 1: # TODO: this should be raised when the ensemble is created raise ValueError("d (%d) must be positive integer" % d) if d > 40: warnings.warn( "i4_sobol_generate does not support d > 40; " "falling back to Monte Carlo method", UserWarning) return rng.uniform(size=(n, d)) return i4_sobol_generate(d, n, skip=0)
def Highpass(tau, order=1): """A differentiated lowpass of given order: ``(tau*s/(tau*s + 1))**order``. Equivalent to differentiating the input, scaling by ``tau``, lowpass filtering with time-constant ``tau``, and finally repeating this ``order`` times. The lowpass filter is required to make this causal. Parameters ---------- tau : ``float`` Time-constant of the lowpass filter, and highpass gain. order : ``integer``, optional Dimension of the resulting linear system. Defaults to ``1``. Returns ------- sys : :class:`.LinearSystem` Highpass filter with time-constant ``tau`` and dimension ``order``. See Also -------- :func:`.Lowpass` :attr:`.s` Examples -------- >>> from nengolib.synapses import Highpass Evaluate the highpass in the frequency domain with a time-constant of 10 ms and with a variety of orders: >>> tau = 1e-2 >>> orders = list(range(1, 9)) >>> freqs = np.linspace(0, 50, 100) # to evaluate >>> import matplotlib.pyplot as plt >>> plt.title(r"$\\tau=%s$" % tau) >>> for order in orders: >>> sys = Highpass(tau, order) >>> assert len(sys) == order >>> plt.plot(freqs, np.abs(sys.evaluate(freqs)), >>> label=r"order=%s" % order) >>> plt.xlabel("Frequency (Hz)") >>> plt.legend() >>> plt.show() """ if order < 1 or not is_integer(order): raise ValueError("order (%s) must be integer >= 1" % order) return (tau * s * Lowpass(tau))**order
def coerce(self, instance, value): value = super(VocabularyOrDimParam, self).coerce(instance, value) if value is not None: if is_integer(value): if value < 1: raise ValidationError( "Vocabulary dimensionality must be at least 1.", attr=self.name, obj=instance) value = instance.vocabs.get_or_create(value) elif not isinstance(value, Vocabulary): raise ValidationError( "Must be of type 'Vocabulary' or an integer (got type %r)." % type(value).__name__, attr=self.name, obj=instance) return value
def __getitem__(self, item): """Index or slice into array""" if not isinstance(item, tuple): item = (item, ) if not all(is_integer(i) or isinstance(i, slice) for i in item): raise SignalError("Can only index or slice into signals") if all(map(is_integer, item)): # turn one index into slice to get a view from numpy item = item[:-1] + (slice(item[-1], item[-1] + 1), ) return Signal(self._initial_value[item], name="%s[%s]" % (self.name, item), base=self.base)
def __getitem__(self, item): """Index or slice into array""" if not isinstance(item, tuple): item = (item,) if not all(is_integer(i) or isinstance(i, slice) for i in item): raise SignalError("Can only index or slice into signals") if all(map(is_integer, item)): # turn one index into slice to get a view from numpy item = item[:-1] + (slice(item[-1], item[-1]+1),) return Signal(self._initial_value[item], name="%s[%s]" % (self.name, item), base=self.base)
def __init__(self, data, rng=None): if is_integer(data): if data < 1: raise ValidationError("Number of dimensions must be a " "positive int", attr='data', obj=self) self.randomize(data, rng=rng) else: try: len(data) except: raise ValidationError( "Must specify either the data or the length for a " "SemanticPointer.", attr='data', obj=self) self.v = np.array(data, dtype=float) if len(self.v.shape) != 1: raise ValidationError("'data' must be a vector", 'data', self)
def __init__(self, dimensions, randomize=True, unitary=False, max_similarity=0.1, include_pairs=False, rng=None): if not is_integer(dimensions): raise TypeError("dimensions must be an integer") if dimensions < 1: raise ValueError("dimensions must be positive") self.dimensions = dimensions self.randomize = randomize self.unitary = unitary self.max_similarity = max_similarity self.pointers = {} self.keys = [] self.key_pairs = None self.vectors = np.zeros((0, dimensions), dtype=float) self.vector_pairs = None self._include_pairs = None self.include_pairs = include_pairs self._identity = None self.rng = rng
def __getitem__(self, item): """Index or slice into array""" if item is Ellipsis or ( isinstance(item, slice) and item == slice(None)): return self if not isinstance(item, tuple): item = (item,) if not all(is_integer(i) or isinstance(i, slice) for i in item): raise SignalError("Can only index or slice into signals") if all(map(is_integer, item)): # turn one index into slice to get a view from numpy item = item[:-1] + (slice(item[-1], item[-1]+1),) view = self._initial_value[item] offset = (npext.array_offset(view) - npext.array_offset(self._initial_value)) return Signal(view, name="%s[%s]" % (self.name, item), base=self.base, offset=offset)
def one_hot_from_labels(labels, classes=None, dtype=float): """Turn integer labels into a one-hot encoding. Parameters ========== labels : (n,) array Labels to turn into one-hot encoding. classes : int or (n_classes,) array (optional) Classes for encoding. If integer and ``labels.dtype`` is integer, this is the number of classes in the encoding. If iterable, this is the list of classes to place in the one-hot (must be a superset of the unique elements in ``labels``). dtype : dtype (optional) Data type of returned one-hot encoding (defaults to ``float``). """ assert labels.ndim == 1 n = labels.shape[0] if np.issubdtype(labels.dtype, np.integer) and (classes is None or is_integer(classes)): index = labels index_min, index_max = index.min(), index.max() n_classes = (index_max + 1) if classes is None else classes assert index_min >= 0 assert index_max < n_classes else: if classes is not None: assert is_iterable(classes) assert set(np.unique(labels)).issubset(classes) classes = np.unique(labels) if classes is None else classes n_classes = len(classes) c_index = np.argsort(classes) c_sorted = classes[c_index] index = c_index[np.searchsorted(c_sorted, labels)] y = np.zeros((n, n_classes), dtype=dtype) y[np.arange(n), index] = 1 return y
def __init__(self, obj, key=slice(None)): self.obj = obj if is_integer(key): # single slices of the form [i] should be cast into # slice objects for convenience if key == -1: # special case because slice(-1, 0) gives the empty list key = slice(key, None) else: key = slice(key, key+1) self.slice = key # Node.size_in != size_out, so one of these can be invalid try: self.size_in = np.arange(self.obj.size_in)[self.slice].size except IndexError: self.size_in = None try: self.size_out = np.arange(self.obj.size_out)[self.slice].size except IndexError: self.size_out = None if self.size_in is None and self.size_out is None: raise ValidationError("Invalid slice '%s' of %s" % (self.slice, self.obj), attr='key')
def build_connection(conn, model): # noqa: C901 rng = np.random.RandomState(model.next_seed()) model.sig_in[conn] = model.sig_out[conn.pre] model.sig_out[conn] = model.sig_in[conn.post] decoders = None eval_points = None solver_info = None transform = np.array(conn.transform_full, dtype=np.float64) # Figure out the signal going across this connection if (isinstance(conn.pre, nengo.Ensemble) and isinstance(conn.pre.neurons, nengo.Direct)): # Decoded connection in directmode if conn.function is None: signal = model.sig_in[conn] else: sig_in, signal = build_pyfunc(fn=conn.function, t_in=False, n_in=model.sig_in[conn].size, n_out=conn.dimensions, label=conn.label, model=model) model.operators.append( DotInc(model.sig_in[conn], Signal(1.0, name="1"), sig_in, tag="%s input" % conn.label)) elif isinstance(conn.pre, nengo.Ensemble): # Normal decoded connection encoders = model.params[conn.pre].encoders gain = model.params[conn.pre.neurons].gain bias = model.params[conn.pre.neurons].bias eval_points = conn.eval_points if eval_points is None: eval_points = npext.array(model.params[conn.pre].eval_points, min_dims=2) elif is_integer(eval_points): eval_points = pick_eval_points(ens=conn.pre, n_points=eval_points, rng=rng) else: eval_points = npext.array(eval_points, min_dims=2) x = np.dot(eval_points, encoders.T / conn.pre.radius) activities = model.dt * conn.pre.neurons.rates(x, gain, bias) if np.count_nonzero(activities) == 0: raise RuntimeError( "In '%s', for '%s', 'activites' matrix is all zero. " "This is because no evaluation points fall in the firing " "ranges of any neurons." % (str(conn), str(conn.pre))) if conn.function is None: targets = eval_points else: targets = np.zeros((len(eval_points), conn.function_size)) for i, ep in enumerate(eval_points): targets[i] = conn.function(ep) if conn.weight_solver is not None: if conn.decoder_solver is not None: raise ValueError("Cannot specify both 'weight_solver' " "and 'decoder_solver'.") # account for transform targets = np.dot(targets, transform.T) transform = np.array(1., dtype=np.float64) decoders, solver_info = conn.weight_solver( activities, targets, rng=rng, E=model.params[conn.post].scaled_encoders.T) model.sig_out[conn] = model.sig_in[conn.post.neurons] signal_size = model.sig_out[conn].size else: solver = (conn.decoder_solver if conn.decoder_solver is not None else nengo.decoders.lstsq_L2nz) decoders, solver_info = solver(activities, targets, rng=rng) signal_size = conn.dimensions # Add operator for decoders and filtering decoders = decoders.T if conn.synapse is not None and conn.synapse > model.dt: decay = decay_coef(pstc=conn.synapse, dt=model.dt) decoder_signal = Signal(decoders * (1.0 - decay), name="%s.decoders * (1 - decay)" % conn.label) else: decoder_signal = Signal(decoders, name="%s.decoders" % conn.label) decay = 0 signal = Signal(np.zeros(signal_size), name=conn.label) model.operators.append( ProdUpdate(decoder_signal, model.sig_in[conn], Signal(decay, name="decay"), signal, tag="%s decoding" % conn.label)) else: # Direct connection signal = model.sig_in[conn] # Add operator for filtering (in the case filter wasn't already # added, when pre.neurons is a non-direct Ensemble) if decoders is None and conn.synapse is not None: # Note: we add a filter here even if synapse < dt, # in order to avoid cycles in the op graph. If the filter # is explicitly set to None (e.g. for a passthrough node) # then cycles can still occur. signal = filtered_signal(signal, conn.synapse, model=model) if conn.modulatory: # Make a new signal, effectively detaching from post model.sig_out[conn] = Signal(np.zeros(model.sig_out[conn].size), name="%s.mod_output" % conn.label) # Add reset operator? # TODO: add unit test # Add operator for transform if isinstance(conn.post, nengo.objects.Neurons): if not model.has_built(conn.post): # Since it hasn't been built, it wasn't added to the Network, # which is most likely because the Neurons weren't associated # with an Ensemble. raise RuntimeError("Connection '%s' refers to Neurons '%s' " "that are not a part of any Ensemble." % (conn, conn.post)) transform *= model.params[conn.post].gain[:, np.newaxis] model.operators.append( DotInc(Signal(transform, name="%s.transform" % conn.label), signal, model.sig_out[conn], tag=conn.label)) # Set up probes for probe in conn.probes["signal"]: Builder.build(probe, dimensions=model.sig_out[conn].size, model=model) model.params[conn] = BuiltConnection(decoders=decoders, eval_points=eval_points, transform=transform, solver_info=solver_info)
def build_connection(self, conn): dt = self.model.dt rng = np.random.RandomState(self.next_seed()) self.model.sig_in[conn] = self.model.sig_out[conn.pre] self.model.sig_out[conn] = self.model.sig_in[conn.post] decoders = None eval_points = None transform = np.array(conn.transform_full, dtype=np.float64) # Figure out the signal going across this connection if (isinstance(conn.pre, nengo.Ensemble) and isinstance(conn.pre.neurons, nengo.Direct)): # Decoded connection in directmode if conn.function is None: signal = self.model.sig_in[conn] else: sig_in, signal = self.build_pyfunc( fn=conn.function, t_in=False, n_in=self.model.sig_in[conn].size, n_out=conn.dimensions, label=conn.label) self.model.operators.append(DotInc( self.model.sig_in[conn], Signal(1.0, name="1"), sig_in, tag="%s input" % conn.label)) elif isinstance(conn.pre, nengo.Ensemble): # Normal decoded connection encoders = self.built[conn.pre].encoders gain = self.built[conn.pre.neurons].gain bias = self.built[conn.pre.neurons].bias eval_points = conn.eval_points if eval_points is None: eval_points = npext.array( self.built[conn.pre].eval_points, min_dims=2) elif is_integer(eval_points): eval_points = self.generate_eval_points( ens=conn.pre, n_points=eval_points, rng=rng) else: eval_points = npext.array(eval_points, min_dims=2) x = np.dot(eval_points, encoders.T / conn.pre.radius) activities = dt * conn.pre.neurons.rates(x, gain, bias) if np.count_nonzero(activities) == 0: raise RuntimeError( "In '%s', for '%s', 'activities' matrix is all zero. " "This is because no evaluation points fall in the firing " "ranges of any neurons." % (str(conn), str(conn.pre))) if conn.function is None: targets = eval_points else: targets = npext.array( [conn.function(ep) for ep in eval_points], min_dims=2) if conn.weight_solver is not None: if conn.decoder_solver is not None: raise ValueError("Cannot specify both 'weight_solver' " "and 'decoder_solver'.") # account for transform targets = np.dot(targets, transform.T) transform = np.array(1., dtype=np.float64) decoders = conn.weight_solver( activities, targets, rng=rng, E=self.built[conn.post].scaled_encoders.T) self.model.sig_out[conn] = self.model.sig_in[ conn.post.neurons] signal_size = self.model.sig_out[conn].size else: solver = (conn.decoder_solver if conn.decoder_solver is not None else nengo.decoders.lstsq_L2nz) decoders = solver(activities, targets, rng=rng) signal_size = conn.dimensions # Add operator for decoders and filtering decoders = decoders.T if conn.filter is not None and conn.filter > dt: o_coef, n_coef = self.filter_coefs(pstc=conn.filter, dt=dt) decoder_signal = Signal( decoders * n_coef, name="%s.decoders * n_coef" % conn.label) else: decoder_signal = Signal(decoders, name="%s.decoders" % conn.label) o_coef = 0 signal = Signal(np.zeros(signal_size), name=conn.label) self.model.operators.append(ProdUpdate( decoder_signal, self.model.sig_in[conn], Signal(o_coef, name="o_coef"), signal, tag="%s decoding" % conn.label)) else: # Direct connection signal = self.model.sig_in[conn] # Add operator for filtering (in the case filter wasn't already # added, when pre.neurons is a non-direct Ensemble) if decoders is None and conn.filter is not None: # Note: we add a filter here even if filter < dt, # in order to avoid cycles in the op graph. If the filter # is explicitly set to None (e.g. for a passthrough node) # then cycles can still occur. signal = self.filtered_signal(signal, conn.filter) if conn.modulatory: # Make a new signal, effectively detaching from post self.model.sig_out[conn] = Signal( np.zeros(self.model.sig_out[conn].size), name="%s.mod_output" % conn.label) # Add reset operator? # TODO: add unit test # Add operator for transform if isinstance(conn.post, nengo.objects.Neurons): if not self.has_built(conn.post): # Since it hasn't been built, it wasn't added to the Network, # which is most likely because the Neurons weren't associated # with an Ensemble. raise RuntimeError("Connection '%s' refers to Neurons '%s' " "that are not a part of any Ensemble." % ( conn, conn.post)) transform *= self.built[conn.post].gain[:, np.newaxis] self.model.operators.append( DotInc(Signal(transform, name="%s.transform" % conn.label), signal, self.model.sig_out[conn], tag=conn.label)) # Set up probes for probe in conn.probes["signal"]: self.build(probe, dimensions=self.model.sig_out[conn].size) return BuiltConnection(decoders=decoders, eval_points=eval_points, transform=transform)
def build_ensemble(self, ens): # Create random number generator seed = self.next_seed() if ens.seed is None else ens.seed rng = np.random.RandomState(seed) # Generate eval points if ens.eval_points is None or is_integer(ens.eval_points): eval_points = self.generate_eval_points( ens=ens, n_points=ens.eval_points, rng=rng) else: eval_points = npext.array( ens.eval_points, dtype=np.float64, min_dims=2) # Set up signal self.model.sig_in[ens] = Signal(np.zeros(ens.dimensions), name="%s.signal" % ens.label) self.model.operators.append(Reset(self.model.sig_in[ens])) # Set up encoders if ens.encoders is None: if isinstance(ens.neurons, nengo.Direct): encoders = np.identity(ens.dimensions) else: sphere = dists.UniformHypersphere(ens.dimensions, surface=True) encoders = sphere.sample(ens.neurons.n_neurons, rng=rng) else: encoders = np.array(ens.encoders, dtype=np.float64) enc_shape = (ens.neurons.n_neurons, ens.dimensions) if encoders.shape != enc_shape: raise ShapeMismatch( "Encoder shape is %s. Should be (n_neurons, dimensions); " "in this case %s." % (encoders.shape, enc_shape)) encoders /= npext.norm(encoders, axis=1, keepdims=True) # Determine max_rates and intercepts if isinstance(ens.max_rates, dists.Distribution): max_rates = ens.max_rates.sample( ens.neurons.n_neurons, rng=rng) else: max_rates = np.array(ens.max_rates) if isinstance(ens.intercepts, dists.Distribution): intercepts = ens.intercepts.sample( ens.neurons.n_neurons, rng=rng) else: intercepts = np.array(ens.intercepts) # Build the neurons if isinstance(ens.neurons, nengo.Direct): bn = self.build(ens.neurons, ens.dimensions) else: bn = self.build(ens.neurons, max_rates, intercepts) # Scale the encoders if isinstance(ens.neurons, nengo.Direct): scaled_encoders = encoders else: scaled_encoders = encoders * (bn.gain / ens.radius)[:, np.newaxis] # Create output signal, using built Neurons self.model.operators.append(DotInc( Signal(scaled_encoders, name="%s.scaled_encoders" % ens.label), self.model.sig_in[ens], self.model.sig_in[ens.neurons], tag="%s encoding" % ens.label)) # Output is neural output self.model.sig_out[ens] = self.model.sig_out[ens.neurons] for probe in ens.probes["decoded_output"]: self.build(probe, dimensions=ens.dimensions) for probe in ens.probes["spikes"] + ens.probes["voltages"]: self.build(probe, dimensions=ens.neurons.n_neurons) return BuiltEnsemble(eval_points=eval_points, encoders=encoders, intercepts=intercepts, max_rates=max_rates, scaled_encoders=scaled_encoders)
def DiscreteDelay(steps): """Delays its input signal by a fixed number of timesteps.""" if not is_integer(steps) or steps < 0: raise ValueError("steps (%s) must be non-negative integer" % (steps,)) return z**(-steps)
def validate(self, instance, num): if num is not None and not is_integer(num): raise ValidationError("Must be an integer; got '%s'" % num, attr=self.name, obj=instance) super(IntParam, self).validate(instance, num)
def Highpass(tau, order=1): """Differentiated lowpass, raised to a given power.""" if order < 1 or not is_integer(order): raise ValueError("order (%s) must be integer >= 1" % order) num, den = map(np.poly1d, ([tau, 0], [tau, 1])) return LinearFilter(num**order, den**order)
def add_spikes(self, ti, spike_idxs): assert is_integer(ti) ti = int(ti) assert ti > 0, "Spike times must be >= 1 (got %d)" % ti assert ti not in self.spikes self.spikes[ti] = spike_idxs
def validate(self, instance, num): if num is not None and not is_integer(num): raise ValueError("Must be an integer; got '%s'" % num) super(IntParam, self).validate(instance, num)
def coerce_defaults(self): if self.shape is None: return True return all(is_integer(dim) or dim in ('...', '*') for dim in self.shape)
def coerce_defaults(self): return all( is_integer(dim) or dim in ('...', '*') for dim in self.shape)
def build_ensemble(ens, model): # noqa: C901 # Create random number generator seed = model.next_seed() if ens.seed is None else ens.seed rng = np.random.RandomState(seed) # Generate eval points if ens.eval_points is None or is_integer(ens.eval_points): eval_points = pick_eval_points(ens=ens, n_points=ens.eval_points, rng=rng) else: eval_points = npext.array(ens.eval_points, dtype=np.float64, min_dims=2) # Set up signal model.sig_in[ens] = Signal(np.zeros(ens.dimensions), name="%s.signal" % ens.label) model.operators.append(Reset(model.sig_in[ens])) # Set up encoders if ens.encoders is None: if isinstance(ens.neurons, nengo.Direct): encoders = np.identity(ens.dimensions) else: sphere = dists.UniformHypersphere(ens.dimensions, surface=True) encoders = sphere.sample(ens.neurons.n_neurons, rng=rng) else: encoders = np.array(ens.encoders, dtype=np.float64) enc_shape = (ens.neurons.n_neurons, ens.dimensions) if encoders.shape != enc_shape: raise ShapeMismatch( "Encoder shape is %s. Should be (n_neurons, dimensions); " "in this case %s." % (encoders.shape, enc_shape)) encoders /= npext.norm(encoders, axis=1, keepdims=True) # Determine max_rates and intercepts if isinstance(ens.max_rates, dists.Distribution): max_rates = ens.max_rates.sample(ens.neurons.n_neurons, rng=rng) else: max_rates = np.array(ens.max_rates) if isinstance(ens.intercepts, dists.Distribution): intercepts = ens.intercepts.sample(ens.neurons.n_neurons, rng=rng) else: intercepts = np.array(ens.intercepts) # Build the neurons if isinstance(ens.neurons, nengo.Direct): Builder.build(ens.neurons, ens.dimensions, model=model) else: Builder.build(ens.neurons, max_rates, intercepts, model=model) bn = model.params[ens.neurons] # Scale the encoders if isinstance(ens.neurons, nengo.Direct): scaled_encoders = encoders else: scaled_encoders = encoders * (bn.gain / ens.radius)[:, np.newaxis] # Create output signal, using built Neurons model.operators.append( DotInc(Signal(scaled_encoders, name="%s.scaled_encoders" % ens.label), model.sig_in[ens], model.sig_in[ens.neurons], tag="%s encoding" % ens.label)) # Output is neural output model.sig_out[ens] = model.sig_out[ens.neurons] for probe in ens.probes["decoded_output"]: Builder.build(probe, dimensions=ens.dimensions, model=model) for probe in ens.probes["spikes"] + ens.probes["voltages"]: Builder.build(probe, dimensions=ens.neurons.n_neurons, model=model) model.params[ens] = BuiltEnsemble(eval_points=eval_points, encoders=encoders, intercepts=intercepts, max_rates=max_rates, scaled_encoders=scaled_encoders)