egttools.numerical.numerical_.PairwiseComparison¶
- class PairwiseComparison¶
Bases:
pybind11_objectAnalytical pairwise-comparison process for finite populations.
This class studies evolutionary dynamics in a well-mixed population of fixed size \(Z\), whose state is represented by a vector of strategy counts \(x = (x_1, \dots, x_n)\) satisfying \(\sum_{i=1}^n x_i = Z\).
Under the pairwise comparison rule, strategy updates are driven by pairwise imitation, typically through the Fermi kernel
\[p_{i \to j}(x) = \frac{1}{1 + \exp[-\beta (f_j(x) - f_i(x))]},\]where \(\beta \ge 0\) is the intensity of selection and \(f_i(x)\) is the fitness of strategy \(i\) in state \(x\).
The class provides tools to construct the full Markov transition matrix, compute gradients of selection, fixation probabilities, and the reduced small-mutation-limit (SML) dynamics.
Construct an analytical pairwise-comparison process.
- Parameters:
population_size (int) – Population size \(Z\).
game (egttools.games.AbstractGame) – Game defining the fitness of each strategy as a function of the current population state.
Notes
The number of population states is
\[|\mathcal{S}| = \binom{Z + n - 1}{n - 1},\]where \(n\) is the number of strategies.
Construct an analytical pairwise-comparison process with a configurable fitness cache.
- Parameters:
population_size (int) – Population size \(Z\).
game (egttools.games.AbstractGame) – Game defining the fitness of each strategy as a function of the current population state.
cache_size (int) – Maximum number of cached fitness evaluations.
Methods
Compute the fixation probability of one mutant in a monomorphic resident population.
Compute the gradient of selection without mutation at a given population state.
Compute the gradient of selection with mutation at a given population state.
Return the natural log of the fixation probability, \(\log\rho\).
Return the reduced transition matrix and fixation matrix in the small-mutation limit.
Return a numerically stable SML transition matrix and the log-fixation matrix.
Compute the full transition matrix of the finite-population Markov chain.
Return the underlying game.
Return the total number of population states.
Return the number of strategies.
Return the population size.
Precompute fitness values along all edges of the simplex.
Update the population size.
- __init__()¶
Construct an analytical pairwise-comparison process.
- Parameters:
population_size (int) – Population size \(Z\).
game (egttools.games.AbstractGame) – Game defining the fitness of each strategy as a function of the current population state.
Notes
The number of population states is
\[|\mathcal{S}| = \binom{Z + n - 1}{n - 1},\]where \(n\) is the number of strategies.
Construct an analytical pairwise-comparison process with a configurable fitness cache.
- Parameters:
population_size (int) – Population size \(Z\).
game (egttools.games.AbstractGame) – Game defining the fitness of each strategy as a function of the current population state.
cache_size (int) – Maximum number of cached fitness evaluations.
- __new__(**kwargs)¶
- calculate_fixation_probability()¶
Compute the fixation probability of one mutant in a monomorphic resident population.
This method restricts the dynamics to the one-dimensional edge involving the invading and resident strategies only. It returns the probability that a single invader eventually takes over the whole population.
- Parameters:
invading_strategy_index (int) – Index of the invading strategy.
resident_strategy_index (int) – Index of the resident strategy.
beta (float) – Intensity of selection \(\beta\).
high_precision (bool, optional) – When True and the library was compiled with Boost multiprecision support, the internal streaming log-sum-exp is evaluated in 50-digit decimal arithmetic, extending the representable range of \(\exp(\log\phi)\). The return value is still a
float; values belowDBL_MIN(~2.2e-308) are rounded to zero regardless. Usecalculate_log_fixation_probability()for the full dynamic range. Defaults toFalse.
- Returns:
Probability that one invader fixates in a population of residents.
- Return type:
- calculate_gradient_of_selection()¶
Compute the gradient of selection without mutation at a given population state.
Let \(x = (x_1,\dots,x_n)\) be the current state. This method returns the expected one-step drift induced only by selection. For each strategy \(i\),
\[g_i(x) = \frac{1}{n} \sum_{j \ne i} \left[ T^{\mathrm{sel}}_{j \to i}(x) - T^{\mathrm{sel}}_{i \to j}(x) \right],\]where \(T^{\mathrm{sel}}_{j \to i}(x)\) is the probability that one individual of strategy \(j\) is replaced by one individual of strategy \(i\) under pairwise comparison alone.
Under the Fermi rule, the local net flux can be written as
\[T^{\mathrm{sel}}_{j \to i}(x) - T^{\mathrm{sel}}_{i \to j}(x) = \frac{x_i x_j}{Z(Z-1)} \tanh\!\left(\frac{\beta}{2}(f_i(x)-f_j(x))\right).\]The resulting vector is tangent to the simplex, so
\[\sum_{i=1}^n g_i(x) = 0.\]- Parameters:
beta (float) – Intensity of selection \(\beta\).
state (numpy.ndarray) – One-dimensional integer array of shape (nb_strategies,) containing the current population state.
- Returns:
One-dimensional array of shape (nb_strategies,) containing the mutation-free gradient of selection.
- Return type:
- calculate_gradient_of_selection_with_mutation()¶
Compute the gradient of selection with mutation at a given population state.
Let \(x = (x_1,\dots,x_n)\) be the current state, with population size \(Z\) and \(n\) strategies. This method returns the expected one-step drift when both pairwise comparison and mutation are active:
\[g_i^{(\mu)}(x) = (1-\mu)\, g_i(x) + \frac{\mu_{\mathrm{eff}}}{nZ}\left(Z - n x_i\right),\]where \(g_i(x)\) is the mutation-free gradient returned by
calculate_gradient_of_selection(), and \(\mu_{\mathrm{eff}}\) is the effective mutation probability towards one specific alternative strategy:\[\begin{split}\mu_{\mathrm{eff}} = \begin{cases} \mu, & n = 2, \\ \mu/(n-1), & n > 2. \end{cases}\end{split}\]The first term is the selection contribution scaled by \((1-\mu)\), and the second term is the mutation drift induced by uniform mutation towards the other strategies.
As in the mutation-free case, the resulting vector is tangent to the simplex:
\[\sum_{i=1}^n g_i^{(\mu)}(x) = 0.\]- Parameters:
beta (float) – Intensity of selection \(\beta\).
mu (float) – Mutation probability \(\mu\).
state (numpy.ndarray) – One-dimensional integer array of shape (nb_strategies,) containing the current population state.
- Returns:
One-dimensional array of shape (nb_strategies,) containing the gradient with mutation.
- Return type:
- calculate_log_fixation_probability()¶
Return the natural log of the fixation probability, \(\log\rho\).
Unlike
calculate_fixation_probability(), this method never underflows: the result is a finitefloatfor any combination of \(\beta\), population size, and fitness values. It is computed as \(-\mathrm{softplus}(\log\phi)\), so values as small as \(e^{-10^{308}}\) are representable.
- calculate_transition_and_fixation_matrix_sml()¶
Return the reduced transition matrix and fixation matrix in the small-mutation limit.
In the Small Mutation Limit (SML), mutations are assumed sufficiently rare that the population is almost always monomorphic before the next mutation occurs. The resulting reduced Markov chain acts only on the monomorphic states.
If the current monomorphic state is strategy \(i\), then for \(i \ne j\)
\[T_{ij}^{\mathrm{SML}} = \frac{\rho_{ij}}{n-1},\]where \(\rho_{ij}\) is the fixation probability of one mutant of strategy \(j\) in a resident population of strategy \(i\). The diagonal entries are set so that each row sums to one.
- Parameters:
beta (float) – Intensity of selection \(\beta\).
- Returns:
A tuple (transition_matrix, fixation_probabilities) where:
transition_matrix is the reduced SML transition matrix of shape (nb_strategies, nb_strategies);
fixation_probabilities[i, j] is the probability that one mutant of strategy j fixates in a population of strategy i.
- Return type:
- calculate_transition_and_log_fixation_matrix_sml()¶
Return a numerically stable SML transition matrix and the log-fixation matrix.
Like
calculate_transition_and_fixation_matrix_sml()but stores \(\log\rho_{ij}\) and builds the transition matrix by scaling all off-diagonal entries by \(\exp(-\max_{k\ne l}\log\rho_{kl})\). This global rescaling preserves the stationary distribution while guaranteeing a valid stochastic matrix even when every \(\rho_{ij}\) underflows to zero in double precision.- Parameters:
beta (float) – Intensity of selection \(\beta\).
- Returns:
A tuple (transition_matrix, log_fixation_probabilities) where:
transition_matrix has the same stationary distribution as the standard SML matrix but is numerically well-conditioned;
log_fixation_probabilities[i, j] = \(\log\rho_{ij}\).
- Return type:
- calculate_transition_matrix()¶
Compute the full transition matrix of the finite-population Markov chain.
The chain evolves on the set of all population states
\[\mathcal{S} = \left\{x \in \mathbb{N}^n : \sum_{i=1}^n x_i = Z \right\}.\]Each off-diagonal transition changes the state by replacing one individual of one strategy by one individual of another strategy. Mutation is incorporated directly into the transition probabilities, and diagonal entries are set so that each row sums to one.
- Parameters:
- Returns:
Sparse transition matrix of shape (nb_states, nb_states).
- Return type:
Notes
For large state spaces, explicitly constructing this matrix may require a large amount of memory.
Implementation note: fitness values are pre-computed in a serial pass (with the GIL held, so Python-subclassed games work correctly), then the sparse matrix is assembled in a parallel OpenMP pass (with the GIL released).
- game()¶
Return the underlying game.
- Returns:
Reference to the game used to evaluate fitness.
- Return type:
- nb_states()¶
Return the total number of population states.
- Returns:
Number of states in the full Markov chain.
- Return type:
- pre_calculate_edge_fitnesses()¶
Precompute fitness values along all edges of the simplex.
This is particularly useful for repeated pairwise fixation calculations, since fixation probabilities only depend on states involving two strategies at a time.
- update_population_size()¶
Update the population size.
- Parameters:
population_size (int) – New population size \(Z\).
- __annotations__ = {}¶