Compare evolutionary dynamics on a Public Goods Game

The same game can produce qualitatively different outcomes under different evolutionary dynamics. This guide compares the Moran process, Fermi imitation, and introspection dynamics on a homogeneous PGG.

See What is a population dynamic? for the mathematical definitions and How states are represented for the state convention used below.

When to use each dynamic

Moran process: a classical, well-studied baseline. The linear fitness weighting and closed-form fixation formula make results easy to interpret analytically.

Fermi imitation: models noisy social learning, where players sometimes copy worse-performing neighbours. The choice_intensity parameter (\(\beta\)) controls rationality: \(\beta \to 0\) is neutral drift, \(\beta \to \infty\) is strict imitation of better-performing players.

Introspection: players deliberate privately about whether to switch, without comparing themselves to others. The chain is ergodic with no absorbing states; use the stationary distribution rather than fixation probabilities.

Moran and Fermi produce absorbing chains. Introspection produces an ergodic chain.

>>> import ludics
>>> import ludics.fitness_functions
>>> import numpy as np

>>> N = 3
>>> r = 1.5
>>> alpha = 1.0
>>> state_space = ludics.get_state_space(N=N, k=2)

Moran process (absorbing chain)

>>> tm_moran = ludics.generate_transition_matrix(
...     state_space=state_space,
...     fitness_function=ludics.fitness_functions.homogeneous_pgg_fitness_function,
...     compute_transition_probability=ludics.compute_moran_transition_probability,
...     selection_intensity=0.5,
...     r=r,
...     alpha=alpha,
... )
>>> ludics.compute_absorption_matrix(tm_moran)
array([[0.80645161, 0.19354839],
       [0.80645161, 0.19354839],
       [0.48387097, 0.51612903],
       [0.80645161, 0.19354839],
       [0.48387097, 0.51612903],
       [0.48387097, 0.51612903]])

Fermi imitation dynamics (absorbing chain)

>>> tm_fermi = ludics.generate_transition_matrix(
...     state_space=state_space,
...     fitness_function=ludics.fitness_functions.homogeneous_pgg_fitness_function,
...     compute_transition_probability=ludics.compute_fermi_transition_probability,
...     choice_intensity=1.0,
...     r=r,
...     alpha=alpha,
... )
>>> ludics.compute_absorption_matrix(tm_fermi)
array([[0.90996943, 0.09003057],
       [0.90996943, 0.09003057],
       [0.66524096, 0.33475904],
       [0.90996943, 0.09003057],
       [0.66524096, 0.33475904],
       [0.66524096, 0.33475904]])

Introspection dynamics (ergodic chain)

Under introspection, a player can always reconsider even when all others play the same strategy, so the chain has no absorbing states.

>>> tm_intro = ludics.generate_transition_matrix(
...     state_space=state_space,
...     fitness_function=ludics.fitness_functions.homogeneous_pgg_fitness_function,
...     compute_transition_probability=ludics.compute_introspection_transition_probability,
...     choice_intensity=1.0,
...     number_of_strategies=2,
...     r=r,
...     alpha=alpha,
... )
>>> ludics.compute_steady_state(tm_intro)
array([0.24117286, 0.14628008, 0.14628008, 0.08872416, 0.14628008,
       0.08872416, 0.08872416, 0.05381442])

The highest weight falls on all-defect \([0,0,0]\) (~24%) and the lowest on all-contribute \([1,1,1]\) (~5%), as expected when \(r < N\).

Summary

Dynamic Chain type Key quantity
Moran Absorbing Fixation probabilities
Fermi imitation Absorbing Fixation probabilities
Introspection Ergodic Stationary distribution

Fermi dynamics places stronger pressure on payoff differences than the Moran process at comparable parameters, driving fixation toward defection more strongly here.