egttools.numerical.PairwiseComparisonNumerical

class PairwiseComparisonNumerical

Bases: pybind11_object

Numerical solver for evolutionary dynamics under the Pairwise Comparison rule.

This class provides efficient simulation-based methods to estimate the fixation probabilities, stationary distributions, and evolutionary trajectories in finite populations.

Construct a numerical solver for a finite population game.

This class defines methods to estimate numerically fixation probabilities, stationary distributions with or without mutation, and strategy distributions.

Parameters:
  • pop_size (int) – The number of individuals in the population.

  • game (AbstractGame) – A game object implementing the payoff and fitness structure.

  • cache_size (int) – The maximum size of the cache to store fitness computations.

Example

>>> game = egttools.games.Matrix2PlayerGameHolder(3, payoff_matrix)
>>> pc = egttools.PairwiseComparisonNumerical(100, game, 10000)

Notes

Numerical computations are not exact. Moreover, for now we still did not implement a method to automatically detect if the precision of the estimation of the stationary and strategy distributions are good enough and, thus, stop the simulation. You are advised to test different nb_generations and transitory periods for your specific problem (game).

If you want to have exact calculations, you can use egttools.analytical.PairwiseComparison. However, this is only advisable for systems with a smaller number of states (i.e., not too big population size or number of strategies). Otherwise, the calculations might require too much memory.

Methods

estimate_fixation_probability

Estimate fixation probability of an invading strategy in a resident population.

estimate_stationary_distribution

Estimate the full stationary distribution of states in sparse format.

estimate_stationary_distribution_sparse

Sparse estimation of the stationary distribution.

estimate_strategy_distribution

Estimate average frequency of each strategy over time.

evolve

Simulate the pairwise comparison process with mutation.

run

run_with_mutation

Simulates stochastic dynamics with mutation for the specified number of generations.

run_without_mutation

Simulates the stochastic dynamics without mutation.

Attributes

cache_size

Maximum number of cached fitness values.

nb_states

Number of discrete states in the population.

nb_strategies

Number of strategies in the population.

payoffs

Payoff matrix used for selection dynamics.

pop_size

Current population size.

__init__()

Construct a numerical solver for a finite population game.

This class defines methods to estimate numerically fixation probabilities, stationary distributions with or without mutation, and strategy distributions.

Parameters:
  • pop_size (int) – The number of individuals in the population.

  • game (AbstractGame) – A game object implementing the payoff and fitness structure.

  • cache_size (int) – The maximum size of the cache to store fitness computations.

Example

>>> game = egttools.games.Matrix2PlayerGameHolder(3, payoff_matrix)
>>> pc = egttools.PairwiseComparisonNumerical(100, game, 10000)

Notes

Numerical computations are not exact. Moreover, for now we still did not implement a method to automatically detect if the precision of the estimation of the stationary and strategy distributions are good enough and, thus, stop the simulation. You are advised to test different nb_generations and transitory periods for your specific problem (game).

If you want to have exact calculations, you can use egttools.analytical.PairwiseComparison. However, this is only advisable for systems with a smaller number of states (i.e., not too big population size or number of strategies). Otherwise, the calculations might require too much memory.

__new__(**kwargs)
estimate_fixation_probability()

Estimate fixation probability of an invading strategy in a resident population.

This method estimates the fixation probability of one mutant of the invading strategy in a population where all other individuals adopt the resident strategy. The parameter nb_runs is very important, since simulations are stopped once a monomorphic state is reached (all individuals adopt the same strategy). The more runs you specify, the better the estimation. You should consider specifying at least a 1000 runs.

index_invading_strategy : int index_resident_strategy : int nb_runs : int

Number of independent simulations.

nb_generations : int beta : float

float

>>> pc.estimate_fixation_probability(0, 1, 1000, 5000, 1.0)
estimate_stationary_distribution()

Estimate the full stationary distribution of states in sparse format.

This method directly estimates how frequent each strategy is in the population, without calculating the stationary distribution as an intermediary step. You should use this method when the number of states of the system is bigger than MAX_LONG_INT, since it would not be possible to index the states in this case, and estimate_stationary_distribution and estimate_stationary_distribution_sparse would run into an overflow error.

nb_runsint

Number of independent simulations to perform. The final result will be an average over all the runs.

nb_generations : int transitory : int

Burn-in generations to discard.

beta : float mu : float

NDArray[np.float64]

The average frequency of each strategy in the population stored in a sparse array.

>>> pc.estimate_stationary_distribution(100, 10000, 1000, 1.0, 0.01)
estimate_stationary_distribution_sparse()

Sparse estimation of the stationary distribution. Optimized for large sparse state spaces.

Same as estimate_stationary_distribution, but faster and more memory efficient.

Parameters:
  • nb_runs (int) – Number of independent simulations to perform. The final result will be an average over all the runs.

  • nb_generations (int)

  • transitory (int) – Burn-in generations to discard.

  • beta (float)

  • mu (float)

Return type:

scipy.sparse.csr_matrix

estimate_strategy_distribution()

Estimate average frequency of each strategy over time.

This method directly estimates how frequent each strategy is in the population, without calculating the stationary distribution as an intermediary step. You should use this method when the number of states of the system is bigger than MAX_LONG_INT, since it would not be possible to index the states in this case, and estimate_stationary_distribution and estimate_stationary_distribution_sparse would run into an overflow error.

Parameters:
  • nb_runs (int) – Number of independent simulations to perform. The final result will be an average over all the runs.

  • nb_generations (int)

  • transitory (int) – Burn-in generations to discard.

  • beta (float)

  • mu (float)

Return type:

NDArray[np.float64]

Example

>>> pc.estimate_strategy_distribution(100, 10000, 1000, 1.0, 0.01)
evolve()

Simulate the pairwise comparison process with mutation.

Parameters:
  • nb_generations (int) – Number of generations to simulate.

  • beta (float) – Intensity of selection.

  • mu (float) – Mutation rate.

  • init_state (NDArray[np.int64]) – Initial state vector of shape (n_strategies,) with counts per strategy.

Returns:

Final population state as counts of each strategy.

Return type:

NDArray[np.int64]

Example

>>> pc.evolve(5000, 1.0, 0.01, np.array([99, 1, 0]))
run()
run_with_mutation()

Simulates stochastic dynamics with mutation for the specified number of generations.

All intermediate states are returned, starting from the initial condition.

Parameters:
  • nb_generations (int) – Number of generations to simulate.

  • beta (float) – Intensity of selection.

  • mu (float) – Mutation rate.

  • init_state (NDArray[np.int64]) – Initial state of the population.

Returns:

Matrix of shape (nb_generations + 1, nb_strategies) with population states.

Return type:

NDArray[np.int64]

Example

>>> pc.run_with_mutation(5000, 1.0, 0.01, np.array([33, 33, 34]))

Simulates stochastic dynamics with mutation, skipping transient states.

Parameters:
  • nb_generations (int) – Total number of generations.

  • transient (int) – Number of initial generations to discard from the result.

  • beta (float) – Intensity of selection.

  • mu (float) – Mutation rate.

  • init_state (NDArray[np.int64]) – Initial state of the population.

Returns:

Matrix of shape (nb_generations - transient, nb_strategies) with population states.

Return type:

NDArray[np.int64]

Example

>>> pc.run_with_mutation(5000, 1000, 1.0, 0.01, np.array([33, 33, 34]))
run_without_mutation()

Simulates the stochastic dynamics without mutation.

This function returns all the intermediate states of the population for each generation, starting from init_state. No mutation occurs; the process stops when fixation is reached or all generations are simulated.

Parameters:
  • nb_generations (int) – Number of generations to simulate.

  • beta (float) – Intensity of selection.

  • init_state (NDArray[np.int64]) – Initial population state (counts of each strategy).

Returns:

Matrix of shape (nb_generations + 1, nb_strategies) containing all population states.

Return type:

NDArray[np.int64]

Example

>>> pc.run_without_mutation(1000, 1.0, np.array([99, 1, 0]))

Simulates the stochastic dynamics without mutation, skipping transient states.

This overload skips the first transient generations in the output.

Parameters:
  • nb_generations (int) – Total number of generations to simulate.

  • transient (int) – Burn-in period; these generations are excluded from the return.

  • beta (float) – Intensity of selection.

  • init_state (NDArray[np.int64]) – Initial population state (counts of each strategy).

Returns:

Matrix of shape (nb_generations - transient, nb_strategies).

Return type:

NDArray[np.int64]

Example

>>> pc.run_without_mutation(1000, 200, 1.0, np.array([50, 50, 0]))
__annotations__ = {}
property cache_size

Maximum number of cached fitness values.

property nb_states

Number of discrete states in the population.

property nb_strategies

Number of strategies in the population.

property payoffs

Payoff matrix used for selection dynamics.

property pop_size

Current population size.