def __init__(self, name, seed=None, fixed_seed=None, dt=0.001, Simulator=simulator.Simulator): self.random = random.Random() if seed is not None: self.random.seed(seed) self.fixed_seed = fixed_seed self.model = SimModel(dt) self.ensembles = {} self.inputs = {} self.steps = self.model.signal(name='steps') self.simtime = self.model.signal(name='simtime') self.one = self.model.signal(value=[1.0], name='one') # -- steps counts by 1.0 self.model.filter(1.0, self.one, self.steps) self.model.filter(1.0, self.steps, self.steps) # simtime <- dt * steps self.model.filter(dt, self.one, self.simtime) self.model.filter(dt, self.steps, self.simtime) self.Simulator = Simulator
class Network(object): def __init__(self, name, seed=None, fixed_seed=None, dt=0.001, Simulator=simulator.Simulator): self.random = random.Random() if seed is not None: self.random.seed(seed) self.fixed_seed = fixed_seed self.model = SimModel(dt) self.ensembles = {} self.inputs = {} self.steps = self.model.signal(name='steps') self.simtime = self.model.signal(name='simtime') self.one = self.model.signal(value=[1.0], name='one') # -- steps counts by 1.0 self.model.filter(1.0, self.one, self.steps) self.model.filter(1.0, self.steps, self.steps) # simtime <- dt * steps self.model.filter(dt, self.one, self.simtime) self.model.filter(dt, self.steps, self.simtime) self.Simulator = Simulator @property def dt(self): return self.model.dt def make_input(self, name, value): if callable(value): pop = self.model.nonlinearity( Direct(n_in=1, n_out=1, fn=value)) self.model.encoder(self.simtime, pop, weights=np.asarray([[1]])) # TODO: add this to simulator_objects pop.input_signal.name = name + '.input' pop.bias_signal.name = name + '.bias' pop.output_signal.name = name + '.output' # move from signals_tmp -> signals self.model.transform(1.0, pop.output_signal, pop.output_signal) else: value = np.asarray(value, dtype='float') N, = value.shape rval = self.model.signal(n=N, value=value, name=name) self.inputs[name] = rval return rval def make_array(self, name, neurons, array_size, dimensions=1, **kwargs): """Generate a network array specifically. This function is depricated; use for legacy code or non-theano API compatibility. """ return self.make( name=name, neurons=neurons, dimensions=dimensions, array_size=array_size, **kwargs) def make(self, name, *args, **kwargs): if 'seed' not in kwargs.keys(): if self.fixed_seed is not None: kwargs['seed'] = self.fixed_seed else: # if no seed provided, get one randomly from the rng kwargs['seed'] = self.random.randrange(0x7fffffff) kwargs['dt'] = self.dt rval = Ensemble(self.model, name, *args, **kwargs) self.ensembles[name] = rval return rval def connect(self, name1, name2, func=None, pstc=0.01, **kwargs): if name1 in self.ensembles: src = self.ensembles[name1] dst = self.ensembles[name2] if func is None: oname = 'X' else: oname = func.__name__ if oname not in src.origin: src.add_origin(oname, func) decoded_origin = src.origin[oname] transform = compute_transform( array_size_pre=src.array_size, dim_pre=decoded_origin.sigs[0].n, array_size_post=dst.array_size, dim_post=dst.dimensions, **kwargs) if pstc > self.dt: smoothed_signals = [] for ii in range(src.array_size): filtered_signal = self.model.signal( n=decoded_origin.sigs[ii].n, #-- views not ok here name=decoded_origin.sigs[ii].name + '::pstc=%s' % pstc) fcoef, tcoef = filter_coefs(pstc, dt=self.dt) self.model.transform(tcoef, decoded_origin.sigs[ii], filtered_signal) self.model.filter(fcoef, filtered_signal, filtered_signal) smoothed_signals.append(filtered_signal) for jj in range(dst.array_size): for ii in range(src.array_size): if np.all(transform[ii, :, jj] == 0): continue self.model.filter( transform[ii, :, jj].T, smoothed_signals[ii], dst.input_signals[jj]) else: smoothed_signals = decoded_origin.sigs for ii in range(src.array_size): for jj in range(dst.array_size): if np.all(transform[ii, :, jj] == 0): continue self.model.transform( transform[ii, :, jj].T, smoothed_signals[ii], dst.input_signals[jj]) elif name1 in self.inputs: src = self.inputs[name1] dst_ensemble = self.ensembles[name2] if (dst_ensemble.array_size,) != src.shape: raise ShapeMismatch( (dst_ensemble.array_size,), src.shape) for ii in range(dst_ensemble.array_size): src_ii = src[ii:ii+1] dst_ii = dst_ensemble.input_signals[ii] assert func is None self.model.filter(kwargs.get('transform', 1.0), src_ii, dst_ii) else: raise NotImplementedError() def _raw_probe(self, sig, dt_sample): """ Create an un-filtered probe of the named signal, without constructing any filters or transforms. """ return Probe(self.model.probe(sig, dt_sample), self) def _probe_signals(self, srcs, dt_sample, pstc): """ set up a probe for signals (srcs) that will record their value *after* decoding, transforming, filtering. This is appropriate for inputs, constants, non-linearities, etc. But if you want to probe the part of a filter that is purely the decoded contribution from a population, then use _probe_decoded_signals. """ src_n = srcs[0].size probe_sig = self.model.signal( n=len(srcs) * src_n, name='probe(%s)' % srcs[0].name ) if pstc > self.dt: # -- create a new smoothed-out signal fcoef, tcoef = filter_coefs(pstc=pstc, dt=self.dt) self.model.filter(fcoef, probe_sig, probe_sig) for ii, src in enumerate(srcs): self.model.filter(tcoef, src, probe_sig[ii * src_n: (ii + 1) * src_n]) return Probe( self.model.probe(probe_sig, dt_sample), self) else: for ii, src in enumerate(srcs): self.model.filter(1.0, src, probe_sig[ii * src_n: (ii + 1) * src_n]) return Probe(self.model.probe(probe_sig, dt_sample), self) def _probe_decoded_signals(self, srcs, dt_sample, pstc): """ set up a probe for signals (srcs) that will record their value just from being decoded. This is appropriate for functions decoded from nonlinearities. """ src_n = srcs[0].size probe_sig = self.model.signal( n=len(srcs) * src_n, name='probe(%s)' % srcs[0].name ) if pstc > self.dt: # -- create a new smoothed-out signal fcoef, tcoef = filter_coefs(pstc=pstc, dt=self.dt) self.model.filter(fcoef, probe_sig, probe_sig) for ii, src in enumerate(srcs): self.model.transform(tcoef, src, probe_sig[ii * src_n: (ii + 1) * src_n]) return Probe( self.model.probe(probe_sig, dt_sample), self) else: for ii, src in enumerate(srcs): self.model.transform(1.0, src, probe_sig[ii * src_n: (ii + 1) * src_n]) return Probe(self.model.probe(probe_sig, dt_sample), self) def make_probe(self, name, dt_sample, pstc): if name in self.ensembles: ens = self.ensembles[name] srcs = ens.origin['X'].sigs return self._probe_decoded_signals(srcs, dt_sample, pstc) elif name in self.inputs: src = self.inputs[name] return self._probe_signals([src], dt_sample, pstc) else: raise NotImplementedError() def _make_simulator(self): sim = self.Simulator(self.model) self.sim = sim def run(self, simtime, verbose=False): try: self.sim except: self._make_simulator() n_steps = int(simtime // self.dt) self.sim.run_steps(n_steps, verbose=verbose)