egttools

Toolbox for Evolutionary Game Theory.

https://github.com/socrats/egttools

Science Score: 67.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
    Found 3 DOI reference(s) in README
  • Academic publication links
    Links to: zenodo.org
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (12.7%) to scientific vocabulary

Keywords

cpp evolutionary-dynamics evolutionary-game-theory python simulation social-dynamics

Keywords from Contributors

pdes optim networks simulations nested gtk qt tk wx mesh
Last synced: 6 months ago · JSON representation ·

Repository

Toolbox for Evolutionary Game Theory.

Basic Info
  • Host: GitHub
  • Owner: Socrats
  • License: gpl-3.0
  • Language: C++
  • Default Branch: master
  • Homepage:
  • Size: 45.8 MB
Statistics
  • Stars: 99
  • Watchers: 2
  • Forks: 24
  • Open Issues: 7
  • Releases: 24
Topics
cpp evolutionary-dynamics evolutionary-game-theory python simulation social-dynamics
Created almost 6 years ago · Last pushed 6 months ago
Metadata Files
Readme Changelog Contributing License Code of conduct Citation

README.md

EGTtools

EGTTools – Evolutionary Game Theory Toolbox

PyPI Docs Live Docs Build Status Gitter Binder DOI

EGTTools is a modular toolbox for simulating and analyzing evolutionary dynamics in strategic environments. It combines analytical methods (replicator dynamics, fixation probabilities) and numerical simulations (Monte Carlo with parallel C++ backends) under a unified interface.


📑 Table of Contents

Testing & Continuous Integration

🚀 Features

  • ✅ Replicator dynamics for 2-strategy and N-player games
  • ✅ Stochastic dynamics using the pairwise comparison rule
  • ✅ Numerical simulation of evolutionary processes in finite populations
  • ✅ Monte Carlo estimation of fixation probabilities and strategy distributions
  • ✅ OpenMP parallelization for large-scale simulations (Linux/macOS)
  • ✅ Modular game and strategy framework, extensible in both Python and C++
  • ✅ Visual tools for plotting gradients, stationary distributions, and simplex diagrams
  • ✅ Support for Boost, Eigen, and BLAS integration (configurable)
  • ✅ Cross-platform wheels (Linux, macOS, Windows; x86_64 and ARM64)

📦 Installation

EGTTools is distributed via PyPI and includes prebuilt wheels for major platforms:

| Platform | Architectures | Python Versions | OpenMP Supported | |-----------------|-----------------------|-----------------|------------------| | Linux (x8664) | x8664 | 3.10 – 3.12 | ✅ Yes | | macOS (x86/arm) | x8664, arm64 (M1/M2) | 3.10 – 3.12 | ✅ Yes | | Windows | x8664, arm64 | 3.10 – 3.12 | ❌ Not available |

▶️ Install with pip

bash pip install egttools

For a more reliable installation on macOS with conda-based environments:

conda install numpy scipy matplotlib networkx seaborn pip install egttools --no-deps


🖥️ Platform Notes

🐧 Linux

  • OpenMP is fully supported and enabled by default.
  • Wheels are built with optimized BLAS/LAPACK and Boost.
  • Recommended for high-performance simulation runs.

🍎 macOS (Intel or Apple Silicon)

  • Supported on both x86_64 and arm64.
  • OpenMP is enabled by default and linked via libomp.
  • If using conda, prefer miniforge or mambaforge for ABI compatibility.
  • To skip dependency resolution and control packages manually:

bash pip install egttools --no-deps conda install numpy scipy matplotlib networkx seaborn `

🪟 Windows (x86_64 and ARM64)

  • Windows wheels are available for both Intel and ARM architectures.
  • OpenMP is currently not available on Windows.
  • Simulations will fall back to single-threaded mode.
  • BLAS/LAPACK can be enabled via conda or system libraries if building from source.

⚙️ Advanced Configuration (BLAS, OpenMP, vcpkg)

The C++ backend of EGTTools supports several build-time options that can be toggled when building from source:

| Feature | CMake Option | Default | Description | |---------------|----------------------------|------------------|-------------------------------------------------| | OpenMP | -DEGTTOOLS_USE_OPENMP=ON | ON (Linux/macOS) | Enables parallel computation for simulations | | BLAS/LAPACK | -DEGTTOOLS_USE_BLAS=ON | OFF | Enables matrix acceleration (e.g., OpenBLAS) | | Use vcpkg | -DEGTTOOLS_USE_VCPKG=ON | ON | Automatically fetches Boost and Eigen | | Disable vcpkg | -DEGTTOOLS_USE_VCPKG=OFF | | Allows using system-provided libraries manually |

🧰 When to disable vcpkg

You may want to disable vcpkg in CI environments or when using a distribution that provides all necessary dependencies system-wide. To do this:

bash cmake -DEGTTOOLS_USE_VCPKG=OFF .

In this case, you are responsible for ensuring that compatible versions of Boost and Eigen are available in your system paths.


🔧 Build from Source (with vcpkg)

To build EGTTools from source with all dependencies managed via vcpkg, run:

bash git clone --recurse-submodules https://github.com/Socrats/EGTTools.git cd EGTTools pip install .

To configure optional features manually, such as OpenMP or BLAS support:

bash cmake -DEGTTOOLS_USE_OPENMP=ON -DEGTTOOLS_USE_BLAS=ON -DEGTTOOLS_USE_VCPKG=OFF . make

If using conda, make sure to activate your environment first and ensure that Python, NumPy, and compiler toolchains are compatible.


🧪 Usage Examples

Calculate Gradient of Selection

```python from egttools.analytical import PairwiseComparison from egttools.games import Matrix2PlayerGameHolder

A = [[-0.5, 2], [0, 0]] game = Matrix2PlayerGameHolder(2, A) evolver = PairwiseComparison(100, game)

gradient = evolver.calculategradientof_selection(beta=1.0, state=[10, 90]) ```


Estimate fixation probability numerically

```python from egttools.numerical import PairwiseComparisonNumerical from egttools.games import Matrix2PlayerGameHolder

A = [[-0.5, 2], [0, 0]] game = Matrix2PlayerGameHolder(2, A) numericalevolver = PairwiseComparisonNumerical(game, populationsize=100, cache=1000000) fp = numericalevolver.estimatefixationprobability( indexinvadingstrategy=1, indexresidentstrategy=0, nbruns=500, nb_generations=5000, beta=1.0 ) ```

More Examples of usage

The Analytical example is a jupyter notebook which analyses analytically the evolutionary dynamics in a (2-person, 2-actions, one-shot) Hawk-Dove game.

The Numerical example is a jupyter notebook which analyses through numerical simulations the evolutionary dynamics in a (2-person, 2-actions, one-shot) Hawk-Dove game.

The Invasion example is a jupyter notebook calculates the fixation probabilities and stationary distribution of a Normal Form Game with 5 strategies and then plots an invasion diagram.

The Plot 2 Simplex is a jupyter notebook that shows how to use EGTtools to plot the evolutionary dynamics in a 2 Simplex (a triangle), both for infinite and finite populations.

You can also check all these notebooks and a bit more on this tutorial repository

For example, assuming the following payoff matrix:

A=\begin{pmatrix} -0.5 & 2 \\ 0 & 0 \end{pmatrix}

You can plot the gradient of selection in a finite population of (Z=100) individuals and assuming and intensity of selection \beta=1 in the following way:

```python import numpy as np from egttools.analytical import PairwiseComparison from egttools.games import Matrix2PlayerGameHolder

beta = 1; Z = 100; nbstrategies = 2; A = np.array([[-0.5, 2.], [0., 0.]]) popstates = np.arange(0, Z + 1, 1)

game = Matrix2PlayerGameHolder(nbstrategies, payoffmatrix=A)

Instantiate evolver and calculate gradient

evolver = PairwiseComparison(populationsize=Z, game=game) gradients = np.array([evolver.calculategradientofselection(beta, np.array([x, Z - x])) for x in range(Z + 1)]) ```

Afterward, you can plot the results with:

```python from egttools.plotting import plot_gradients

plotgradients(gradients, figsize=(4, 4), figtitle="Hawk-Dove game stochastic dynamics", markerfacecolor='white', xlabel="frequency of hawks (k/Z)", marker="o", markersize=20, markerplotfreq=2) ```

Gradient of selection

And you can plot the stationary distribution for a mutation rate \mu=1eˆ{-3} with:

```python import matplotlib.pyplot as plt from egttools.utils import calculatestationarydistribution

transitions = evolver.calculatetransitionmatrix(beta, mu=1e-3) stationarywithmu = calculatestationarydistribution(transitions.transpose()) fig, ax = plt.subplots(figsize=(5, 4)) fig.patch.setfacecolor('white') lines = ax.plot(np.arange(0, Z + 1) / Z, stationarywithmu) plt.setp(lines, linewidth=2.0) ax.setylabel('stationary distribution', size=16) ax.setxlabel('$k/Z$', size=16) ax.setxlim(0, 1) plt.show() ```

Stationary distribution

We can get the same results through numerical simulations. The error will depend on how many independent simulations you perform and for how long you let the simulation run. While a future implementation will offer an adaptive method to vary these parameters depending on the variations between the estimated distributions, for the moment it is important that you let the simulation run for enough generations after it has achieved a steady state. Here is a comparison between analytical and numerical results:

```python from egttools.numerical import PairwiseComparisonNumerical from egttools.games import NormalFormGame

Instantiate the game

game = NormalFormGame(1, A) numerical_evolver = PairwiseComparisonNumerical(Z, game, 1000000)

We do this for different betas

betas = np.logspace(-4, 1, 50) stationary_points = []

numerical simulations

for i in range(len(betas)): stationarypoints.append(numericalevolver.stationarydistribution(30, int(1e6), int(1e3), betas[i], 1e-3)) stationarypoints = np.asarray(stationary_points)

Now we estimate the probability of Cooperation for each possible state

statefrequencies = np.arange(0, Z + 1) / Z cooplevel = np.dot(statefrequencies, stationarypoints.T) ```

Lastly, we plot the results:

```python from sklearn.metrics import meansquarederror

mse = meansquarederror(1 - cooplevelanalytical, coop_level)

Finally, we plot and compare visually (and check how much error we get)

fig, ax = plt.subplots(figsize=(7, 5))

ax.scatter(betas, coop_level, label="simulation")

ax.scatter(betas, cooplevelanalytical, marker='x', label="analytical") ax.scatter(betas, cooplevel, marker='o', label="simulation") ax.text(0.01, 0.535, 'MSE = {0:.3e}'.format(mse), style='italic', bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10}) ax.legend() ax.setxlabel(r'$\beta$', fontsize=15) ax.setylabel('Cooperation level', fontsize=15) ax.setxscale('log') plt.show() ```

Comparison numerical analytical

Finally, you may also visualize the result of independent simulations:

```python initstates = np.random.randint(0, Z + 1, size=10, dtype=np.uint64) output = [] for i in range(10): output.append(evolver.run(int(1e6), 1, 1e-3, [initstates[i], Z - init_states[i]]))

Plot each year's time series in its own facet

fig, ax = plt.subplots(figsize=(5, 4))

for run in output: ax.plot(run[:, 0] / Z, color='gray', linewidth=.1, alpha=0.6) ax.setylabel('k/Z') ax.setxlabel('generation') ax.set_xscale('log') ```

Comparison numerical analytical

Plotting the dynamics in a 2 Simplex

EGTtools can also be used to visualize the evolutionary dynamics in a 2 Simplex. In the example bellow, we use the egttools.plotting.plot_replicator_dynamics_in_simplex which calculates the gradients on a simplex given an initial payoff matrix and returns a egttools.plotting.Simplex2D object which can be used to plot the 2 Simplex.

```python import numpy as np import matplotlib.pyplot as plt from egttools.plotting import plotreplicatordynamicsinsimplex

payoffs = np.array([[1, 0, 0], [0, 2, 0], [0, 0, 3]]) type_labels = ['A', 'B', 'C']

fig, ax = plt.subplots(figsize=(10, 8))

simplex, gradientfunction, roots, rootsxy, stability = plotreplicatordynamicsinsimplex(payoffs, ax=ax)

plot = (simplex.addaxis(ax=ax) .drawtriangle() .drawgradients(zorder=0) .addcolorbar() .addvertexlabels(typelabels) .drawstationarypoints(rootsxy, stability) .drawtrajectoryfromroots(gradientfunction, roots, stability, trajectorylength=15, linewidth=1, step=0.01, color='k', drawarrow=True, arrowdirection='right', arrowsize=30, zorder=4, arrowstyle='fancy') .drawscattershadow(gradient_function, 300, color='gray', marker='.', s=0.1, zorder=0) )

ax.axis('off') ax.set_aspect('equal')

plt.xlim((-.05, 1.05)) plt.ylim((-.02, simplex.top_corner + 0.05)) plt.show() ```

2 Simplex dynamics in infinite populations

The same can be done for finite populations, with the added possibility to plot the stationary distribution inside the triangle (see simplex plotting and simplified simplex plotting for a more in-depth example).


📚 Documentation

You can find a full description of available games, strategies, and simulation methods, along with Jupyter notebooks and real-world use cases.


🧪 Testing & Continuous Integration

EGTTools uses GitHub Actions for full CI/CD automation:

  • 🧱 wheels.yml builds wheels for all platforms (Linux, macOS, Windows; x86_64 and arm64)
  • 📘 docs.yml builds documentation and deploys it to GitHub Pages and ReadTheDocs
  • ✅ Unit tests run with pytest and are included in each CI matrix build
  • 🧪 Python stub files are auto-generated from pybind11 bindings for better typing support

To run tests locally:

bash pytest tests

You can also build and validate docs locally with:

bash cd docs make html


📖 Citation

If you use EGTtools in your publications, please cite it in the following way with bibtex:

latex @article{Fernandez2023, author = {Fernández Domingos, Elias and Santos, Francisco C. and Lenaerts, Tom}, title = {EGTtools: Evolutionary game dynamics in Python}, journal = {iScience}, volume = {26}, number = {4}, pages = {106419}, year = {2023}, issn = {2589-0042}, doi = {https://doi.org/10.1016/j.isci.2023.106419} }

Or in text format:

Fernández Domingos, E., Santos, F. C. & Lenaerts, T. EGTtools: Evolutionary game dynamics in Python. iScience 26, 106419 (2023).

And to cite the current version of EGTtools you can use:

latex @misc{Fernandez2020, author = {Fernández Domingos, Elias}, title = {EGTTools: Toolbox for Evolutionary Game Theory (0.1.12)}, year = {2022}, month = {Dec}, journal = {Zenodo}, doi = {10.5281/zenodo.7458631} }

Moreover, you may find our article at here.


📄 License

EGTTools is released under the GPLv3 or later.


🙏 Acknowledgements

Developed and maintained by Elias Fernández.

  • Great parts of this project have been possible thanks to the help of Yannick Jadoul author of Parselmouth and Eugenio Bargiacchi author of AIToolBox. They are both great programmers and scientists, so it is always a good idea to check out their work.
  • EGTtools makes use of the amazing pybind11. library to provide a Python interface for optimized monte-carlo simulations written in C++.

⚠️ Caveats

  • On Windows, OpenMP is currently not supported. All simulations will run single-threaded.
  • On macOS, OpenMP is supported but performance may depend on the installed libomp. If using conda, make sure llvm-openmp is available.
  • Wheels are only built for Python 3.10 – 3.12.
  • Numerical simulations require large RAM allocations when using large population sizes or caching; ensure you configure the cache size accordingly.
  • Advanced users building from source should ensure Boost, Eigen, and BLAS/LAPACK libraries are compatible with their compiler toolchain.

Owner

  • Name: Elias Fernandez
  • Login: Socrats
  • Kind: user
  • Location: Brussels, Belgium
  • Company: Université Libre de Bruxelles

Postdoctoral Researcher at MLG and @vub-ai-lab. Interested in machine learning, reinforcement learning, evolutionary game theory and human behavior

Citation (CITATION.cff)

cff-version: 1.2.0
title: 'EGTtools: Toolbox for Evolutionary Game Theory'
abstract: >-
    This Python package provides efficient implementation of analytical and numerical
    Evolutionary Game Theory methods and models
message: >-
  Please cite this software using the metadata from
  'preferred-citation'.
type: software
authors:
  - family-names: "Fernández Domingos"
    given-names: "Elias"
    orcid: "https://orcid.org/0000-0002-4717-7984"
    affiliation: Machine Learning Group, Université Libre de Bruxelles
    email: elias.fernandez.domingos@ulb.be
keywords:
- Evolutionary Game Theory
- EGT
- Python
- C++
- modeling
- computational social sciences
version: 0.1.12
doi: 10.5281/zenodo.7256084
date-released: 2022-12-19
url: "https://github.com/Socrats/EGTTools"
license: GPL-3.0-or-later
preferred-citation:
  type: article
  authors:
    - family-names: "Fernández Domingos"
      given-names: "Elias"
      orcid: "https://orcid.org/0000-0002-4717-7984"
    - family-names: "Santos"
      given-names: "Francisco C."
    - family-names: "Lenaerts"
      given-names: "Tom"
  doi: https://doi.org/10.1016/j.isci.2023.106419
  journal: "iScience"
  title: "EGTtools: Evolutionary Game Dynamics in Python"
  year: 2023
  volume: 26
  number: 4
  pages: 106419

GitHub Events

Total
  • Release event: 3
  • Watch event: 16
  • Delete event: 15
  • Issue comment event: 9
  • Push event: 176
  • Pull request event: 32
  • Fork event: 4
  • Create event: 25
Last Year
  • Release event: 3
  • Watch event: 16
  • Delete event: 15
  • Issue comment event: 9
  • Push event: 176
  • Pull request event: 32
  • Fork event: 4
  • Create event: 25

Committers

Last synced: 9 months ago

All Time
  • Total Commits: 1,192
  • Total Committers: 4
  • Avg Commits per committer: 298.0
  • Development Distribution Score (DDS): 0.06
Past Year
  • Commits: 193
  • Committers: 2
  • Avg Commits per committer: 96.5
  • Development Distribution Score (DDS): 0.057
Top Committers
Name Email Commits
eliasfernandez S****s 1,120
dependabot[bot] 4****] 69
cvanelteren c****n@g****m 2
The Gitter Badger b****r@g****m 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 8
  • Total pull requests: 118
  • Average time to close issues: 21 days
  • Average time to close pull requests: 20 days
  • Total issue authors: 3
  • Total pull request authors: 5
  • Average comments per issue: 2.13
  • Average comments per pull request: 0.32
  • Merged pull requests: 78
  • Bot issues: 0
  • Bot pull requests: 113
Past Year
  • Issues: 0
  • Pull requests: 35
  • Average time to close issues: N/A
  • Average time to close pull requests: 26 days
  • Issue authors: 0
  • Pull request authors: 1
  • Average comments per issue: 0
  • Average comments per pull request: 0.43
  • Merged pull requests: 16
  • Bot issues: 0
  • Bot pull requests: 35
Top Authors
Issue Authors
  • Socrats (4)
  • cvanelteren (1)
  • intuser (1)
Pull Request Authors
  • dependabot[bot] (135)
  • Socrats (2)
  • gitter-badger (1)
  • ediazysu (1)
Top Labels
Issue Labels
Pull Request Labels
dependencies (135) github_actions (24)

Packages

  • Total packages: 1
  • Total downloads:
    • pypi 325 last-month
  • Total dependent packages: 0
  • Total dependent repositories: 1
  • Total versions: 21
  • Total maintainers: 1
pypi.org: egttools

Efficient Python library for Evolutionary Game Theory (EGT)

  • Versions: 21
  • Dependent Packages: 0
  • Dependent Repositories: 1
  • Downloads: 325 Last month
Rankings
Downloads: 4.5%
Stargazers count: 8.6%
Forks count: 8.9%
Dependent packages count: 10.1%
Average: 10.7%
Dependent repos count: 21.6%
Maintainers (1)
Last synced: 6 months ago

Dependencies

docs/examples/requirements.txt pypi
  • egttools *
  • matplotlib *
  • numpy *
  • scikit-learn *
  • seaborn *
docs/requirements.txt pypi
  • GitPython *
  • PyGithub *
  • Sphinx >=3.2.1
  • docutils <=0.16
  • ipykernel *
  • ipywidgets *
  • nbsphinx >=0.8.7
  • prompt-toolkit <3.0.0
  • recommonmark >=0.7.1
  • requests *
  • sphinx-autodoc-typehints <=1.12.0
  • sphinx_rtd_theme >=0.5.1
requirements.txt pypi
  • matplotlib >=3.3
  • networkx *
  • numpy >=1.7
  • scipy >=1.5
  • seaborn >=0.11.2
tests/requirements.txt pypi
  • pytest * test
.github/workflows/build_macos.yml actions
  • actions/checkout v3 composite
  • actions/setup-python v4 composite
  • actions/upload-artifact v3 composite
  • jwlawson/actions-setup-cmake v1.13 composite
  • mxschmitt/action-tmate v3 composite
  • pypa/cibuildwheel v2.11.2 composite
.github/workflows/ci.yml actions
  • actions/checkout v3 composite
  • actions/setup-python v4 composite
  • ammaraskar/gcc-problem-matcher master composite
  • jwlawson/actions-setup-cmake v1.13 composite
  • mxschmitt/action-tmate v3 composite
.github/workflows/codeql-analysis.yml actions
  • actions/checkout v3 composite
  • github/codeql-action/analyze v2 composite
  • github/codeql-action/autobuild v2 composite
  • github/codeql-action/init v2 composite
.github/workflows/upload_pypi.yml actions
  • actions/checkout v3 composite
  • actions/setup-python v4 composite
  • pypa/gh-action-pypi-publish v1.6.4 composite
  • robinraju/release-downloader v1.7 composite
.github/workflows/wheels.yml actions
  • actions/checkout v3 composite
  • actions/download-artifact v2 composite
  • actions/setup-python v4 composite
  • actions/upload-artifact v3 composite
  • jwlawson/actions-setup-cmake v1.13 composite
  • mxschmitt/action-tmate v3 composite
  • ncipollo/release-action v1.12.0 composite
  • pypa/cibuildwheel v2.11.2 composite
.github/workflows/wheels_windows.yml actions
  • actions/checkout v3 composite
  • actions/setup-python v4 composite
  • actions/upload-artifact v3 composite
  • jwlawson/actions-setup-cmake v1.13 composite
  • mxschmitt/action-tmate v3 composite
  • pypa/cibuildwheel v2.11.2 composite
environment.yml pypi
pyproject.toml pypi
setup.py pypi