def __init__(self, target, variables): self.target = target for mon_var in variables: if not hasattr(target, mon_var): raise errors.ModelDefError( f"Item {mon_var} isn't defined in model {target}, " f"so it can not be monitored.") item_names = [] mon_indices = [] item_content = {} if variables is not None: if isinstance(variables, (list, tuple)): for mon_var in variables: if isinstance(mon_var, str): var_data = getattr(target, mon_var) mon_key = mon_var mon_idx = None mon_shape = ops.shape(var_data) elif isinstance(mon_var, (tuple, list)): mon_key = mon_var[0] var_data = getattr(target, mon_key) mon_idx = mon_var[1] mon_shape = ops.shape(mon_idx) # TODO: matrix index else: raise errors.ModelUseError( f'Unknown monitor item: {str(mon_var)}') item_names.append(mon_key) mon_indices.append(mon_idx) dtype = var_data.dtype if hasattr(var_data, 'dtype') else None item_content[mon_var] = ops.zeros((1, ) + mon_shape, dtype=dtype) elif isinstance(variables, dict): for k, v in variables.items(): item_names.append(k) mon_indices.append(v) if v is None: shape = ops.shape(getattr(target, k)) else: shape = ops.shape(v) val_data = getattr(target, k) dtype = val_data.dtype if hasattr(val_data, 'dtype') else None item_content[k] = ops.zeros((1, ) + shape, dtype=dtype) else: raise errors.ModelUseError( f'Unknown monitors type: {type(variables)}') self.ts = None self.item_names = item_names self.item_indices = mon_indices self.item_contents = item_content self.num_item = len(item_content)
def __init__(self, v0, delay_len, before_t0=0., t0=0., dt=None): # size self.size = ops.shape(v0) # delay_len self.delay_len = delay_len self.dt = backend.get_dt() if dt is None else dt self.num_delay = int(math.ceil(delay_len / self.dt)) # other variables self._delay_in = self.num_delay - 1 self._delay_out = 0 self.current_time = t0 # before_t0 self.before_t0 = before_t0 # delay data self.data = ops.zeros((self.num_delay + 1,) + self.size) if callable(before_t0): for i in range(self.num_delay): self.data[i] = before_t0(t0 + (i - self.num_delay) * self.dt) else: self.data[:-1] = before_t0 self.data[-1] = v0
def run(self, duration, inputs=(), report=False, report_percent=0.1): """The running function. Parameters ---------- duration : float, int, tuple, list The running duration. inputs : list, tuple The model inputs with the format of ``[(key, value [operation])]``. report : bool Whether report the running progress. report_percent : float The percent of progress to report. """ # times # ------ start, end = utils.check_duration(duration) times = ops.arange(start, end, backend.get_dt()) run_length = ops.shape(times)[0] # build run function # ------------------ self.run_func = self.build(inputs, inputs_is_formatted=False, mon_length=run_length, return_code=False) # run the model # ------------- res = utils.run_model(self.run_func, times, report, report_percent) self.mon.ts = times return res
def period_input(values, durations, dt=None, return_length=False): """Format an input current with different periods. For example: If you want to get an input where the size is 0 bwteen 0-100 ms, and the size is 1. between 100-200 ms. >>> import numpy as np >>> period_input(values=[0, 1], >>> durations=[100, 100]) Parameters ---------- values : list, np.ndarray The current values for each period duration. durations : list, np.ndarray The duration for each period. dt : float Default is None. return_length : bool Return the final duration length. Returns ------- current_and_duration : tuple (The formatted current, total duration) """ assert len(durations) == len(values), f'"values" and "durations" must be the same length, while ' \ f'we got {len(values)} != {len(durations)}.' dt = backend.get_dt() if dt is None else dt # get input current shape, and duration I_duration = sum(durations) I_shape = () for val in values: shape = ops.shape(val) if len(shape) > len(I_shape): I_shape = shape # get the current start = 0 I_current = ops.zeros((int(math.ceil(I_duration / dt)),) + I_shape) for c_size, duration in zip(values, durations): length = int(duration / dt) I_current[start: start + length] = c_size start += length if return_length: return I_current, I_duration else: return I_current
def constant_input(I_and_duration, dt=None): """Format constant input in durations. For example: If you want to get an input where the size is 0 bwteen 0-100 ms, and the size is 1. between 100-200 ms. >>> import numpy as np >>> constant_input([(0, 100), (1, 100)]) >>> constant_input([(np.zeros(100), 100), (np.random.rand(100), 100)]) Parameters ---------- I_and_duration : list This parameter receives the current size and the current duration pairs, like `[(Isize1, duration1), (Isize2, duration2)]`. dt : float Default is None. Returns ------- current_and_duration : tuple (The formatted current, total duration) """ dt = backend.get_dt() if dt is None else dt # get input current dimension, shape, and duration I_duration = 0. I_dim = 0 I_shape = () for I in I_and_duration: I_duration += I[1] shape = ops.shape(I[0]) if len(shape) > len(I_shape): I_shape = shape # get the current I_current = ops.zeros((int(math.ceil(I_duration / dt)),) + I_shape) start = 0 for c_size, duration in I_and_duration: length = int(duration / dt) I_current[start: start + length] = c_size start += length return I_current, I_duration
def __init__(self, size, delay_time): if isinstance(size, int): size = (size, ) self.size = tuple(size) self.delay_time = delay_time if isinstance(delay_time, (int, float)): self.uniform_delay = True self.delay_num_step = int(math.ceil( delay_time / backend.get_dt())) + 1 self.delay_data = ops.zeros((self.delay_num_step, ) + self.size) else: if not len(self.size) == 1: raise NotImplementedError( f'Currently, BrainPy only supports 1D heterogeneous delays, while does ' f'not implement the heterogeneous delay with {len(self.size)}-dimensions.' ) self.num = size2len(size) if isinstance(delay_time, type(ops.as_tensor([1]))): assert ops.shape(delay_time) == self.size elif callable(delay_time): delay_time2 = ops.zeros(size) for i in range(size[0]): delay_time2[i] = delay_time() delay_time = delay_time2 else: raise NotImplementedError( f'Currently, BrainPy does not support delay type ' f'of {type(delay_time)}: {delay_time}') self.uniform_delay = False delay = delay_time / backend.get_dt() dint = ops.as_tensor(delay_time / backend.get_dt(), dtype=int) ddiff = (delay - dint) >= 0.5 self.delay_num_step = ops.as_tensor(delay + ddiff, dtype=int) + 1 self.delay_data = ops.zeros((max(self.delay_num_step), ) + size) self.diag = ops.arange(self.num) self.delay_in_idx = self.delay_num_step - 1 if self.uniform_delay: self.delay_out_idx = 0 else: self.delay_out_idx = ops.zeros(self.num, dtype=int) self.name = None
def mat2ij(conn_mat): """Get the i-j connections from connectivity matrix. Parameters ---------- conn_mat : np.ndarray Connectivity matrix with `(num_pre, num_post)` shape. Returns ------- conn_tuple : tuple (Pre-synaptic neuron indexes, post-synaptic neuron indexes). """ if len(ops.shape(conn_mat)) != 2: raise errors.ModelUseError('Connectivity matrix must be in the ' 'shape of (num_pre, num_post).') pre_ids, post_ids = ops.where(conn_mat > 0) return ops.as_tensor(pre_ids, dtype=ops.int), \ ops.as_tensor(post_ids, dtype=ops.int)
def run(self, duration, report=False, report_percent=0.1): if isinstance(duration, (int, float)): duration = [0, duration] elif isinstance(duration, (tuple, list)): assert len(duration) == 2 duration = tuple(duration) else: raise ValueError # get the times times = ops.arange(duration[0], duration[1], backend.get_dt()) # reshape the monitor for key in self.mon.keys(): self.mon[key] = ops.zeros((len(times), ) + ops.shape(self.mon[key])[1:]) # run the model run_model(run_func=self.run_func, times=times, report=report, report_percent=report_percent)
def format_net_level_inputs(inputs, run_length): """Format the inputs of a network. Parameters ---------- inputs : tuple The inputs. run_length : int The running length. Returns ------- formatted_input : dict The formatted input. """ from brainpy.simulation.dynamic_system import DynamicSystem # 1. format the inputs to standard # formats and check the inputs if not isinstance(inputs, (tuple, list)): raise errors.ModelUseError('"inputs" must be a tuple/list.') if len(inputs) > 0 and not isinstance(inputs[0], (list, tuple)): if isinstance(inputs[0], DynamicSystem): inputs = [inputs] else: raise errors.ModelUseError('Unknown input structure. Only supports ' '"(target, key, value, [operation])".') for input in inputs: if not 3 <= len(input) <= 4: raise errors.ModelUseError('For each target, you must specify ' '"(target, key, value, [operation])".') if len(input) == 4: if input[3] not in SUPPORTED_INPUT_OPS: raise errors.ModelUseError(f'Input operation only supports ' f'"{SUPPORTED_INPUT_OPS}", ' f'not "{input[3]}".') # 2. format inputs formatted_inputs = {} for input in inputs: # target if isinstance(input[0], DynamicSystem): target = input[0] target_name = input[0].name else: raise KeyError(f'Unknown input target: {str(input[0])}') # key key = input[1] if not isinstance(key, str): raise errors.ModelUseError('For each input, input[1] must be a string ' 'to specify variable of the target.') if not hasattr(target, key): raise errors.ModelUseError(f'Target {target} does not have key {key}. ' f'So, it can not assign input to it.') # value and data type val = input[2] if isinstance(input[2], (int, float)): data_type = 'fix' else: shape = ops.shape(val) if shape[0] == run_length: data_type = 'iter' else: data_type = 'fix' # operation if len(input) == 4: operation = input[3] else: operation = '+' # final result if target_name not in formatted_inputs: formatted_inputs[target_name] = [] format_inp = (key, val, operation, data_type) formatted_inputs[target_name].append(format_inp) return formatted_inputs
def format_pop_level_inputs(inputs, host, mon_length): """Format the inputs of a population. Parameters ---------- inputs : tuple, list The inputs of the population. host : Population The host which contains all data. mon_length : int The monitor length. Returns ------- formatted_inputs : tuple, list The formatted inputs of the population. """ if inputs is None: inputs = [] if not isinstance(inputs, (tuple, list)): raise errors.ModelUseError('"inputs" must be a tuple/list.') if len(inputs) > 0 and not isinstance(inputs[0], (list, tuple)): if isinstance(inputs[0], str): inputs = [inputs] else: raise errors.ModelUseError('Unknown input structure, only support inputs ' 'with format of "(key, value, [operation])".') for input in inputs: if not 2 <= len(input) <= 3: raise errors.ModelUseError('For each target, you must specify "(key, value, [operation])".') if len(input) == 3 and input[2] not in SUPPORTED_INPUT_OPS: raise errors.ModelUseError(f'Input operation only supports ' f'"{SUPPORTED_INPUT_OPS}", ' f'not "{input[2]}".') # format inputs # ------------- formatted_inputs = [] for input in inputs: # key if not isinstance(input[0], str): raise errors.ModelUseError('For each input, input[0] must be a string ' 'to specify variable of the target.') key = input[0] if not hasattr(host, key): raise errors.ModelUseError(f'Input target key "{key}" is not defined in {host}.') # value and data type val = input[1] if isinstance(input[1], (int, float)): data_type = 'fix' else: shape = ops.shape(input[1]) if shape[0] == mon_length: data_type = 'iter' else: data_type = 'fix' # operation if len(input) == 3: operation = input[2] else: operation = '+' if operation not in SUPPORTED_INPUT_OPS: raise errors.ModelUseError(f'Currently, BrainPy only support operations ' f'{SUPPORTED_INPUT_OPS}, ' f'not {operation}') # input format_inp = (key, val, operation, data_type) formatted_inputs.append(format_inp) return formatted_inputs