Skip to main content

AlphaRankMetaSolver

Struct AlphaRankMetaSolver 

Source
pub struct AlphaRankMetaSolver {
    pub ranking_intensity_alpha: f32,
    pub moran_population_size: u32,
    pub max_iterations: usize,
    pub tolerance: f32,
    pub normalize_payoff_span: bool,
}
Expand description

α-rank meta-solver (Omidshafiei et al. 2019, Nature Sci Reports 9:9937).

Computes the stationary distribution of a Markov chain over joint pure strategies where transitions follow Moran-process mutation dynamics: at each step a random agent is selected, a random deviation strategy is proposed for that agent, and the deviation is accepted with probability proportional to 1 / (1 + exp(−α · (payoff_after − payoff_before))).

Guarantee shipped: highest stationary mass under the response-graph Moran dynamics — NOT ε-Nash. The α-rank ordering captures the dynamic strength of strategies but does not coincide with the Nash equilibrium support in general (Omidshafiei et al. 2019 §2 + Discussion). Use this solver when the goal is N-player ranking over joint pure strategies, not Nash refinement.

§API surfaces

Two entry points are provided:

  • AlphaRankMetaSolver::solve (MetaSolver trait): takes a symmetric n × n payoff matrix payoffs[i][j] (row-player payoff when row plays strategy i against column strategy j) and computes the α-rank stationary distribution over the n strategies. This is the 2-player symmetric path and is used for the random-payoff sanity tests. The returned distribution has length n.
  • AlphaRankMetaSolver::solve_n_player: takes a per-agent payoff tensor of shape (num_joint_strategies, num_agents) where payoffs[s][a] is agent a’s scalar payoff at joint pure strategy s, plus the number of agents and the per-agent per-role population size k. The total number of joint strategies must equal k^num_agents. Returns the stationary distribution over the k^num_agents joint strategies. This is the true N-player path used by the PSRO N > 2 branch.

§Defaults (per Omidshafiei §2.3)

  • ranking_intensity_alpha = 10.0 — the response-graph ranking intensity. Larger values sharpen the deviation acceptance probability; the paper’s experiments use α ∈ [1, 100].
  • moran_population_size = 50 — the Moran population size m parameter controlling fixation probability magnitudes. The paper recommends m ≥ 10.
  • max_iterations = 200 — power-iteration cap.
  • tolerance = 1e-6 — power-iteration convergence threshold on L1 distance between successive distributions.

Fields§

§ranking_intensity_alpha: f32

Response-graph ranking intensity α.

§moran_population_size: u32

Moran population size m.

§max_iterations: usize

Maximum power-iteration steps.

§tolerance: f32

Power-iteration L1 convergence tolerance.

§normalize_payoff_span: bool

When true, normalize each Moran payoff differential delta = π_τ − π_σ by the payoff span of the input tensor (max − min over all per-agent payoffs) before multiplying by α (issue #215).

§Why this matters

The Moran fixation probability is driven by α · delta (see moran_fixation_probability). α-rank’s defaults (α = 10, m = 50) were validated on the {−1, +1} matching-pennies game, where |delta| ≤ 2 and α · delta ≤ 20 — comfortably inside the regime where the fixation probability is a graded sigmoid-like function of the payoff advantage. On the bucket-brigade [−700, 0] payoff band, |delta| can reach ~700 and α · delta ≈ 7000, which saturates every non-neutral transition to a hard 0 or 1. The graded Moran dynamics collapse into a degenerate deterministic best-response graph, and the resulting stationary distribution is acutely sensitive to tiny payoff-estimate noise — a plausible contributor to the exploitability divergence observed on the no-convergence cells (issue #215, #198).

When enabled, the differential is rescaled to delta_norm = delta / span (with span = max − min, guarded against a degenerate zero span), so the effective selection strength α · delta_norm lands in the same [−α, α] band the defaults were tuned for regardless of the absolute payoff magnitude. This is the α-rank analogue of NFSP’s / PSRO’s br_reward_scale: a magnitude-invariance fix, not a change to the ranking semantics on a fixed scale.

false (the default) preserves the pre-#215 behavior bit-for-bit.

Implementations§

Source§

impl AlphaRankMetaSolver

Source

pub fn new( ranking_intensity_alpha: f32, moran_population_size: u32, max_iterations: usize, tolerance: f32, ) -> Self

Construct with explicit hyperparameters. Payoff-span normalization defaults to false (pre-#215 behavior). Use AlphaRankMetaSolver::with_payoff_span_normalization to opt in.

Source

pub fn with_payoff_span_normalization(self, enabled: bool) -> Self

Builder-style setter: enable/disable payoff-span normalization of the Moran payoff differential (issue #215). See AlphaRankMetaSolver::normalize_payoff_span for the rationale.

Source

pub fn solve_n_player_impl( &self, payoffs: &[Vec<f32>], num_agents: usize, per_role_k: usize, ) -> Vec<f32>

Inherent N-player α-rank stationary distribution helper.

This is the workhorse implementation called by the MetaSolver::solve_n_player trait override below. Kept as a separate inherent method so callers with a concrete AlphaRankMetaSolver (e.g. the in-tree unit tests at test_alpha_rank_three_player_rps_*) can invoke it without going through trait dispatch.

§Inputs
  • payoffs: shape (num_joint_strategies, num_agents) where payoffs[s][a] is agent a’s payoff at joint pure strategy s.
  • num_agents: number of agents N in the game.
  • per_role_k: per-agent per-role population size k (assumed identical across agents in this PR — matches the symmetric PSRO posture).
§Joint-strategy index encoding

Strategy index s decomposes into per-agent indices (s_0, s_1, ..., s_{N-1}) with s_i ∈ [0, k) via little-endian mixed-radix: s = Σ_i s_i * k^i. Agent 0 is the fastest-varying index.

§Returns

A probability vector of length k^N summing to 1.0 ± 1e-6.

Trait Implementations§

Source§

impl Clone for AlphaRankMetaSolver

Source§

fn clone(&self) -> AlphaRankMetaSolver

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AlphaRankMetaSolver

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for AlphaRankMetaSolver

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl MetaSolver for AlphaRankMetaSolver

Source§

fn solve(&self, payoffs: &[Vec<f32>]) -> Vec<f32>

2-player symmetric α-rank: interprets payoffs[i][j] as the row player’s payoff and computes the α-rank stationary distribution over the n pure strategies under the symmetric self-play assumption (both players draw from the same population). For the 2-player symmetric case this collapses to the solve_n_player path with num_agents = 1 over the row-player marginal — equivalent to treating the column player’s payoff structure as the row’s negation under zero-sum symmetry.

Source§

fn solve_n_player( &self, payoffs: &[Vec<f32>], num_agents: usize, per_role_k: usize, ) -> Vec<f32>

N-player solve over an explicit per-agent payoff tensor. Read more
Source§

fn name(&self) -> &'static str

Human-readable name for diagnostics / logging.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more