Discrete event simulation¶
Queueing-network primitives.
Building blocks¶
Queue(maxlen, name)— FIFO buffer ofEntityinstances.PriorityQueue— min-heap by entity property.Resource/ResourcePool— countable concurrency limiters.Service(capacity, buffer_size, next_q, default_service_time, rng)— multi-channel server that pulls from its own buffer and forwards finished entities.ArrivalGenerator(interarrival, factory, target, rng)— Poisson-by- default source that builds entities and pushes them into a target.EntityProperties— typed attribute bag attached to each entity for routing decisions.
RNG distributions¶
exponential, uniform, normal, deterministic — convenience
factories that return zero-arg samplers bound to a numpy.random.Generator.
rng = np.random.default_rng(0)
service_time = sw.exponential(rate=1.0, rng=rng)
service_time() # callable per draw
Example: M/M/2¶
See the Quickstart for the full snippet. The recorded outputs render as:
Calendar time axis¶
Simulation clocks are dimensionless floats. :class:~simweave.core.time_axis.SimTimeAxis
maps any simulation time to a real-world calendar date so that plot axes
show months and years rather than raw tick numbers.
import simweave as sw
# 1 tick = 1 day, simulation starts 1 January 2027
tax = sw.SimTimeAxis(start="2027-01-01", tick_unit="days")
tax.label(90.0) # "2027-04-01"
tax.tick_for_date("2027-07-01") # 181.0 (schedule events by date)
# Pass to any time-series plot helper
fig = sw.plot_queue_length(recorder, time_axis=tax)
# Or apply after the fact
fig = sw.plot_warehouse_stock(recorder)
tax.apply_to_figure(fig)
Supported tick_unit values: "seconds", "minutes", "hours",
"days", "weeks", "months" (≈ 30.44 days), "years" (≈ 365.25 days).
Use tick_size to express coarser steps — e.g. tick_unit="hours",
tick_size=4 makes each simulation unit equal to 4 real hours.
SimTimeAxis
¶
SimTimeAxis(start: str | datetime, tick_unit: str = 'days', tick_size: float = 1.0, date_format: str | None = None)
Map simulation tick time to real-world calendar dates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str | datetime
|
Calendar date/time that corresponds to simulation |
required |
tick_unit
|
str
|
Duration of one simulation time unit. Must be one of
|
'days'
|
tick_size
|
float
|
Scale factor: how many |
1.0
|
date_format
|
str | None
|
:func: |
None
|
Examples:
to_datetime
¶
Convert a scalar simulation time to a :class:~datetime.datetime.
to_datetimes
¶
Convert an iterable of simulation times to :class:~datetime.datetime objects.
The returned list is suitable for Plotly's x parameter; Plotly
renders datetime objects natively with automatic axis formatting.
apply_to_figure
¶
Replace numeric tick values on axis with calendar dates.
Iterates through every trace in fig.data and, wherever the
nominated axis data is a numeric array, substitutes
:class:~datetime.datetime objects. Plotly then renders the axis
as a date axis with its own smart tick-label formatter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fig
|
Any
|
A |
required |
axis
|
str
|
|
'x'
|
title
|
str | None
|
Optional replacement axis title. If |
None
|
Returns:
| Type | Description |
|---|---|
The same figure object (modified in-place), so calls can be chained::
|
fig = plot_fleet_availability(rec) fig = time_axis.apply_to_figure(fig, title="Calendar date") fig.show() |
tick_for_date
¶
Return the simulation tick corresponding to a given calendar date.
Useful for scheduling events at specific real-world dates::
t_start = tax.tick_for_date("2027-03-01")
env.schedule_at(t_start, my_callback)
API¶
Discrete-event primitives: queues, services, resources, arrival generators.
EntityProperties
dataclass
¶
EntityProperties(entity_type: str = 'default', service_time: Distribution = (lambda: exponential(1.0))(), balk_on_length: int | None = None, renege_after: float | None = None, extras: dict[str, Any] = dict())
Per-entity sim properties. Pass the same instance to many entities.
Attributes:
| Name | Type | Description |
|---|---|---|
entity_type |
str
|
Free-form tag, useful for stratified summaries. |
service_time |
Distribution
|
Distribution drawn whenever a Service pulls this entity into a work channel. |
balk_on_length |
int | None
|
If the waiting queue has more than this many items on arrival, the
entity refuses to join. |
renege_after |
float | None
|
If the entity's |
extras |
dict[str, Any]
|
Arbitrary additional fields the modeller wants to track. |
Queue
¶
Bases: Entity
Bounded FIFO queue.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
maxlen
|
int
|
Maximum number of items held. Extra arrivals are dropped (and the drop counter is incremented). |
10
|
name
|
str | None
|
Human-readable name. |
None
|
next_q
|
'Queue | str'
|
Where forwarded items go -- another Queue/Service or the sentinel
string |
'terminus'
|
Source code in src/simweave/discrete/queues.py
enqueue
¶
enqueue(item: Entity) -> bool
Attempt to append an item. Returns True on success.
Honours item.sim_properties.balk_on_length if present.
Source code in src/simweave/discrete/queues.py
forward
¶
Dequeue head and enqueue into override_target (or self.next_q).
Returns True if forwarded, False if downstream is blocked (in
which case the head item is not removed).
Source code in src/simweave/discrete/queues.py
average_length
¶
Mean queue length over the elapsed simulation time (L in Little's law).
average_wait
¶
Mean residence time of completed items (W in Little's law).
PriorityQueue
¶
Bases: Queue
Min-heap priority queue. Lower priority values dequeue first.
Items are wrapped in (priority, seq, item) tuples internally so the
payload doesn't need to be comparable.
Source code in src/simweave/discrete/queues.py
Resource
¶
Bases: Entity
A reusable resource that can be checked out of a pool.
Source code in src/simweave/discrete/resources.py
release
¶
Return the resource to to or its home pool.
Source code in src/simweave/discrete/resources.py
ResourcePool
¶
Bases: Queue
Pool of interchangeable resources that a Service can check out.
Source code in src/simweave/discrete/resources.py
deposit
¶
deposit(resource: Resource) -> None
Return a resource to the pool. Raises if the pool is at capacity.
Source code in src/simweave/discrete/resources.py
try_acquire
¶
try_acquire() -> Resource | None
Non-blocking acquire. Returns a Resource or None if empty.
Source code in src/simweave/discrete/resources.py
Service
¶
Service(capacity: int = 1, buffer_size: int = 10, next_q: 'Queue | str' = 'terminus', resources: ResourcePool | None = None, default_service_time: float = 1.0, rng: Generator | None = None, name: str | None = None)
Bases: Queue
Multi-channel server with optional resource pool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
capacity
|
int
|
Number of parallel work channels (servers). |
1
|
buffer_size
|
int
|
Max queue length before service. Further arrivals are dropped. |
10
|
next_q
|
'Queue | str'
|
Where to forward completed items. |
'terminus'
|
resources
|
ResourcePool | None
|
Optional :class: |
None
|
default_service_time
|
float
|
Fallback when an arriving entity has no |
1.0
|
rng
|
Generator | None
|
Optional numpy Generator used when drawing service times. |
None
|
Source code in src/simweave/discrete/services.py
ArrivalGenerator
¶
ArrivalGenerator(interarrival: Callable[[Generator], float], factory: Callable[[SimEnvironment], Entity], target: Queue, rng: Generator | None = None, name: str | None = None)
Bases: Entity
Generates new entities according to an inter-arrival distribution.
On each tick it adds to an internal clock and, whenever the clock passes
the next scheduled arrival, invokes factory(env) to mint a new
entity and pushes it into target. Multiple arrivals within a single
tick are handled correctly.
Source code in src/simweave/discrete/services.py
exponential
¶
Exponential inter-arrival / service time.
Source code in src/simweave/discrete/properties.py
normal
¶
Normal distribution; by default clips at 0 since negative service times are nonsense.