Source code for nengo.utils.ensemble

import numpy as np

from . import numpy as npext


[docs]def tuning_curves(ens, sim, inputs=None): """Calculates the tuning curves of an ensemble. That is the neuron responses in dependence of the vector represented by the ensemble. For 1-dimensional ensembles, the unpacked return value of this function can be passed directly to ``matplotlib.pyplot.plot``. Parameters ---------- ens : nengo.Ensemble Ensemble to calculate the tuning curves of. sim : nengo.Simulator Simulator providing information about the built ensemble. (An unbuilt ensemble does not have tuning curves assigned to it.) inputs : sequence of ndarray, optional The inputs at which the tuning curves will be evaluated. For each of the ``D`` ensemble dimensions one array of dimensionality ``D`` is needed. The output of :func:`numpy.meshgrid` with ``indexing='ij'`` is in the right format. Returns ------- inputs : sequence of ndarray The passed or auto-generated ``inputs``. activities : ndarray The activities of the individual neurons given the ``inputs``. For ensembles with 1 dimension, the rows correspond to the ``inputs`` and the columns to individual neurons. For ensembles with > 1 dimension, the last dimension enumerates the neurons, the remaining dimensions map to ``inputs``. See Also -------- response_curves """ # note: imported here to avoid circular imports from nengo.builder.ensemble import ( # pylint: disable=import-outside-toplevel get_activities, ) if inputs is None: inputs = np.linspace(-ens.radius, ens.radius) if ens.dimensions > 1: inputs = npext.meshgrid_nd(*(ens.dimensions * [inputs])) else: inputs = [inputs] inputs = np.asarray(inputs).T else: inputs = np.asarray(inputs) eval_points = inputs.reshape((-1, ens.dimensions)) activities = get_activities(sim.data[ens], ens, eval_points) return inputs, activities.reshape(inputs.shape[:-1] + (-1,))
[docs]def response_curves(ens, sim, inputs=None): """Calculates the response curves of an ensemble. That is the neuron responses in dependence of an already encoded value. This corresponds to the tuning curves along the neuron's preferred directions. Parameters ---------- ens : nengo.Ensemble Ensemble to calculate the response curves of. sim : nengo.Simulator Simulator providing information about the built ensemble. (An unbuilt ensemble does not have response curves assigned to it.) inputs : 1d array, optional The inputs between -1 and 1 at which the neuron responses will be evaluated. They are assumed to be along each neuron's preferred direction. Returns ------- inputs : 1d array The passed or auto-generated ``inputs``. activities : 2d array The activities of the individual neurons given the ``inputs``. The rows map to ``inputs`` and the columns to the neurons in the ensemble. See Also -------- tuning_curves """ if inputs is None: inputs = np.linspace(-1.0, 1.0) return inputs, ens.neuron_type.rates(inputs, sim.data[ens].gain, sim.data[ens].bias)
def _similarity(encoders, index, rows, cols=1): """Helper function to compute similarity for one encoder. Parameters ---------- encoders: ndarray The encoders. index: int The encoder to compute for. rows: int The width of the 2d grid. cols: int The height of the 2d grid. """ i = index % cols # find the 2d location of the indexth element j = index // cols sim = 0 # total of dot products count = 0 # number of neighbours if i > 0: # if we're not at the left edge, do the WEST comparison sim += np.dot(encoders[j * cols + i], encoders[j * cols + i - 1]) count += 1 if i < cols - 1: # if we're not at the right edge, do EAST sim += np.dot(encoders[j * cols + i], encoders[j * cols + i + 1]) count += 1 if j > 0: # if we're not at the top edge, do NORTH sim += np.dot(encoders[j * cols + i], encoders[(j - 1) * cols + i]) count += 1 if j < rows - 1: # if we're not at the bottom edge, do SOUTH sim += np.dot(encoders[j * cols + i], encoders[(j + 1) * cols + i]) count += 1 return sim / count
[docs]def sorted_neurons(ensemble, sim, iterations=100, seed=None): """Sort neurons in an ensemble by encoder and intercept. Parameters ---------- ensemble : Ensemble The population of neurons to be sorted. sim : Simulator Simulator providing information about the built ensemble. iterations: int The number of times to iterate during the sort. seed: float A random number seed. Returns ------- indices: ndarray An array with sorted indices into the neurons in the ensemble Examples -------- You can use this to generate an array of sorted indices for plotting. This can be done after collecting the data. E.g. .. testcode:: from nengo.utils.ensemble import sorted_neurons from nengo.utils.matplotlib import rasterplot with nengo.Network() as net: ens = nengo.Ensemble(10, 1) ens_p = nengo.Probe(ens.neurons) with nengo.Simulator(net) as sim: sim.run(0.1) indices = sorted_neurons(ens, sim) rasterplot(sim.trange(), sim.data[ens_p][:, indices]) .. testoutput:: :hide: ... Notes ----- The algorithm is for each encoder in the initial set, randomly pick another encoder and check to see if swapping those two encoders would reduce the average difference between the encoders and their neighbours. Difference is measured as the dot product. Each encoder has four neighbours (N, S, E, W), except for the ones on the edges which have fewer (no wrapping). This algorithm is repeated ``iterations`` times, so a total of ``iterations*N`` swaps are considered. """ # Normalize all the encoders encoders = np.array(sim.data[ensemble].encoders) encoders /= npext.norm(encoders, axis=1, keepdims=True) # Make an array with the starting order of the neurons N = encoders.shape[0] indices = np.arange(N) rng = np.random.RandomState(seed) for k in range(iterations): target = rng.randint(0, N, N) # pick random swap targets for i in range(N): j = target[i] if i != j: # if not swapping with yourself # compute similarity score how we are (unswapped) sim1 = _similarity(encoders, i, N) + _similarity(encoders, j, N) # swap the encoder encoders[[i, j], :] = encoders[[j, i], :] indices[[i, j]] = indices[[j, i]] # compute similarity score how we are (swapped) sim2 = _similarity(encoders, i, N) + _similarity(encoders, j, N) # if we were better unswapped if sim1 > sim2: # swap them back encoders[[i, j], :] = encoders[[j, i], :] indices[[i, j]] = indices[[j, i]] return indices