Version 3.5.0
Version 3.5.0 (2026-07-05)
This release provides several major performance improvements, focused on random number generation, networks, and pregnancy. On a representative large simulation (50,000 agents, 100 years, SIS on a random network with births and deaths), the random number changes alone make the default configuration roughly 1.4x faster, or about 2x faster with common random numbers disabled (ss.options.crn = False); the network, transmission, and pregnancy changes described below provide further ~1.3x speedups on top of this, for a total of ~1.8-2.6x speedups.
Common random numbers
- Common random numbers (CRN) work by giving each agent a "slot" and drawing one random number per slot, so that the same agent makes the same decision regardless of what other agents do. Previously this was implemented by drawing
slots.max()+1numbers and keeping only those at the requested slots. Because newborn agents are assigned slots spread over a wide range (up toslot_scaletimes the population size), this could mean generating up to 5x more random numbers than were actually needed. The default CRN path now generates only the number of values needed, via a counter-based hash (ss.distributions.hash_uniforms(), a Numba-compiled splitmix64 algorithm keyed by the distribution seed and draw index) that maps each slot directly to a uniform value. This preserves CRN reproducibility while removing the redundant draws. - Added a new
crnoption (ss.options.crn, defaultTrue). Settingss.options.crn = Falseskips the slot machinery entirely. This is not CRN-safe across scenarios, but is statistically valid and considerably faster; it is useful when reproducibility across counterfactual scenarios is not required. - Sped up
ss.multi_random(used for pairwise transmission probabilities) by including a dedicated fast path for the common two-distribution case that avoids constructing a typed list on each call. - Regression: the
single_rngoption has been removed. Its purpose was to demonstrate the "single centralized RNG" behavior of other agent-based modeling frameworks; usess.options.crn = Falseinstead, which is both faster and demonstrates the same stochastic-branching problem. (Note, however, that it does not use a single RNG; this option is no longer available.) - Regression: because the default CRN mechanism changed, the exact random values produced for agent-indexed draws are different from previous versions. Results remain statistically equivalent and CRN reproducibility is preserved, but stored regression baselines will need to be regenerated.
RandomNet and HouseholdNet
- Regression:
ss.RandomNetis now a faster (~1.8x), approximate network in which the target end of each edge is drawn independently. The per-agent degree is therefore only approximately Poisson rather than exact. The previous exact behavior is available as the newss.RandomExactNet; switch to it if you rely on the exact degree distribution. - Edge generation for
ss.RandomExactnetworks (what were previously calledss.Random) now uses an in-place Fisher-Yates shuffle (ss.networks.fisher_yates_shuffle()) instead ofnp.random.permutation, about 1.3x faster. - Networks whose edges last a single timestep (
dur=0, e.g.ss.RandomNet) now regenerate edges via a zero-copy fast path that avoids concatenating onto the previous edge list each step. ssl.HouseholdNetinitialization is now fully vectorized across household assignment, edge construction, and female-head-of-household selection, for a performance improvement of 10-20x for large populations.ssl.HouseholdNet.add_births()was also vectorized, for a performance improvement of ~1.3x in high-turnover simulations.
Pregnancy
- The
ss.Pregnancyconception logic was optimized, for a ~20% performance improvement. - Regression: the default
slot_scaleforss.Pregnancywas increased from 5 to 100. Newborns are assigned a random slot in the range[n_agents, slot_scale·n_agents]; a larger range reduces the chance that two newborns share a slot (and therefore make identical random draws). Previously a largerslot_scalealso meant proportionally more random draws, but with the new hash-based CRN the number of draws no longer depends on the slot range, so the default was raised to reduce these collision artifacts at no performance cost. This changes results for models with pregnancy.
Other performance optimizations
- The disease transmission step now uses a Numba-compiled kernel (
_nb_transmit) that identifies transmitting edges in a single branchless pass and returns its result as a zero-copy view, about 1.4x faster at typical transmission densities. Effective transmissibility and susceptibility are computed directly on the raw state arrays, avoiding intermediateArrwrapper allocations. - Extracting the UIDs of a boolean state (
Arr.true(),Arr.uids, and boolean filtering) now uses a branchless Numba compaction kernel above a threshold number of elements. - The
numba_indexingthreshold (the array size above which Numba is used instead of NumPy for indexing) was lowered from 5000 to 2000, since Numba wins for both gather and compaction above ~2000 elements.
Other changes
starsim.librarynow exports its contents at the top level, so classes can be accessed either via their submodule (e.g.ssl.networks.HouseholdNet,ssl.diseases.Cholera) or directly (e.g.ssl.HouseholdNet,ssl.Cholera), like core Starsim.- Added
tests/benchmark_large.pyand associated benchmark data for tracking performance on larger simulations.
Regression information
- The default random number values for agent-indexed draws have changed (see "Common random numbers" above); results are statistically equivalent but not bit-for-bit identical, and baselines should be regenerated.
ss.RandomNetis now approximate; usess.RandomExactNetfor the previous exact-degree behavior.- The
single_rngoption has been removed; usess.options.crn = Falseinstead. - The default
slot_scaleforss.Pregnancywas increased from 5 to 100, which changes results for models with pregnancy. - GitHub info: PR 1378