pyLEAFS.fields module
Fields living on the shared grid.
A field is anything spatially distributed that the simulation steps in time and that agents can sample: the resource field here, and later a pheromone field, chemical gradients, and so on. The simulation holds a list of fields and steps each one, so new field types are add-ons rather than rewrites.
Field is the structural protocol every field follows. ResourceField
is the v1 implementation: a replenishing Poisson point process, ported from the
MATLAB Region/Environment classes but stored as one flat struct-of-arrays
buffer instead of per-region objects.
- class pyLEAFS.fields.Field(*args, **kwargs)[source]
Bases:
ProtocolStructural protocol for a steppable, samplable field.
A field references a
Gridand implements the three verbs the simulation and agents use.depositis optional in spirit (the resource field does not accept deposits), but the signature is reserved so that pheromone-style fields slot in without changing call sites.
- class pyLEAFS.fields.ResourceField(grid, Gamma, gamma, epsilon, dt, capacity_factor=4.0)[source]
Bases:
objectA replenishing Poisson resource field on the shared grid.
Resources are points scattered through the domain. Each timestep, within every region, new resources are born and existing ones die:
\[\begin{split}k_\mathrm{grow} &\sim \mathrm{Poisson}(\Gamma L^D\,dt / \epsilon) \\ k_\mathrm{decay} &\sim \mathrm{Binomial}(N,\, 1 - e^{-\gamma\,dt})\end{split}\]giving an agent-free equilibrium of \(N_\mathrm{eq} = \Gamma L^D / (\epsilon\gamma)\) resources per region. Positions are stored in one flat
(capacity, D)buffer; each region owns a contiguous slot range and an active count, so births append, deaths swap-delete, and harvest is O(1) — the struct-of-arrays equivalent of the MATLAB active-prefixRegion.- Parameters:
grid (Grid) – Shared spatial grid.
Gamma (float) – Resource birth rate per unit volume, \(\Gamma\).
gamma (float) – Resource decay rate, \(\gamma\).
epsilon (float) – Energy yield per resource, \(\epsilon\).
dt (float) – Timestep.
capacity_factor (float, optional) – Per-region buffer is
max(20, ceil(capacity_factor * N_eq))slots (default 4.0, matching the MATLABRegion).
- N_eq
Agent-free equilibrium count per region.
- Type:
float
- positions
Physical positions of all active resources (rebuilt on demand by
all_positions()).
Examples
>>> g = Grid((5, 5), L=10.0) >>> rf = ResourceField(g, Gamma=0.001, gamma=0.1, epsilon=0.1, dt=0.025) >>> round(rf.N_eq) 10
- harvest(region_id, slot)[source]
Remove one resource by
(region_id, slot). O(1) swap-delete.- Returns:
True if a resource was removed; False if the slot was already empty (e.g. another agent harvested it first this step).
- Return type:
bool
- neighbourhood(pos)[source]
Resources in the Moore neighbourhood of a single query position.
- Parameters:
- Returns:
- sample(pos)[source]
Nearest-resource displacement for each query position.
- Parameters:
- Returns:
disp (ndarray, shape (n, D)) – Displacement to the nearest resource (NaN row if none in range).
dist2 (ndarray, shape (n,)) – Squared distance to that resource (inf if none).
Notes
Searches the Moore neighbourhood of each query position. This is the sensing primitive the greedy population uses; it is a per-agent loop for now and is a natural
@njittarget once the core is validated.
- seed(rng, n0=None)[source]
Populate every region near equilibrium.
- Parameters:
rng (numpy.random.Generator) – Random source.
n0 (int, optional) – Exact initial count per region. If omitted, each region draws
Poisson(N_eq).