Events & Timeline
Dynamic event management subsystem: scandals, economic shocks, election timelines, and synthetic poll generation.
Event
Dataclass representing a dynamic event in the simulation.
from electoral_sim.events.event_manager import Event
event = Event(
id=0,
type="scandal",
start_step=5,
duration=8,
severity=25.0,
target_party_id=2,
description="Scandal hitting Party 2",
)
Fields:
| Field | Type | Description |
|-------|------|-------------|
| id | int | Unique event identifier |
| type | Literal["scandal", "economic_shock", "international_crisis"] | Event category |
| start_step | int | Simulation step when the event begins |
| duration | int | Number of steps the event lasts |
| severity | float | Impact magnitude (0-50+ for scandals, ±5.0 for shocks) |
| target_party_id | int | None | Party targeted (or None for economy-wide) |
| description | str | Human-readable event description |
Property:
- end_step → int: Computed as start_step + duration.
EventManager
Manages generation, tracking, and expiration of dynamic events during a simulation.
from electoral_sim.events.event_manager import EventManager
manager = EventManager(
rng=np.random.default_rng(42),
prob_scandal=0.01,
prob_shock=0.005,
)
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| rng | np.random.Generator | required | Random number generator |
| prob_scandal | float | 0.01 | Per-step probability of a scandal |
| prob_shock | float | 0.005 | Per-step probability of an economic shock |
Attributes:
- active_events — List of currently active Event objects
- history — List of all past events
step
Advance one step: expire old events, possibly generate new scandals/shocks.
Returns: List of newly generated events this step.
Example:
# Run a campaign timeline with events
for step in range(30):
new = manager.step(n_parties=5)
for e in new:
print(f"Step {step}: {e.description}")
get_valence_modifiers
Get total valence penalty/bonus for each party from active scandal events. Penalty decays linearly over the event's duration.
Returns: Dict mapping party ID → net valence modifier.
get_economic_modifier
Get total modification to economic growth from active economic shocks. Shocks decay linearly over duration.
Returns: Net economic shock value (positive for booms, negative for crashes).
ElectionTimeline
Discrete-event campaign/election timeline for scheduling campaign phases, polls, debates, and election day.
from electoral_sim.events.timeline import ElectionTimeline
timeline = ElectionTimeline(
total_steps=30,
campaign_start=5,
debate_steps=[10, 20],
poll_steps=[8, 15, 25],
election_day=30,
)
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| total_steps | int | 30 | Total time steps in the election cycle |
| campaign_start | int | 5 | Step when campaigning begins |
| debate_steps | list[int] | None | [10, 20] | Steps at which debates occur |
| poll_steps | list[int] | None | [8, 15, 25] | Steps at which polls are taken |
| election_day | int | None | total_steps | Step of the election |
step
Advance one time step and return any events triggered.
Returns: Dict with step (current step) and events (list of triggered event dicts).
is_election_day
Return True if the current step is election day.
simulate_poll
Generate a synthetic poll with sampling error via Dirichlet distribution + Gaussian noise.
Returns: (n_parties,) poll results as normalized vote shares.
PollGenerator
Synthetic poll generation with house effects, sampling error, likely-voter screens, nonresponse, and correlated misses.
from electoral_sim.events.timeline import PollGenerator
polls = PollGenerator(
sample_size=1000,
house_effect=0.0,
moe=0.03,
)
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| sample_size | int | 1000 | Poll sample size |
| house_effect | float | 0.0 | Pollster's systematic bias (-0.05 to +0.05) |
| moe | float | 0.03 | Margin of error (default 3pp) |
generate_poll
Generate a poll from true vote shares with realistic error modeling.
Returns: Dict with poll_shares, sample_size, moe, house_effect.
Example: