Python API
Generated from the docstrings of the installed package.
Development
Development of spiking networks from a body plan and a genome.
- class neurogenesis.development.BodyPlan(name: str, regions: list, projections: list, conduction_velocity: float = 20.0, max_delay: int = 31, ids: dict = <factory>, rules: dict = <factory>, plugins: list = <factory>)[source]
Bases:
objectRegions, allowed projections (src, dst) in growth order, and physical constants of development.
- name: str
- regions: list
- projections: list
- conduction_velocity: float = 20.0
- max_delay: int = 31
- ids: dict
- rules: dict
- plugins: list
- class neurogenesis.development.Count(value: int = 1, gene: tuple | None = None, lo: int = 1, hi: int = 16)[source]
Bases:
objectA number of neurons: a constant, or a gene (path in the genome) with a default and bounds.
- value: int = 1
- gene: tuple | None = None
- lo: int = 1
- hi: int = 16
- class neurogenesis.development.FixedPlacement(labels: list, counts: list | None = None, jitter: dict | None = None)[source]
Bases:
objectNeurons at given local labels; label k is repeated counts[k] times (consecutively).
jitter: None; {“kind”: “normal”, “sd”: s, “axes”: (1, 1, 0)} adds s * N(0, 1) * axes to every label (then clips to [0, 1]); {“kind”: “uniform”, “axes”: [1, 2]} replaces the listed coordinates by U(0, 1) draws.
- labels: list
- counts: list | None = None
- jitter: dict | None = None
- class neurogenesis.development.Region(name: str, origin: tuple, size: tuple, placement: FixedPlacement | None = None, role: int = 0, sign: str | None = None, refractory: int = 3, count_bounds: tuple = (4, 1024))[source]
Bases:
objectA region of the plan. placement None means grown (count, migration and inhibitory genes of this region).
role: 0 internal, 1 input (driven by external currents), 2 output (read out). sign: None (genetic), “exc” or “inh” (imposed on every neuron of the region). refractory: refractory period in ticks.
- name: str
- origin: tuple
- size: tuple
- placement: FixedPlacement | None = None
- role: int = 0
- sign: str | None = None
- refractory: int = 3
- count_bounds: tuple = (4, 1024)
- property grown: bool
- neurogenesis.development.get_path(genome, path, default=None)[source]
Value at a gene path (sequence of keys) in a nested genome, or default if any key is missing.
- neurogenesis.development.grow(plan: BodyPlan, genome: dict, seed: int = 0, regions=None, projections=None, name: str | None = None) SNNNetwork[source]
Develop one individual. regions / projections: a subset of the plan (default: all, in plan order).
- neurogenesis.development.grow_many(calls)[source]
neurogenesis.development.grow(**kw)for every kw in calls (keys: plan, genome, seed, regions, projections, name).
- neurogenesis.development.map_calls(fn, calls)[source]
[fn(**kw) for kw in calls], in parallel if set_workers was called. fn must be a module-level function.Scripts that use workers must guard their entry point with if __name__ == “__main__”: (spawned workers re-import the main module) and should keep JAX imports out of module level, or set JAX_PLATFORMS=cpu when __name__ != “__main__”, so that workers do not claim the GPU.
- neurogenesis.development.set_workers(n)[source]
Use n worker processes for map_calls (n <= 1: serial, the default).
- neurogenesis.development.region_of(net: SNNNetwork, plan: BodyPlan, region: str) ndarray[source]
Indices of the neurons of a region in a grown network.
- neurogenesis.development.knockout(genome: dict, regions=(), projections=()) dict[source]
Copy of a genome with virtual knockouts: the listed regions never form, the listed projections never grow.
- neurogenesis.development.tonic_current(net: SNNNetwork, plan: BodyPlan, genome: dict) ndarray[source]
Intrinsic standing current of each neuron (int32, per tick), from genome[“tonic”][region] (default 0).
- class neurogenesis.development.GuidanceContext(src: 'str', dst: 'str', pos_src: 'np.ndarray', pos_dst: 'np.ndarray', inhibitory_src: 'np.ndarray', identity_src: 'np.ndarray | None', gd: 'dict', shift: 'np.ndarray | None' = None, target: 'np.ndarray | None' = None, p: 'np.ndarray | None' = None)[source]
Bases:
object- src: str
- dst: str
- pos_src: ndarray
- pos_dst: ndarray
- inhibitory_src: ndarray
- identity_src: ndarray | None
- gd: dict
- shift: ndarray | None = None
- target: ndarray | None = None
- p: ndarray | None = None
- class neurogenesis.development.PlacementContext(region: 'str', pos: 'np.ndarray', genome: 'dict')[source]
Bases:
object- region: str
- pos: ndarray
- genome: dict
- class neurogenesis.development.WeightContext(src: 'str', dst: 'str', pre: 'np.ndarray', post: 'np.ndarray', w: 'np.ndarray', gd: 'dict')[source]
Bases:
object- src: str
- dst: str
- pre: ndarray
- post: ndarray
- w: ndarray
- gd: dict
- neurogenesis.development.register(phase, name)[source]
Decorator: register a rule for a phase (“placement”, “shift”, “target”, “probability” or “weight”).
- neurogenesis.development.differentiate(dg, pos, base_v, base_s, rng)[source]
Per-neuron threshold, time constants and pacemaker identity from the two fates.
- neurogenesis.development.lateral_fates(pos, b0, b, c, r, rng, iters=12, gain=8.0)[source]
Fate in [0, 1] per cell: positional bias plus noise, inhibited by the mean fate of neighbours (Gaussian kernel of range r, rows normalised).
- neurogenesis.development.neutral_differentiation()[source]
Founding values of the differentiation step: no effect (uniform fates, threshold 1024, base time constants, no pacemaker).
- neurogenesis.development.neutral_identity(k=6)[source]
Founding identity code: all logits 0 (every neuron takes identity 0).
- neurogenesis.development.neutral_typed_guidance(gd, k=6)[source]
Founding identity-dependent guidance of a projection: no offset, full expression (no effect).
Parallel development in CPU processes (spawned; JAX restricted to the CPU there). Results equal the serial ones.
- neurogenesis.development.parallel.set_workers(n)[source]
Use n worker processes for map_calls (n <= 1: serial, the default).
- neurogenesis.development.parallel.map_calls(fn, calls)[source]
[fn(**kw) for kw in calls], in parallel if set_workers was called. fn must be a module-level function.Scripts that use workers must guard their entry point with if __name__ == “__main__”: (spawned workers re-import the main module) and should keep JAX imports out of module level, or set JAX_PLATFORMS=cpu when __name__ != “__main__”, so that workers do not claim the GPU.
- neurogenesis.development.parallel.grow_many(calls)[source]
neurogenesis.development.grow(**kw)for every kw in calls (keys: plan, genome, seed, regions, projections, name).
Legacy compiler (A5): a BodyPlan as a Stage schedule.
compile_plan_to_schedule / compile_plan_to_project wrap a plan into the legacy_grow_stage stage, which runs the decomposed steps of development.grow; with run_schedule(…, legacy_stream=True) the result is bit-for-bit that of grow().
- class neurogenesis.development.legacy_compiler.LegacyGrowStage[source]
Bases:
objectCanonical stage that executes decomposed steps of legacy growth.
All state is fully contained and serializable: takes plan data in params, updates Tissue directly without hidden global caches or private monkey-patched attributes.
- run(tissue: Tissue, params: Dict[str, Any], genome: Dict[str, Any], fields: Dict[str, Any], rng: Generator) Tissue[source]
- operator_name = 'legacy_grow_stage'
- neurogenesis.development.legacy_compiler.compile_plan_to_schedule(plan: BodyPlan, genome: Dict[str, Any] | None = None) List[Stage][source]
Compiles a legacy BodyPlan into a schedule of declarative, serializable Stages.
When executed via run_schedule(project, genome, seed, legacy_stream=True), reproduces development.grow() bit-for-bit with zero state duplication.
Projects, Params and stages
Project I/O for reading and writing projects.
- class neurogenesis.project.io.Project(version: str = '1.1.0', geometry: Dict[str, Any]=<factory>, fields: Dict[str, Any]=<factory>, schedule: List[Dict[str, Any]]=<factory>, genome: Dict[str, Any]=<factory>, plan: Optional[Dict[str, Any]]=None, plugins: List[str] = <factory>, neuron_model: str = 'lif_int', metadata: Dict[str, Any]=<factory>, data_sources: Optional[Dict[str, Any]]=None, pharmacology: Optional[Dict[str, Any]]=None, morphology: Optional[Dict[str, Any]]=None)[source]
Bases:
object- version: str = '1.1.0'
- geometry: Dict[str, Any]
- fields: Dict[str, Any]
- schedule: List[Dict[str, Any]]
- genome: Dict[str, Any]
- plan: Dict[str, Any] | None = None
- plugins: List[str]
- neuron_model: str = 'lif_int'
- metadata: Dict[str, Any]
- data_sources: Dict[str, Any] | None = None
- pharmacology: Dict[str, Any] | None = None
- morphology: Dict[str, Any] | None = None
- to_dict() Dict[str, Any][source]
Convert the project to a dictionary, removing None values where appropriate.
Project schema validation and migration.
- neurogenesis.project.schema.validate(data: Any) None[source]
Validate that the given dictionary conforms to the current Project schema.
- neurogenesis.project.schema.migrate_010_to_100(data: Dict[str, Any]) Dict[str, Any][source]
Migrate a 0.1.0 legacy BodyPlan to a 1.0.0 Project.
- neurogenesis.project.schema.migrate_100_to_110(data: Dict[str, Any]) Dict[str, Any][source]
Migrate a 1.0.0 Project to 1.1.0: only the version changes (the new sections data_sources, pharmacology and morphology are optional), so a migrated project develops exactly as before.
- neurogenesis.project.schema.migrate(data: Dict[str, Any], from_version: str, to_version: str) Dict[str, Any][source]
Migrate data from one version to another, through intermediate versions if needed (e.g. 0.1.0 -> 1.0.0 -> 1.1.0).
Param sources (A3): how a stage parameter gets its value.
Const, Gene (a genome entry between lo and hi), Field (a field sampled at cell positions), Fit (fitted by neurogenesis.fitting, init until then) and Expr (a formula). resolve gives a Param’s value for a genome and fields, worst_case its value for cost estimates, param_from_dict / param_to_dict the JSON form, and collect_genes, collect_project_genes and collect_fits list the genes and fits of a schedule or Project.
- class neurogenesis.params.Const(value: 'Union[float, int, str, list, dict]')[source]
Bases:
object- value: float | int | str | list | dict
- class neurogenesis.params.Gene(path: 'Union[Tuple, List, str]', lo: 'float' = 0.0, hi: 'float' = 1.0, integer: 'bool' = False)[source]
Bases:
object- path: Tuple | List | str
- lo: float = 0.0
- hi: float = 1.0
- integer: bool = False
- class neurogenesis.params.Field(name: 'str', transform: 'Optional[str]' = None)[source]
Bases:
object- name: str
- transform: str | None = None
- class neurogenesis.params.Fit(target: 'str', init: 'float', lo: 'float', hi: 'float')[source]
Bases:
object- target: str
- init: float
- lo: float
- hi: float
- neurogenesis.params.param_from_dict(d: Dict[str, Any] | Any) Const | Gene | Field | Fit | Expr[source]
Converts a dictionary or primitive to a Param object.
A dict is a Param source when its “type” is one of Const, Gene, Field, Fit, Expr, or, without “type”, when its keys are exactly those of one source: {“value”}, {“path”, “lo”, “hi”[, “integer”]}, {“name”, “transform”}, {“target”, “init”, “lo”, “hi”} or {“formula”}. Any other dict (e.g. a guidance dict with a “target” key) is a plain value, Const(d).
- neurogenesis.params.worst_case(param: Any, default: Any) Any[source]
Value of a Param for cost estimates (declared before the genome is known).
A Const gives its value, a Gene or Fit its upper bound hi, a Field or Expr (or None) gives default; a dict is read with param_from_dict first, and any other value is returned as is.
- neurogenesis.params.param_to_dict(param: Const | Gene | Field | Fit | Expr | Any) Dict[str, Any][source]
- neurogenesis.params.resolve(param: Const | Gene | Field | Fit | Expr | Dict[str, Any] | Any, genome: Dict[str, Any], fields: Dict[str, Any], positions: ndarray | None = None, cell_indices: ndarray | None = None, context_vars: Dict[str, Any] | None = None) float | int | ndarray | str[source]
- neurogenesis.params.resolve_nested(value: Any, genome: Dict[str, Any], fields: Dict[str, Any]) Any[source]
resolve applied at every depth of nested dicts and lists (no positions): a Param anywhere inside, e.g. a Gene in one entry of a matrix, is replaced by its value; plain values and plain dicts are kept.
- neurogenesis.params.collect_genes(stage_configs: List[Dict[str, Any]]) List[Tuple[Tuple, float, float, bool]][source]
All genes used by stage configs, nested params included, as (path, lo, hi, integer) tuples sorted by str(path).
A path used several times is listed once, with the bounds of its first use in schedule order.
- neurogenesis.params.collect_project_genes(project: Dict[str, Any]) List[Tuple[Tuple, float, float, bool]][source]
All genes of a Project: those of its schedule (as
collect_genes) and those inside its rawfieldsdefinitions (e.g. layer thicknesses given as Gene dicts). Same format and order ascollect_genes.
- neurogenesis.params.collect_fits(project: Dict[str, Any]) List[Tuple[str, float, float, float]][source]
All Fit params of a Project (schedule and field definitions) as (target, init, lo, hi), sorted by target. Fits sharing a target share one fitted value (bounds and init of the first use in schedule order).
Stage interface and scheduler (A4).
register_stage adds a stage class (run(tissue, params, genome, fields, rng), cost(N, E, params)) to STAGE_REGISTRY; Stage is one schedule entry (when condition, repeat); run_schedule runs a Project’s schedule with one random stream per stage name and repeat; schedule_cost sums the declared costs.
- class neurogenesis.stages.base.Stage(name: 'str', operator: 'str', params: 'Dict[str, Param]', when: 'Optional[str]' = None, repeat: 'int' = 1)[source]
Bases:
object- name: str
- operator: str
- when: str | None = None
- repeat: int = 1
- neurogenesis.stages.base.schedule_cost(project: Dict[str, Any], N: int, E: int) Tuple[int, int][source]
Sums up the expected bytes and ops cost of the entire schedule.
- neurogenesis.stages.base.run_schedule(project: Dict[str, Any], genome: Dict[str, Any], seed: int, checkpoints: bool = False, legacy_stream: bool = False) Tissue | List[Tissue][source]
Tissue state (A2): the struct-of-arrays state that stages read and write.
Tissue holds per-cell arrays (positions, lineage, type, region, expression, sign, alive, birth time, transmitters, receptors, morphology) and a SparseConnectivity (pre, post, weight, delay, receptor class, and optional morphology and conductance arrays). Helpers add, compact, subset and concatenate cells with every array kept aligned, and to_network compiles a tissue to a simulation network.
- class neurogenesis.tissue.SparseConnectivity(pre: ndarray, post: ndarray, weight: ndarray, delay: ndarray, receptor_class: ndarray | None = None, pre_node: ndarray | None = None, post_node: ndarray | None = None, path_length: ndarray | None = None, dendritic_distance: ndarray | None = None, e_rev: ndarray | None = None, tau_decay: ndarray | None = None, plastic: ndarray | None = None, contacts: ndarray | None = None)[source]
Bases:
objectSynapses as struct of arrays. receptor_class (E,) uint8 (0 = the classic signed synapse) always exists; the morphology arrays pre_node, post_node (arbor node indices, -1 = soma / none), path_length and dendritic_distance (space units, NaN = unknown), conductance arrays e_rev (mV), tau_decay (ms) and the plasticity mask plastic (bool; None = every synapse plastic, see plastic_mask) are None until a stage sets them. Use take and concat to filter or join synapses so that every array stays aligned.
- pre: ndarray
- post: ndarray
- weight: ndarray
- delay: ndarray
- receptor_class: ndarray | None = None
- pre_node: ndarray | None = None
- post_node: ndarray | None = None
- path_length: ndarray | None = None
- dendritic_distance: ndarray | None = None
- e_rev: ndarray | None = None
- tau_decay: ndarray | None = None
- plastic: ndarray | None = None
- contacts: ndarray | None = None
- classmethod empty() SparseConnectivity[source]
- take(sel: ndarray, pre: ndarray | None = None, post: ndarray | None = None) SparseConnectivity[source]
Synapses selected by a boolean mask or index array (every array kept aligned); pre / post replace the selected indices (e.g. after re-indexing cells).
- classmethod concat(parts: List[SparseConnectivity]) SparseConnectivity[source]
Synapses of several stores; optional arrays present in any part are filled with their default elsewhere.
- append(pre, post, weight, delay, **extra) SparseConnectivity[source]
This store plus new synapses (int32 core arrays; extra per-synapse arrays such as receptor_class).
- class neurogenesis.tissue.Tissue(positions: 'np.ndarray', directions: 'np.ndarray', cell_id: 'np.ndarray', parent_id: 'np.ndarray', clone_id: 'np.ndarray', birth_stage: 'np.ndarray', cell_type: 'np.ndarray', region: 'np.ndarray', expression: 'np.ndarray', sign: 'np.ndarray', alive: 'np.ndarray', mode: 'np.ndarray', shift_v: 'np.ndarray', shift_s: 'np.ndarray', base_weight: 'np.ndarray', conn_radius: 'np.ndarray', conn_prob: 'np.ndarray', burst_period: 'np.ndarray', burst_duty: 'np.ndarray', poisson_hz: 'np.ndarray', refractory: 'np.ndarray', role: 'np.ndarray', compartment: 'np.ndarray', threshold: 'np.ndarray', connectivity: 'SparseConnectivity', expression_names: 'List[str]' = <factory>, _next_cell_id: 'int' = 0, generation: 'Optional[np.ndarray]' = None, cycling: 'Optional[np.ndarray]' = None, birth_time: 'Optional[np.ndarray]' = None, transmitter: 'Optional[np.ndarray]' = None, receptor_expression: 'Optional[np.ndarray]' = None, morphology: 'Optional[object]' = None)[source]
Bases:
object- positions: ndarray
- directions: ndarray
- cell_id: ndarray
- parent_id: ndarray
- clone_id: ndarray
- birth_stage: ndarray
- cell_type: ndarray
- region: ndarray
- expression: ndarray
- sign: ndarray
- alive: ndarray
- mode: ndarray
- shift_v: ndarray
- shift_s: ndarray
- base_weight: ndarray
- conn_radius: ndarray
- conn_prob: ndarray
- burst_period: ndarray
- burst_duty: ndarray
- poisson_hz: ndarray
- refractory: ndarray
- role: ndarray
- compartment: ndarray
- threshold: ndarray
- connectivity: SparseConnectivity
- expression_names: List[str]
- generation: ndarray | None = None
- cycling: ndarray | None = None
- birth_time: ndarray | None = None
- transmitter: ndarray | None = None
- receptor_expression: ndarray | None = None
- morphology: object | None = None
- property lineage_id: ndarray
Alias for backward compatibility.
- add_cells(N: int, positions: ndarray | None = None, K: int = 0, parent_ids: ndarray | None = None, **kwargs) None[source]
Adds N new cells. cell_ids are automatically assigned.
- compact() None[source]
Removes dead cells, remaps connectivity indices, dropping synapses attached to dead cells.
- subset(indices: ndarray) Tissue[source]
Returns a new Tissue with only the given cell indices (assumes connectivity only between subset).
- to_network() SNNNetwork[source]
Network of the live cells and their synapses. cycling and the synapse plastic mask (when set) ride along as the in-memory attributes _cycling / _plastic read back by from_network; network files do not store them (the kernels ignore them).
- classmethod from_network(net: SNNNetwork) Tissue[source]
Geometry and fields
Geometries (B1-B2): primitives, set operations, triangle meshes and voxel masks, with a JSON registry.
- class neurogenesis.geometry.Cylinder(p0: ndarray, p1: ndarray, radius: float)[source]
Bases:
Geometry
- class neurogenesis.geometry.Sheet2D(center: ndarray, u_vec: ndarray, v_vec: ndarray, thickness: float)[source]
Bases:
Geometry
- class neurogenesis.geometry.CurvedSheet(x_expr: str, y_expr: str, z_expr: str, thickness: float)[source]
Bases:
Geometry
- class neurogenesis.geometry.MeshGeometry(vertices: ndarray, faces: ndarray, resolution: int = 32)[source]
Bases:
GeometryClosed triangle mesh: exact point-in-mesh by ray parity plus an occupancy voxel cache.
Ray parity is vectorised over faces: for a fixed ray direction d, the Moller-Trumbore coordinates u, v, t of every (point, face) pair are linear in the point, so they are computed as (P, 3) @ (3, F) products. Point and face blocks are chunked so that at most
MAX_PAIRS(point, face) pairs are held at once (a few float64 arrays of that size, about 8 MB each); cost is O(P * F) operations and O(MAX_PAIRS) memory.- MAX_PAIRS = 1048576
- classmethod from_obj(filepath: str) MeshGeometry[source]
- classmethod from_stl(filepath: str) MeshGeometry[source]
- contains(points: ndarray) ndarray[source]
Exact point-in-mesh test by ray parity (bounding-box prefilter).
- sample_points(n: int, rng: Generator) ndarray[source]
Uniform samples in the mesh volume.
Draws uniform points in voxels of the cache that are inside or crossed by the surface (all voxels have the same volume) and keeps those passing the exact point-in-mesh test; points in voxels wholly inside are kept without testing.
- class neurogenesis.geometry.VoxelMaskGeometry(mask: ndarray, origin: ndarray, pitch: ndarray, source: str | None = None)[source]
Bases:
GeometryOccupancy mask on an axis-aligned voxel grid; voxel (i, j, k) spans origin + [i, i+1) * pitch.
- classmethod from_npz(path: str) VoxelMaskGeometry[source]
Load a mask from a
.npzfile.Keys:
mask(3D array, nonzero = inside) and eitheraffine(4 x 4 voxel-index to space transform, axis-aligned: diagonal = voxel size, last column = origin of voxel (0, 0, 0)’s corner) ororiginandvoxel_size(3-vectors;pitchaccepted).
- neurogenesis.geometry.geometry_from_dict(d: dict) Geometry[source]
Instantiate a Geometry from a dictionary with a registered ‘type’ field.
- neurogenesis.geometry.register_geometry(type_name: str) Callable[[Type], Type][source]
Decorator to register geometry types for dynamic serialization/deserialization.
Field types (B3) and their JSON registry.
Field is the interface (values(points), to_dict); GridField (nearest or linear interpolation on a regular grid), AnalyticField (a formula of x, y, z, evaluated by expressions.eval_expr), LayerStackField (layers of Param thicknesses along an axis), VectorField and LabelField. register_field / field_from_dict map JSON types to classes.
- class neurogenesis.fields.core.Field[source]
Bases:
ABC
- class neurogenesis.fields.core.GridField(data: ndarray | list, origin: List[float] | ndarray, spacing: List[float] | ndarray, method: str = 'nearest')[source]
Bases:
Field
- class neurogenesis.fields.core.LayerStackField(base_field: Field, thicknesses: List[Any], labels: List[int] | None = None)[source]
Bases:
FieldLayer label and relative depth w in [0, 1] within the layer, from a depth field.
thicknessesentries are numbers or Params (Const,Gene,Exprobjects or their dicts); Gene-controlled thicknesses are resolved bybind(genome), whichrun_schedulecalls with the run’s genome.
- class neurogenesis.fields.core.VectorField(components: List[Field])[source]
Bases:
FieldVector field whose components are scalar fields; values have shape (…, n_components).
- class neurogenesis.fields.core.LabelField(data: ndarray | list, origin: List[float] | ndarray, spacing: List[float] | ndarray, background: int = -1, names: Dict[str, str] | None = None)[source]
Bases:
FieldInteger labels on a 2D / 3D grid; cell (i, j[, k]) spans origin + [i, i+1) * spacing.
Sampling is nearest-cell (labels are never interpolated); points outside the grid get
background.namesoptionally maps labels to region names.
Point patterns and maps (B4).
Point sets: regular_points, jittered_points, poisson_disc_points (Bridson’s dart throwing with k attempts per point; Bridson, 2007, ACM SIGGRAPH sketches) and PointSetField. Orientation maps: pinwheel_map from given singularities, bandpass_pinwheels (band-pass filtered noise; Swindale, 1996, Network: Computation in Neural Systems; Kaschube, 2010, Science), PinwheelField, find_pinwheels and pinwheel_charges. Randomness only from the given rng.
- neurogenesis.fields.maps.regular_points(bounds: Tuple[ndarray, ndarray], spacing: float | List[float]) ndarray[source]
- neurogenesis.fields.maps.jittered_points(bounds: Tuple[ndarray, ndarray], spacing: float | List[float], jitter: float, rng: Generator) ndarray[source]
- neurogenesis.fields.maps.poisson_disc_points(bounds: Tuple[ndarray, ndarray], radius: float, rng: Generator, k: int = 30) ndarray[source]
- neurogenesis.fields.maps.pinwheel_map(bounds: Tuple[ndarray, ndarray], spacing: float, singularities: ndarray, charges: ndarray) Tuple[ndarray, ndarray, ndarray][source]
Generates an orientation map from singularities. Returns: points grid, angle field (N, M), and pinwheel positions.
- neurogenesis.fields.maps.find_pinwheels(angles: ndarray, origin: ndarray | list, spacing: float | list) Tuple[ndarray, ndarray][source]
Pinwheels of an orientation grid (angles in [0, pi) on a regular 2D grid, axis 0 = x): (positions (K, 2), charges).
For each grid square, the steps of 2 theta around its four corners are wrapped to (-pi, pi] and summed; a winding of +-2 pi is a pinwheel of charge +-1/2 placed at the square’s centre. O(grid size), no loops.
- neurogenesis.fields.maps.bandpass_pinwheels(bounds: Tuple[ndarray, ndarray], spacing: float, k0: float, sigma: float, rng: Generator, return_pinwheels: bool = False)[source]
Generates an orientation map using bandpass filtered noise. Returns points grid and angle field; with return_pinwheels (2D bounds only) also the pinwheel positions and charges found by find_pinwheels.
- class neurogenesis.fields.maps.PinwheelField(singularities: ndarray | list, charges: ndarray | list, phase: float = 0.0)[source]
Bases:
FieldOrientation angle in [0, pi) around hand-placed pinwheel singularities.
theta(x) = phase + sum_k q_k atan2(y - y_k, x - x_k) (mod pi), using the first two coordinates of the points; a singularity of charge q = +-1/2 rotates the orientation by +-pi around it. Orientation maps with pinwheels: Swindale 1996 (Network: Computation in Neural Systems); pinwheel density and statistics: Kaschube et al. 2010 (Science).
- neurogenesis.fields.maps.pinwheel_charges(field: Field, centres: ndarray, radius: float, n_samples: int = 64) ndarray[source]
Charge of the orientation field around each centre: winding of 2 theta on a circle / (4 pi).
The circle of
radiusaround each centre (in the first two coordinates) is sampled atn_samplespoints; steps of 2 theta are wrapped to (-pi, pi] and summed.
- class neurogenesis.fields.maps.PointSetField(points: Any = None, pattern: str = None, bounds: Any = None, spacing: Any = None, jitter: float = 0.0, radius: float = None, seed: int = 0)[source]
Bases:
FieldA point set (B4) as a field: values is the distance from each query point to the nearest point of the set.
Points are given (points, (M, d) with d <= 3, missing coordinates 0) or generated deterministically from a pattern: pattern “regular”, “jittered” or “poisson_disc” with bounds, spacing / jitter / radius and seed. seed_cells accepts it as points; e.g. blob centres or pinwheel centres. Nearest-point search through the cell list (O(M + queries)).
Genomes, evolution, modules
Genomes: nested dicts of genes; gene addressing, [0, 1] coding, gene groups and JSON.
- neurogenesis.genome.from_unit(genome, genes, u, integer_roots=('count', 'excitability'))[source]
Copy of genome with gene k set to low_k + clip(u_k, 0, 1) (high_k - low_k).
- neurogenesis.genome.rebound(genes, new)[source]
Gene list with some bounds replaced: new = {path: (low, high)}.
- neurogenesis.genome.set_gene(genome, path, v)[source]
Set a gene in place (array values are replaced by modified copies).
- neurogenesis.genome.to_unit(genome, genes) ndarray[source]
Gene values of a genome scaled to [0, 1] (clipped).
- neurogenesis.genome.body_genes(region, count=(16, 256))[source]
Count, excitability, migration and inhibitory fraction of a grown region.
- neurogenesis.genome.differentiation_genes(region)[source]
Lateral-inhibition differentiation of a region (neurogenesis.development.differentiation).
- neurogenesis.genome.field_genes(src, dst, w_lo=0.0, w_hi=512.0)[source]
Field width, probability and weight of a projection (no change of its topography).
- neurogenesis.genome.guidance_genes(src, dst, w_lo=20.0, w_hi=512.0)[source]
Positional guidance of a projection: B (3 x 3), c (3), sigma, p0, w.
- neurogenesis.genome.identity_genes(region, k=6, root='identity')[source]
Molecular identity code of a region: K x (a_k0, a_k) logits.
- neurogenesis.genome.typed_guidance_genes(src, dst, k=6)[source]
Identity-dependent guidance of a projection: per source identity, a target offset (3) and an expression level (1).
- neurogenesis.genome.from_json(d)[source]
Genome from its JSON form: “a->b” keys become tuples, numeric lists become arrays.
Evolution of genomes (island model) and robustness to developmental randomness.
- neurogenesis.evolution.choose(base, genes, P, evaluate, seeds, integer_roots=('count', 'excitability'), top=None)[source]
Best genome of a final population on given (validation) seeds. Returns (genome, its evaluation info).
- neurogenesis.evolution.evolve(base, genes, evaluate, island=0, pop=64, gens=150, seeds_per_gen=6, elite=2, parents=16, sigma=0.1, integer_roots=('count', 'excitability'), log=None)[source]
Evolve one island.
evaluate(genomes, seeds) -> (fitness array, list of per-genome info dicts). Returns (final population as [0, 1] vectors, history list). log(dict) is called after every generation.
- neurogenesis.evolution.seeds_of(island, generation, n)[source]
Development seeds of one generation: distinct across islands and generations, never equal to small audit seeds.
- neurogenesis.evolution.audit(evaluate_one, genome, seeds=(1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019), keep=())[source]
Per-individual audit of one genome on seeds never used in evolution. evaluate_one(genome, seeds) -> result dict.
- neurogenesis.evolution.robust_value(r, mean_weight=0.25)[source]
Worst individual’s score + mean_weight x mean score - cost.
Shareable, composable modules (plan + genome + interface + validation).
- class neurogenesis.modules.Module(name: 'str', plan: 'BodyPlan', genome: 'dict', inputs: 'list' = <factory>, outputs: 'list' = <factory>, description: 'str' = '', validation: 'dict' = <factory>, provenance: 'dict' = <factory>, neuron_model: 'str' = 'lif_int', version: 'str' = '0.1.0', toolbox: 'str' = '*')[source]
Bases:
object- name: str
- genome: dict
- inputs: list
- outputs: list
- description: str = ''
- validation: dict
- provenance: dict
- neuron_model: str = 'lif_int'
- version: str = '0.1.0'
- toolbox: str = '*'
- neurogenesis.modules.compose(name, modules, links=(), offsets=None, inh_weight_factor=2.0, w_clip=512)[source]
One plan and genome from several modules.
modules: {prefix: Module}. links: [(src, dst, guidance genes)] with prefixed region names (“retina.ganglion”). offsets: {prefix: (dx, dy, dz)} shifts a module’s regions in space (this changes conduction delays of links only). Returns a Module whose inputs and outputs are those of the parts, prefixed.
Spiking
Data structures and serialization for 3D Spiking Neural Networks (SNN).
Handles Structure-of-Arrays (SoA), Compressed Sparse Row (CSR) graph conversions, JSON serialization/deserialization compatible with the WebGL2 morphogenetic visualizer, and network topology graph analytics.
- class neurogenesis.spiking.network.NeuronData(id: 'int', x: 'float', y: 'float', z: 'float', dir_x: 'float', dir_y: 'float', dir_z: 'float', mode: 'int', shift_v: 'int' = 5, shift_s: 'int' = 4, base_weight: 'int' = 180, conn_radius: 'float' = 28.0, conn_prob: 'float' = 0.38, burst_period: 'int' = 200, burst_duty: 'int' = 24, poisson_hz: 'float' = 25.0, refractory: 'int' = 0, role: 'int' = 0, compartment: 'int' = -1, threshold: 'int' = 1024)[source]
Bases:
object- id: int
- x: float
- y: float
- z: float
- dir_x: float
- dir_y: float
- dir_z: float
- mode: int
- shift_v: int = 5
- shift_s: int = 4
- base_weight: int = 180
- conn_radius: float = 28.0
- conn_prob: float = 0.38
- burst_period: int = 200
- burst_duty: int = 24
- poisson_hz: float = 25.0
- refractory: int = 0
- role: int = 0
- compartment: int = -1
- threshold: int = 1024
- class neurogenesis.spiking.network.SynapseData(pre: 'int', post: 'int', weight: 'int', delay: 'int')[source]
Bases:
object- pre: int
- post: int
- weight: int
- delay: int
- class neurogenesis.spiking.network.SNNNetwork(version: 'str' = '1.0.0', morphology: 'str' = 'Custom', neurons: 'List[NeuronData]' = <factory>, synapses: 'Union[List[SynapseData], _SynapseListView]' = <factory>, synapse_arrays: 'Optional[Dict[str, np.ndarray]]' = None)[source]
Bases:
object- version: str = '1.0.0'
- morphology: str = 'Custom'
- neurons: List[NeuronData]
- synapses: List[SynapseData] | _SynapseListView
- synapse_arrays: Dict[str, ndarray] | None = None
- classmethod from_arrays(version: str, morphology: str, neurons: List[NeuronData], synapse_arrays: Dict[str, ndarray]) SNNNetwork[source]
- property num_neurons: int
- property num_synapses: int
- to_dict() Dict[str, Any][source]
Convert network to a JSON-serializable dictionary matching the Web format.
- classmethod from_dict(data: Dict[str, Any]) SNNNetwork[source]
Construct SNNNetwork from parsed JSON data.
- classmethod load_json(path: str | Path) SNNNetwork[source]
Load a network from a JSON file.
- classmethod load_npz(path: str | Path) SNNNetwork[source]
Load a network from an NPZ file.
Batched simulation of many networks with the JAX kernel: each network sees its own sequence of constant stimuli.
Bit-identical to running each network alone with neurogenesis.spiking.jax_backend.tick (padding neurons never spike).
- neurogenesis.spiking.batch.pad_sizes(nets)[source]
Common padded sizes: neurons rounded up to a multiple of 128, synapses to a power of 2 (fewer recompilations), Poisson drivers to the largest number in the batch (at least 1).
- neurogenesis.spiking.batch.stack(nets)[source]
Packed, padded and stacked arrays of a list of networks (leading axis = network).
- neurogenesis.spiking.batch.simulate_counts(nets, ext_list, ticks=50, blank=0, model='lif_int', check_cost=True, force=False)[source]
Spike counts (S, N_pad) per network for a sequence of S stimuli.
ext_list[i]: (S, n_i) int32 external currents of network i, one row per stimulus, applied at every tick of the stimulus. Each stimulus lasts ticks ticks and is preceded by blank ticks without input; only stimulus ticks are counted. The network state is carried over from one stimulus to the next. Network i uses kernel seed i.
model: neuron model (neurogenesis.spiking.models): “lif_int” (default, the integer kernel), “two_compartment”, “hh”. check_cost: estimate memory and time first (neurogenesis.cost); refuse if the memory does not fit, unless force.
Neuron models over one shared transmission layer (synapses, delays, drivers): choose the level of biophysical detail per simulation; estimate its cost first with neurogenesis.cost.
- neurogenesis.spiking.models.register_model(module)[source]
Add a neuron model (a module or object with name, description, substeps, state_bytes, flops, init_state, tick).
Plasticity rules (E1) on struct-of-arrays synapses, in JAX.
STDPRule: pair-based spike-timing-dependent plasticity with pre / post traces, hard or soft bounds, optional integer traces (Bi, 1998, Journal of Neuroscience; Song, 2000, Nature Neuroscience). HebbianRule: Hebbian growth with subtractive or multiplicative normalisation (Miller, 1994, Neural Computation) or Oja’s rule (Oja, 1982, Journal of Mathematical Biology). ThreeFactorRule: eligibility trace times a modulator (Izhikevich, 2007, Cerebral Cortex; Fremaux, 2016, Frontiers in Neural Circuits). Each rule has a per-tick step, an apply over a spike raster, and keeps weight signs (Dale’s principle).
- class neurogenesis.spiking.plasticity.STDPRule(A_plus: float = 1.0, A_minus: float = 1.0, tau_plus: float = 20.0, tau_minus: float = 20.0, w_min: float = 0.0, w_max: float = 1000.0, soft_bounds: bool = False, integer_traces: bool = False)[source]
Bases:
object- init_state(num_neurons: int, num_synapses: int) Tuple[Array, Array][source]
Returns initial (tr_pre_syn, tr_post_neuron) state for tick-by-tick simulation.
- step(weights: Array, pre: Array, post: Array, spikes_post: Array, arrivals_pre: Array, tr_pre_syn: Array, tr_post_neuron: Array, original_weights: Array | None = None) Tuple[Array, Array, Array][source]
Tick-by-tick update for online simulation loop (no T x N memory required).
arrivals_pre: (E,) binary / float indicating pre-synaptic spike arrival at each synapse at current tick. spikes_post: (N,) binary indicating whether each post-synaptic neuron spiked at current tick.
- class neurogenesis.spiking.plasticity.HebbianRule(eta: float = 0.01, norm_target: float = 1.0, norm_type: str = 'l1_subtractive')[source]
Bases:
object- step(weights: Array, pre: Array, post: Array, spikes_post: Array, arrivals_pre: Array, num_neurons: int, original_weights: Array | None = None) Array[source]
Single tick step update for online simulation loop.
- class neurogenesis.spiking.plasticity.ThreeFactorRule(eta: float = 0.01, tau_e: float = 20.0)[source]
Bases:
object- step(weights: Array, pre: Array, post: Array, spikes_post: Array, arrivals_pre: Array, elig: Array, modulator_val: float | Array, original_weights: Array | None = None) Tuple[Array, Array][source]
Single tick step for ThreeFactorRule.
Cost and analysis
Compute cost of a simulation before running it: memory, operations and wall time, per neuron model, on this machine.
Memory is counted array by array as the kernels allocate it (neuron parameters, model state, synapse arrays, temporary arrivals, recorded counts). Time per tick is t = a + N x substeps x b + E x c, with a (fixed overhead per tick), b (seconds per neuron-substep) and c (seconds per synapse-tick) measured once per model and device by a short benchmark (calibrate) and cached in ~/.cache/neurogenesis/throughput.json. Estimates for networks far larger than the benchmark extrapolate linearly and ignore effects such as cache misses or multi-device communication: treat them as optimistic lower bounds.
python -m neurogenesis estimate –neurons 3e8 –synapses-per-neuron 5000 –seconds 1
- exception neurogenesis.cost.CostError[source]
Bases:
RuntimeErrorThe simulation does not fit in this machine’s memory (pass force=True to try anyway).
- neurogenesis.cost.available_memory()[source]
Bytes available to the simulation: free GPU memory if JAX runs on a GPU, else physical RAM.
- neurogenesis.cost.memory_bytes(model, n_neurons, n_synapses, n_records=1, max_delay=31)[source]
Bytes needed: parameters and state of every neuron, synapse arrays and their per-tick buffers, recorded counts.
- neurogenesis.cost.calibrate(model, refresh=False)[source]
Fixed seconds per tick (a), seconds per neuron-substep (b) and per synapse-tick (c) for a model on this device, fitted on three benchmark networks, measured once and cached.
- neurogenesis.cost.estimate(model, n_neurons, n_synapses, ticks, n_records=1, calibrated=True, max_delay=31)[source]
dict: memory (bytes), available memory, fits (bool), operations per tick, seconds per tick and in total (None if not calibrated and calibrated=False), and a one-line verdict.
- neurogenesis.cost.check(model, n_neurons, n_synapses, ticks, force=False, warn_seconds=3600, max_delay=31)[source]
Called before every batched simulation: refuses networks that do not fit in memory (CostError, unless force), and warns when a calibrated time estimate exceeds warn_seconds. Never runs a benchmark itself.
Measures on grown networks.
- neurogenesis.analysis.nearest_neighbour_regularity(xy) float[source]
Nearest-neighbour regularity index of a cell mosaic: mean / s.d. of each cell’s distance to its nearest neighbour (about 1.9 for random positions; larger for regular mosaics, e.g. retinal cell types).
- neurogenesis.analysis.fi_curve(currents, shift_v=5, shift_s=4, threshold=1024, refractory=3, ticks=1000, model='lif_int')[source]
Firing probability per tick of one isolated neuron for each constant external current (added every tick), each current applied to a fresh copy of the neuron starting from rest (models with bistability, such as Hodgkin-Huxley, would otherwise depend on the order of the currents): the frequency-current curve of a cell type.
Interoperability
Format registry and export reports shared by every importer and exporter (roadmap task J1).
A format module registers itself with register_format(name, export=…, import_=…, extra=…). Exporters return an ExportReport saying which network fields were written exactly, which were approximated (and how), and which were dropped, so that a user always knows what the file in another simulator’s format still means.
- class neurogenesis.interop.core.ExportReport(format: str, path: str, exact: List[str] = <factory>, approximated: Dict[str, str]=<factory>, dropped: Dict[str, str]=<factory>, counts: Dict[str, int]=<factory>)[source]
Bases:
objectWhat an export kept. approximated and dropped map a field to an explanation.
- format: str
- path: str
- exact: List[str]
- approximated: Dict[str, str]
- dropped: Dict[str, str]
- counts: Dict[str, int]
- property lossless: bool
- neurogenesis.interop.core.register_format(name: str, export: Callable | None = None, import_: Callable | None = None, extra: str | None = None, description: str = '') None[source]
Register a format. export(net, path, **opts) -> ExportReport, import_(path, **opts) -> SNNNetwork; extra names the optional dependency group (pip install “neurogenesis-sim[extra]”).
- neurogenesis.interop.core.formats() List[str][source]
Names of the registered and built-in formats.
- neurogenesis.interop.core.as_network(net: SNNNetwork | str | Path) SNNNetwork[source]
An SNNNetwork from an object, a network JSON file or an NGB1 file.
- neurogenesis.interop.core.export_network(net: SNNNetwork | str | Path, fmt: str, path: str | Path, **opts) ExportReport[source]
Write a network in format fmt to path; returns what was kept, approximated and dropped.
- neurogenesis.interop.core.import_network(fmt: str, path: str | Path, **opts) SNNNetwork[source]
Read a network written in format fmt.
- neurogenesis.interop.core.require(module: str, extra: str)[source]
Import an optional dependency, or explain which extra installs it.
One translation of the integer LIF neuron into a current-based exponential LIF, shared by all exporters.
The integer kernel (neurogenesis.spiking.reference) updates every neuron once per tick of 1 ms:
v <- v - max(1, v >> shift_v) (leak; the mirror rule for v < 0)
I <- I - max(1, I >> shift_s) (decay of the neuron's synaptic current, same rounding)
v <- v + (I >> 2) (floor of I / 4), then v is clamped to [-2048, 2048]
spike when v >= threshold; then v <- -256, held there with no spike for `refractory` ticks
a spike at tick t through a synapse of delay d adds `weight` to the target's I at the end of tick t + d,
so it first moves v at tick t + d + 1
Without rounding this is the 1-ms sampling of a current-based exponential LIF:
dV/dt = (E_L - V) / tau_m + I / C_m, tau_syn dI/dt = -I,
with these correspondences (a = 2^-shift):
tau = -1 ms / ln(1 - a): the per-tick decay factors match exactly (2^shift ms overestimates tau, by 39 % at shift 1 and 1.6 % at shift 5);
voltage = E_L + s * v for a free scale s (mV per unit): exact, spikes are invariant under it. The default (E_L = -65 mV, s = 15/1024 mV) puts the default threshold of 1024 units at -50 mV, as in PyNN’s defaults;
a weight w becomes a current jump W = C_m * s * w * (1 - a) / (4 a tau_syn) (a = 2^-shift_s), which delivers the same total charge to V as w delivers to v: an approximation of the PSP shape;
a delay of d ticks becomes d + 1 ms (the extra tick of synaptic latency), always >= 1 ms;
the refractory period is refractory ms.
Integer rounding, the minimum decrement of 1, the clamp and the 1-ms time step are not represented: spike times in another simulator are close, not identical. Exporters that can carry extra attributes also store the raw integers, so that reading the file back into the toolbox is exact.
- neurogenesis.interop.dynamics.tau_ms(shift: int) float[source]
Time constant (ms) whose 1-ms decay factor equals the kernel’s 1 - 2^-shift (shift >= 1).
- neurogenesis.interop.dynamics.shift_from_tau(tau: float) int[source]
The kernel shift whose time constant is closest to tau (ms), for importers.
- neurogenesis.interop.dynamics.delay_ms(delay_ticks: int) float[source]
Delay in ms of a synapse of delay_ticks, including the kernel’s extra tick of latency.
- neurogenesis.interop.dynamics.delay_ticks(delay: float) int[source]
Inverse of delay_ms, for importers.
- class neurogenesis.interop.dynamics.LIFParams(tau_m: float, tau_syn: float, C_m: float, E_L: float, V_reset: float, V_th: float, t_ref: float, mV_per_unit: float, shift_s: int)[source]
Bases:
objectCurrent-based exponential LIF parameters of one neuron: ms, mV, pF; currents in pA.
- tau_m: float
- tau_syn: float
- C_m: float
- E_L: float
- V_reset: float
- V_th: float
- t_ref: float
- mV_per_unit: float
- shift_s: int
- neurogenesis.interop.dynamics.lif_params(neuron, mV_per_unit: float = 0.0146484375, E_L: float = -65.0, C_m: float = 250.0) LIFParams[source]
The shared translation of one NeuronData (drivers keep their LIF part).
SONATA network files: writer and reader (roadmap task J2).
SONATA (Dai et al. 2020, PLoS Comput Biol 16:e1007696) stores nodes and edges in HDF5 with CSV type tables and a JSON circuit config; BMTK, NEST (via BMTK PointNet), NEURON and libsonata read it. Layout written here, checked against the SONATA developer guide and BMTK’s example circuits:
<dir>/circuit_config.json
<dir>/network/nodes.h5 /nodes/<pop>/{node_id, node_type_id, node_group_id, node_group_index}
/nodes/<pop>/0/{x, y, z, ngs_*}, /nodes/<pop>/0/dynamics_params/<NEST iaf_psc_exp>
<dir>/network/edges.h5 /edges/<pop>_to_<pop>/{source_node_id, target_node_id, edge_type_id, ...}
/edges/<pop>_to_<pop>/0/{syn_weight (pA), delay (ms), ngs_weight, ngs_delay}
/edges/<pop>_to_<pop>/indices/{source_to_target, target_to_source}/...
<dir>/network/node_types.csv, edge_types.csv
<dir>/components/point_neuron_models/*.json, synaptic_models/static_synapse.json
One population, one attribute group “0” (libsonata reads only that). Simulator-facing values (positions, NEST iaf_psc_exp parameters, weights in pA, delays in ms) follow neurogenesis.interop.dynamics; every toolbox field is also stored raw (ngs_*), so that reading a file written here gives back the same network exactly. Files from other tools are read through their positions, NEST-style dynamics parameters, weights and delays.
- neurogenesis.interop.sonata.export_sonata(net: SNNNetwork, path: Path, population: str = 'ngs', mV_per_unit: float = 0.0146484375, E_L: float = -65.0, C_m: float = 250.0) ExportReport[source]
Write net as a SONATA circuit in directory path; returns the export report.
- neurogenesis.interop.sonata.import_sonata(path: Path, population: str | None = None, mV_per_unit: float = 0.0146484375) SNNNetwork[source]
Read a SONATA circuit (a directory holding circuit_config.json, or the config file itself).
Files written by export_sonata give back the original network exactly. For other files, each neuron gets the shifts closest to its tau_m / tau_syn, threshold 1024 (the voltage scale is set per neuron from V_th - E_L), its refractory period in ticks, and weights and delays through the inverse of the shared mapping; missing dynamics parameters keep the toolbox defaults.
Bridge
NGB1: the binary network format exchanged between the bridge and the desktop apps (desktop/common/PROTOCOL.md).
Little endian, no padding:
header b"NGB1", int32 N (neurons), int32 E (synapses), int32 flags (0)
neurons positions (N, 3) float64, directions (N, 3) float64,
then one int32 column (N,) per NEURON_I32 field, one float64 column (N,) per NEURON_F64 field
synapses pre, post, weight, delay: one int32 column (E,) each
extensions only when flags bit 0 is set: int32 C, then C optional named columns (EXT_DTYPES), which readers that do
not know them skip
Float64 keeps positions and Poisson rates exactly as in Python, so a round trip changes nothing.
- neurogenesis.bridge.ngb.nbytes(n_neurons: int, n_synapses: int) int[source]
Size of an NGB1 file: 16 + 112 N + 16 E bytes.
- neurogenesis.bridge.ngb.write_network(net, path, extensions=None) None[source]
Writes an SNNNetwork as NGB1. extensions: optional columns {name: (axis, array)}, axis “neuron” or “synapse”, array of shape (N or E,) or (N or E, components), any EXT_DTYPES type.