Frequently Asked Questions#

Do I need a GPU to use brainevent?#

No. Event-driven array and sparse-matrix operations run on CPU, GPU, and TPU. A GPU (and a host C++ compiler) is only required when you compile custom C++/CUDA kernels. See Installation.

Do I need to install the CUDA Toolkit separately?#

No. Installing jax[cuda12] or jax[cuda13] pulls in the nvidia-* pip packages, which already bundle nvcc, ptxas, and the CUDA runtime and headers. You still need the NVIDIA driver and a host C++ compiler (g++/clang++). Details in Installation.

How does the event-driven optimization actually work?#

When you multiply a BinaryArray by a connectivity structure, brainevent dispatches a kernel that iterates only over the active spike indices and accumulates their contributions. Work scales with the number of spikes, not the size of the matrix. See What is event-driven computation?.

Which connectivity format should I use?#

  • Explicit, reusable sparsity → CSR / CSC.

  • Large random connectivity → JITC (memory independent of synapse count).

  • Fixed number of connections per neuron → FixedPreNumConn / FixedPostNumConn.

See Choose a connectivity format and Sparse format trade-offs.

Can I learn or inspect individual JITC weights?#

No. JITC connectivity is regenerated from a seed inside the kernel and never materialised, so individual weights are not addressable. Use an explicit CSR matrix when you need plastic or inspectable weights. See Just-in-time connectivity.

Are computations reproducible?#

Yes. JITC connectivity is fully determined by its seed — the same seed reproduces the same matrix across processes and devices. Combine with JAX’s own PRNG-key discipline for end-to-end reproducibility.

Can I attach physical units to weights?#

Yes. brainevent integrates with BrainUnit, so weights and currents can carry units and be dimensionally checked, with no runtime cost. See Compute with physical units.

Which custom-kernel backend should I use?#

  • Numba (CPU) / Numba-CUDA, Warp (GPU) — convenient, decorator-based, no separate compiler step.

  • Raw C++/CUDA — maximum control, or to reuse existing native code.

For raw CUDA kernels, brainevent compiles your source via nvcc, registers XLA FFI targets, and caches compiled artifacts on disk for fast reloads. See The custom-kernel architecture and Compile a raw CUDA/C++ kernel.

How do I ship a custom CUDA kernel with my project?#

Place the kernel in a co-located .cu file and load it at import time:

# my_module/my_kernels.py
from pathlib import Path
from brainevent import load_cuda_file

_module = load_cuda_file(
    Path(__file__).parent / "my_kernels.cu",
    target_prefix="my_module.my_kernels",
)

Annotate each entry point in the .cu file with // @BE:

// @BE my_kernel arg arg ret stream
void my_kernel(const BE::Tensor& input,
               const BE::Tensor& weights,
               BE::Tensor& output,
               int64_t stream) {
    // kernel launch code
}

load_cuda_file compiles the kernel on first use, caches the .so to disk, and registers it as a JAX FFI target. Subsequent imports skip recompilation (see Caching).