API Reference

Core Types

Core data types for the Ideological Dynamics Simulator.

Based on Cidral’s formal framework: replicator-mutator dynamics on the simplex, latent sympathy for dormancy/martyrdom, endogenous environment modification, hybridization as stochastic jump process. The full system is a PDMP.

class ideasim.types.Ideology(name, env_response, latent_conversion=0.1, latent_generation=0.3, latent_decay=0.05, martyrdom_coeff=0.5, institutional_amp=0.2, capture_threshold=0.25, governance_threshold=0.4, mutation_rate=0.01)[source]

Bases: object

A single ideological current in the ecosystem.

Parameters:
name

Human-readable name (e.g., “liberalism”, “Marxism”).

env_response

Weight vector w_i (length M) — how this ideology responds to environmental conditions. Positive = thrives in that condition.

latent_conversion

gamma_i — rate at which latent sympathy converts to manifest adoption.

latent_generation

alpha_i — rate at which active adherents generate latent sympathizers.

latent_decay

beta_i — natural decay rate of latent sympathy.

martyrdom_coeff

delta_i — how efficiently suppression creates sympathy.

institutional_amp

mu_i — amplification rate above capture threshold.

capture_threshold

theta_i — share above which institutional capture kicks in.

governance_threshold

theta_i^gov — share above which ideology can suppress others.

mutation_rate

nu_i — rate of parameter drift per year.

name: str
env_response: ndarray[tuple[Any, ...], dtype[float64]]
latent_conversion: float = 0.1
latent_generation: float = 0.3
latent_decay: float = 0.05
martyrdom_coeff: float = 0.5
institutional_amp: float = 0.2
capture_threshold: float = 0.25
governance_threshold: float = 0.4
mutation_rate: float = 0.01
class ideasim.types.StochasticParams(hybridization_rates, hybridization_thresholds, charisma_rate=0.02, charisma_decay=20.0, charisma_amplitude_mean=0.3, charisma_amplitude_std=0.5, mutation_step_size=0.01, hybridization_seed_share=0.02)[source]

Bases: object

Parameters for stochastic event overlays.

Parameters:
hybridization_rates

p_{ij} — rate of hybridization between i and j. Shape (N, N), symmetric. Zero on diagonal.

hybridization_thresholds

H_{ij} — latent sympathy overlap threshold. Shape (N, N), symmetric.

charisma_rate

lambda_char — global rate of charismatic events per year.

charisma_decay

tau_char — decay time of charismatic effect (years).

charisma_amplitude_mean

Mean of log-normal charisma amplitude.

charisma_amplitude_std

Std of log-normal charisma amplitude.

mutation_step_size

sigma_mut — std of Gaussian mutation perturbation.

hybridization_seed_share

epsilon_h — initial share of new hybrid.

hybridization_rates: ndarray[tuple[Any, ...], dtype[float64]]
hybridization_thresholds: ndarray[tuple[Any, ...], dtype[float64]]
charisma_rate: float = 0.02
charisma_decay: float = 20.0
charisma_amplitude_mean: float = 0.3
charisma_amplitude_std: float = 0.5
mutation_step_size: float = 0.01
hybridization_seed_share: float = 0.02
class ideasim.types.EnvironmentSchedule(variable_names, initial, exogenous_shocks=<factory>, autonomous_decay=None, policy_influence=None)[source]

Bases: object

Exogenous environment trajectory and endogenous feedback.

Parameters:
variable_names

Names of the M environmental variables.

initial

e(0), shape (M,).

exogenous_shocks

List of (time, variable_index, delta) — discrete shocks.

autonomous_decay

g_k decay rate toward baseline for each variable.

policy_influence

P matrix (N x M) — how ideologies change the environment.

variable_names: list[str]
initial: ndarray[tuple[Any, ...], dtype[float64]]
exogenous_shocks: list[tuple[float, int, float]]
autonomous_decay: ndarray[tuple[Any, ...], dtype[float64]] | None = None
policy_influence: ndarray[tuple[Any, ...], dtype[float64]] | None = None
class ideasim.types.SimulationConfig(ideologies, interaction_matrix, suppression_matrix, environment, stochastic, initial_shares, initial_latent, rho=0.005, t_start=1800.0, t_end=2025.0, dt=0.05, record_interval=20, seed=42)[source]

Bases: object

Complete configuration for an ideological dynamics simulation.

Parameters:
ideologies

List of ideological types.

interaction_matrix

B — NxN competitive interaction matrix.

suppression_matrix

s_{ij} — NxN, propensity of j to suppress i when in power.

environment

Environment configuration.

stochastic

Stochastic event parameters.

initial_shares

x(0) on the simplex, shape (N,).

initial_latent

y(0), shape (N,).

rho

Replicator-mutator immigration rate (latent -> manifest).

t_start

Start year.

t_end

End year.

dt

Integration time step (years).

record_interval

How often to record state (in time steps).

seed

Random seed for reproducibility.

ideologies: list[Ideology]
interaction_matrix: ndarray[tuple[Any, ...], dtype[float64]]
suppression_matrix: ndarray[tuple[Any, ...], dtype[float64]]
environment: EnvironmentSchedule
stochastic: StochasticParams
initial_shares: ndarray[tuple[Any, ...], dtype[float64]]
initial_latent: ndarray[tuple[Any, ...], dtype[float64]]
rho: float = 0.005
t_start: float = 1800.0
t_end: float = 2025.0
dt: float = 0.05
record_interval: int = 20
seed: int | None = 42
property n_ideologies: int
property n_env_vars: int
ideology_names()[source]
Return type:

list[str]

class ideasim.types.StateSnapshot(time, shares, latent, environment, ideology_names, fitness=None)[source]

Bases: object

Immutable snapshot of the system at a single point in time.

Parameters:
time: float
shares: ndarray[tuple[Any, ...], dtype[float64]]
latent: ndarray[tuple[Any, ...], dtype[float64]]
environment: ndarray[tuple[Any, ...], dtype[float64]]
ideology_names: list[str]
fitness: ndarray[tuple[Any, ...], dtype[float64]] | None = None
class ideasim.types.SimulationEvent(time, event_type, details=<factory>)[source]

Bases: object

Record of a discrete stochastic event.

Parameters:
time: float
event_type: str
details: dict[str, Any]
class ideasim.types.SimulationResult(config_summary, history, events, ideology_names, metadata=<factory>)[source]

Bases: object

Complete result of a simulation run.

Parameters:
config_summary: dict[str, Any]
history: list[StateSnapshot]
events: list[SimulationEvent]
ideology_names: list[str]
metadata: dict[str, Any]
property n_steps: int
times()[source]
Return type:

ndarray[tuple[Any, ...], dtype[double]]

share_timeseries(name)[source]
Return type:

ndarray[tuple[Any, ...], dtype[double]]

Parameters:

name (str)

latent_timeseries(name)[source]
Return type:

ndarray[tuple[Any, ...], dtype[double]]

Parameters:

name (str)

env_timeseries(var_index)[source]
Return type:

ndarray[tuple[Any, ...], dtype[double]]

Parameters:

var_index (int)

entropy_timeseries()[source]

Shannon entropy of ideological distribution over time.

Return type:

ndarray[tuple[Any, ...], dtype[double]]

Simulation Engine

PDMP simulation engine for ideological dynamics.

Implements Cidral’s framework: continuous replicator-mutator ODE dynamics punctuated by discrete stochastic events (hybridization, mutation, charisma). Integration via RK4; events via Poisson process overlay.

ideasim.engine.simulate(config)[source]

Run the full PDMP simulation.

Returns a SimulationResult with time series and event log.

Return type:

SimulationResult

Parameters:

config (SimulationConfig)

Configuration Defaults

Default scenario: 4 ideologies in Europe, 1800-2025.

Parameters from Cidral’s formalization (Section 7.3-7.6), validated against Jose’s mechanisms and Mark’s historical cases.

The default scenario is stored as a JSON file in data/default_scenario.json. This module loads that file and exposes the same API as before.

ideasim.defaults.make_default_ideologies()[source]

Create the default 4-ideology system.

Return type:

list[Ideology]

ideasim.defaults.make_default_config()[source]

Create the default European 1800-2025 simulation config.

Return type:

SimulationConfig

I/O

JSON serialization/deserialization for simulation configs and results.

ideasim.io.result_to_dict(result)[source]

Convert SimulationResult to a JSON-serializable dict.

Return type:

dict[str, Any]

Parameters:

result (SimulationResult)

ideasim.io.save_result(result, path)[source]

Save simulation result to JSON file.

Return type:

None

Parameters:
ideasim.io.load_config(path)[source]

Load simulation config from JSON file.

Return type:

SimulationConfig

Parameters:

path (str | Path)

ideasim.io.save_config(config, path)[source]

Save simulation config to JSON file.

Return type:

None

Parameters:

CLI

CLI entry point for the Ideological Dynamics Simulator.

ideasim.cli.main(argv=None)[source]
Return type:

None

Parameters:

argv (list[str] | None)

Sensitivity Analysis

Sensitivity analysis for ideological dynamics simulations.

Two complementary approaches:

  1. One-At-a-Time (OAT): vary each parameter individually across its range while holding all others at baseline. Reveals per-parameter response curves.

  2. Latin Hypercube Sampling (LHS): sample N points from the full parameter space using quasi-random LHS. Captures interaction effects and provides global summary statistics.

Both methods collect final ideology shares and health-check metrics for each simulation run, packaging results into typed dataclasses that serialize cleanly to JSON.

This module is pure computation – no I/O, no CLI, no side effects.

class ideasim.sensitivity.RunSummary(parameter_values, final_shares, health, final_entropy, n_events)[source]

Bases: object

Condensed output of a single simulation run.

Parameters:
parameter_values

Mapping of parameter name to the value used.

final_shares

Mapping of ideology name to final share.

health

HealthReport for the run.

final_entropy

Shannon entropy of the final share distribution.

n_events

Total number of stochastic events that occurred.

parameter_values: dict[str, float]
final_shares: dict[str, float]
health: HealthReport
final_entropy: float
n_events: int
to_dict()[source]
Return type:

dict[str, object]

class ideasim.sensitivity.OATParameterResult(parameter_name, values, runs)[source]

Bases: object

OAT sweep result for a single parameter.

Parameters:
parameter_name

The parameter that was varied.

values

The parameter values tested.

runs

One RunSummary per value.

parameter_name: str
values: list[float]
runs: list[RunSummary]
to_dict()[source]
Return type:

dict[str, object]

class ideasim.sensitivity.LHSSummaryStats(metric_name, mean, std, min, max)[source]

Bases: object

Aggregate statistics across all LHS samples for one output metric.

Parameters:
metric_name

e.g. “liberalism_final_share” or “final_entropy”.

mean

Mean across all samples.

std

Standard deviation.

min

Minimum.

max

Maximum.

metric_name: str
mean: float
std: float
min: float
max: float
to_dict()[source]
Return type:

dict[str, object]

class ideasim.sensitivity.SensitivityResult(oat=<factory>, lhs_runs=<factory>, lhs_stats=<factory>, n_parameters=0, metadata=<factory>)[source]

Bases: object

Complete sensitivity analysis result.

Parameters:
oat

OAT results, one per parameter. Empty if OAT was not run.

lhs_runs

Individual LHS run summaries. Empty if LHS was not run.

lhs_stats

Summary statistics across LHS runs. Empty if LHS was not run.

n_parameters

Number of parameters analyzed.

metadata

Additional info (e.g. n_oat_steps, n_lhs_samples).

oat: list[OATParameterResult]
lhs_runs: list[RunSummary]
lhs_stats: list[LHSSummaryStats]
n_parameters: int = 0
metadata: dict[str, object]
to_dict()[source]
Return type:

dict[str, object]

ideasim.sensitivity.run_oat(config, n_steps=10, deterministic=True)[source]

One-At-a-Time sensitivity analysis.

For each fittable parameter, holds all others at baseline and varies that parameter across n_steps evenly spaced values between its lower and upper bounds.

Parameters:
  • config (SimulationConfig) – Baseline SimulationConfig.

  • n_steps (int) – Number of values to test per parameter (including endpoints).

  • deterministic (bool) – If True, disable stochastic events for reproducibility.

Return type:

list[OATParameterResult]

Returns:

List of OATParameterResult, one per parameter.

ideasim.sensitivity.run_lhs(config, n_samples=50, seed=42, deterministic=True)[source]

Latin Hypercube Sampling sensitivity analysis.

Draws n_samples parameter combinations that cover the full parameter space quasi-randomly, runs the simulation for each, and computes summary statistics across all runs.

Parameters:
  • config (SimulationConfig) – Baseline SimulationConfig (provides structure and bounds).

  • n_samples (int) – Number of LHS samples to draw.

  • seed (int | None) – Random seed for LHS sampling reproducibility.

  • deterministic (bool) – If True, disable stochastic events for reproducibility.

Return type:

tuple[list[RunSummary], list[LHSSummaryStats]]

Returns:

Tuple of (list of RunSummary, list of LHSSummaryStats).

ideasim.sensitivity.run_sensitivity(config, oat_steps=10, lhs_samples=50, seed=42, deterministic=True, run_oat_analysis=True, run_lhs_analysis=True)[source]

Run full sensitivity analysis combining OAT and LHS.

This is the main entry point. Runs both analyses (or either one independently) and packages everything into a single result object.

Parameters:
  • config (SimulationConfig) – Baseline SimulationConfig.

  • oat_steps (int) – Number of values per parameter in OAT sweep.

  • lhs_samples (int) – Number of LHS samples.

  • seed (int | None) – Random seed for LHS.

  • deterministic (bool) – Disable stochastic events for reproducibility.

  • run_oat_analysis (bool) – Whether to run OAT analysis.

  • run_lhs_analysis (bool) – Whether to run LHS analysis.

Return type:

SensitivityResult

Returns:

SensitivityResult with all collected data.

Validation

Input validation for simulation configs and datasets.

Validates structural consistency, numerical sanity, and constraint satisfaction before a simulation runs. This prevents cryptic numpy errors deep in the engine by catching problems early with clear error messages.

class ideasim.validation.ValidationError(field, message, severity='error')[source]

Bases: object

A single validation issue.

Parameters:
field: str
message: str
severity: str = 'error'
class ideasim.validation.ValidationResult(errors=<factory>, warnings=<factory>)[source]

Bases: object

Result of validating a SimulationConfig.

Parameters:
errors: list[ValidationError]
warnings: list[ValidationError]
property is_valid: bool

True if no errors (warnings are acceptable).

add_error(field_name, message)[source]
Return type:

None

Parameters:
  • field_name (str)

  • message (str)

add_warning(field_name, message)[source]
Return type:

None

Parameters:
  • field_name (str)

  • message (str)

summary()[source]

Human-readable summary of validation results.

Return type:

str

ideasim.validation.validate_config(config)[source]

Validate a SimulationConfig for structural and numerical correctness.

Checks: - At least 1 ideology. - All array dimensions are consistent (N ideologies, M env vars). - Initial shares sum to 1 and are non-negative. - Initial latent values are non-negative. - Time range is valid (t_start < t_end). - dt is positive and not larger than total duration. - Matrices are the right shape (interaction, suppression, etc.). - Stochastic parameter matrices are the right shape. - Parameter values are in reasonable ranges (warnings for extreme values).

Parameters:

config (SimulationConfig) – The SimulationConfig to validate.

Return type:

ValidationResult

Returns:

ValidationResult with any errors and warnings found.

Health Checks

Health checks for simulation results.

Post-hoc sanity checks on simulation output to detect numerical issues, degenerate dynamics, or parameter tuning problems. These are the “basic reporting metrics” that help assess whether a simulation run is producing sensible results.

Designed to be run automatically after every simulation (e.g., in CI/CD or as part of a test harness) to flag problems early.

class ideasim.health.HealthCheck(name, passed, message, severity='error')[source]

Bases: object

A single health check result.

Parameters:
name: str
passed: bool
message: str
severity: str = 'error'
class ideasim.health.HealthReport(checks=<factory>)[source]

Bases: object

Aggregated health report for a simulation run.

Parameters:

checks (list[HealthCheck])

checks: list[HealthCheck]
property all_passed: bool

True if all checks passed.

property n_errors: int
property n_warnings: int
summary()[source]

Human-readable summary.

Return type:

str

to_dict()[source]

JSON-serializable representation.

Return type:

dict[str, object]

ideasim.health.check_health(result)[source]

Run all health checks on a simulation result.

Checks performed: 1. Simplex invariant: shares sum to ~1.0 at every recorded step. 2. Non-negativity: shares and latent values never go negative. 3. No NaN/Inf: no numerical blowup in shares, latent, or environment. 4. No total collapse: at least 2 ideologies above 1% at the end. 5. No pathological dominance: no ideology at exactly 1.0 (within tolerance). 6. Reasonable entropy range: final entropy is not zero (unless only 1 ideology). 7. Sufficient history: at least 10 recorded snapshots. 8. Event plausibility: stochastic events have valid types and timing.

Parameters:

result (SimulationResult) – The SimulationResult to check.

Return type:

HealthReport

Returns:

HealthReport with all check results.