Skip to content

hyperpolymath/Cliodynamics.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Cliodynamics.jl

Overview

Cliodynamics is the scientific study of historical dynamics — applying mathematical models and quantitative methods to understand long-term patterns in social complexity, state formation, demographic cycles, elite dynamics, and political instability. This package implements frameworks from Peter Turchin’s research program in cliodynamics.

What is Cliodynamics?

Cliodynamics treats history as a science, using mathematical models to analyze:

  • Population dynamics and demographic pressures

  • Elite overproduction and intra-elite competition

  • Political instability and state breakdown

  • Secular cycles (150-300 year oscillations in societies)

  • State capacity and collective action problems

The field bridges history, mathematics, evolutionary theory, and complex systems science.

Features

Population Dynamics

  • Malthusian Models: Logistic population growth with carrying capacity constraints

  • Demographic-Structural Theory (DST): Coupled models of population, elites, and state capacity

  • Population Pressure: Measurement of stress relative to carrying capacity

Elite Dynamics

  • Elite Overproduction Index: Quantify when elite supply exceeds available positions

  • Elite-to-Population Ratios: Track elite expansion relative to general population

  • Intra-Elite Competition: Model competition effects on political stability

Political Instability

  • Political Stress Indicator (PSI): Composite measure combining:

    • Mass Mobilization Potential (wage decline, immiseration)

    • Elite Mobilization Potential (elite overproduction)

    • State Fiscal Distress (revenue crisis)

  • Instability Probability: Convert stress indicators to event probabilities

  • Conflict Intensity: Aggregate historical instability events over time

Secular Cycles

  • Cycle Detection: Identify 150-300 year oscillations in historical data

  • Phase Classification: Categorize periods as Expansion, Stagflation, Crisis, or Depression

  • Trend-Cycle Decomposition: Separate long-term trends from cyclical components

State Formation

  • State Capacity Models: Tax revenue, military strength, institutional quality

  • Collective Action Problems: Model cooperation challenges in state building

  • Institutional Development: Track state-building trajectories

Spatial Models (v1.0.0)

  • Instability Diffusion: Multi-region model of instability spreading across borders

  • Territorial Competition: Lotka-Volterra style state competition over territory

  • Frontier Formation: Meta-ethnic frontier index (Turchin’s frontier thesis)

Model Fitting & Estimation

  • Malthusian Fitting: Recover growth rate and carrying capacity from observed population data

  • DST Fitting: Fit full demographic-structural model to historical time series

  • Parameter Estimation: Generic model fitting with bootstrap confidence intervals

  • Seshat Integration: Load and analyze data from the Seshat Global History Databank

Bayesian Inference (v1.0.0)

Requires using Turing (loaded as package extension):

  • Bayesian Malthusian: MCMC posterior estimation for growth parameters

  • Bayesian DST: Full Bayesian fit of demographic-structural model

  • Model Comparison: WAIC-based model selection

Plotting

Plot recipes for Plots.jl via package extension (loaded automatically when using Plots):

  • plot(psi_result, Val(:psi)) — PSI with component breakdown

  • plot(eoi_result, Val(:eoi)) — Elite overproduction with baseline

  • plot(analysis, Val(:secular_cycle)) — Trend-cycle decomposition

  • plot(phases, Val(:phases)) — Phase-colored timeline

  • plot(intensity, Val(:conflict)) — Conflict intensity

Installation

using Pkg
Pkg.add("Cliodynamics")

Quick Start

using Cliodynamics
using DataFrames

# 1. Model Malthusian population dynamics
params = MalthusianParams(r=0.02, K=1000.0, N0=100.0)
sol = malthusian_model(params, tspan=(0.0, 200.0))
println("Population at t=200: ", round(sol(200.0)[1], digits=1))

# 2. Calculate elite overproduction index
data = DataFrame(
    year = 1800:1900,
    population = collect(100_000:1000:200_000),
    elites = [1000 + 10*i + 5*i^1.5 for i in 0:100]
)
eoi = elite_overproduction_index(data)
println("Final EOI: ", round(eoi.eoi[end], digits=3))

# 3. Calculate Political Stress Indicator
stress_data = DataFrame(
    year = 1800:1900,
    real_wages = 100.0 .- collect(0:100).^1.2 ./ 10,
    elite_ratio = 0.01 .+ collect(0:100) ./ 5000,
    state_revenue = 1000.0 .- collect(0:100).^1.5 ./ 5
)
psi = political_stress_indicator(stress_data)
println("PSI at 1900: ", round(psi.psi[end], digits=3))

# 4. Detect secular cycles
timeseries = 100.0 .+ 50.0 .* sin.(2π .* (1:300) ./ 100) .+ 2 .* randn(300)
analysis = secular_cycle_analysis(Float64.(timeseries), window=30)
println("Estimated cycle period: $(analysis.period) years")

Demographic-Structural Theory Example

Model a complete secular cycle with coupled population, elite, and state dynamics:

using Cliodynamics

params = DemographicStructuralParams(
    r=0.015,      # Population growth rate (1.5% per year)
    K=1000.0,     # Carrying capacity
    w=2.0,        # Elite wage premium
    δ=0.03,       # Elite death/retirement rate
    ε=0.001,      # Elite production rate
    N0=500.0,     # Initial population (50% of capacity)
    E0=10.0,      # Initial elite population
    S0=100.0      # Initial state fiscal capacity
)

sol = demographic_structural_model(params, tspan=(0.0, 300.0))

# Extract state at key timepoints
for t in [0.0, 100.0, 200.0, 300.0]
    state = sol(t)
    println("t=$t: N=$(round(state[1],digits=1)), E=$(round(state[2],digits=1)), S=$(round(state[3],digits=1))")
end

Seshat Data Integration (v0.2.0)

Analyze historical data from the Seshat Global History Databank:

using Cliodynamics
using DataFrames

# Load Seshat-format CSV data
raw = load_seshat_csv("data/seshat_sample.csv")

# Prepare Roman Empire data
roman = prepare_seshat_data(raw, polity="RomPrinworlds")

# Compute elite overproduction across Roman periods
roman_all = prepare_seshat_data(raw)
roman_all = filter(row -> occursin("Rom", string(row.polity)), roman_all)
sort!(roman_all, :year)
eoi = elite_overproduction_index(roman_all)

# Fit Malthusian model to English population growth
english = filter(row -> occursin("Eng", string(row.polity)), prepare_seshat_data(raw))
sort!(english, :year)
fit = fit_malthusian(Float64.(english.year), Float64.(english.population),
                     r_init=0.005, K_init=2_000_000.0)
println("Fitted r=$(round(fit.params.r, digits=6)), K=$(round(fit.params.K, digits=0))")

Model Fitting & Parameter Estimation (v0.2.0)

using Cliodynamics

# Fit Malthusian model to observed data
years = collect(0.0:10.0:100.0)
population = [50.0 * exp(0.03 * t) / (1 + 50.0/500.0*(exp(0.03*t)-1)) for t in years]
result = fit_malthusian(years, population, r_init=0.01, K_init=600.0)

# Generic parameter estimation with bootstrap confidence intervals
model_fn(p, t) = p[1] .* exp.(p[2] .* (t .- t[1]))
est = estimate_parameters(model_fn, population, years, [50.0, 0.02], n_bootstrap=200)
println("r = $(round(est.params[2], digits=5))  95% CI: [$(round(est.ci_lower[2], digits=5)), $(round(est.ci_upper[2], digits=5))]")

Key Concepts

Malthusian Dynamics

Population grows until constrained by resources (carrying capacity K):

dN/dt = r*N*(1 - N/K)

Elite Overproduction

When elite aspirants exceed available positions, intra-elite competition intensifies, destabilizing the political system:

EOI = (E/N) / (E/N)_baseline - 1

Political Stress Indicator

Composite index combining three destabilizing forces:

PSI = 0.4*MMP + 0.4*EMP + 0.2*SFD

where:

  • MMP = Mass Mobilization Potential (popular immiseration)

  • EMP = Elite Mobilization Potential (elite overproduction)

  • SFD = State Fiscal Distress (revenue crisis)

Secular Cycles

Long-term oscillations (150-300 years) with four phases:

  1. Expansion: Low pressure, state strengthening, prosperity

  2. Stagflation: Rising pressure, elite overproduction begins

  3. Crisis: Political instability, state breakdown, conflict

  4. Depression/Intercycle: Population decline, elite winnowing, recovery

References

Primary Sources

  • Turchin, P. (2003). Historical Dynamics: Why States Rise and Fall. Princeton University Press.

  • Turchin, P. (2016). Ages of Discord: A Structural-Demographic Analysis of American History. Beresta Books.

  • Turchin, P., & Nefedov, S. A. (2009). Secular Cycles. Princeton University Press.

  • Turchin, P. (2023). End Times: Elites, Counter-Elites, and the Path of Political Disintegration. Penguin Press.

Theoretical Foundations

  • Goldstone, J. A. (1991). Revolution and Rebellion in the Early Modern World. University of California Press.

  • Korotayev, A., & Tsirel, S. (2010). "A Spectral Analysis of World GDP Dynamics." Structure and Dynamics, 4(1).

Applications

  • Turchin, P., et al. (2018). "Quantitative historical analysis uncovers a single dimension of complexity that structures global variation in human social organization." PNAS, 115(2), E144-E151.

Citation

If you use this package in research, please cite:

@software{cliodynamics_jl,
  author = {Jewell, Jonathan D.A.},
  title = {Cliodynamics.jl: Mathematical Modeling of Historical Dynamics},
  year = {2026},
  url = {https://github.com/hyperpolymath/Cliodynamics.jl}
}

And cite the foundational work:

@book{turchin2003historical,
  author = {Turchin, Peter},
  title = {Historical Dynamics: Why States Rise and Fall},
  year = {2003},
  publisher = {Princeton University Press}
}

Contributing

See CONTRIBUTING.md for guidelines.

License

Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>

This project is licensed under the Palimpsest License (PMPL-1.0-or-later). See LICENSE for details.

About

Julia package: Cliodynamics

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors