Skip to content

Ranking Algorithm

RankHub uses the Glicko-2 rating system to compute rankings from pairwise votes. This page describes the algorithm and the integer storage conventions used in the codebase.

Overview

Glicko-2 improves on the original Glicko and Elo systems by introducing an explicit volatility parameter and a more robust rating update procedure. Every item has three metrics:

MetricSymbolDefaultRange
Rating$\mu$1500.000.00 -- 3000.00
Rating Dev.$\phi$350.001.00 -- 350.00
Volatility$\sigma$0.060.000001 -- 1.0

Step 1: Convert to Glicko-2 Scale

Before computing updates, ratings and RDs are converted to the Glicko-2 scale:

$$\mu = \frac{r - 1500}{173.7178}$$

$$\phi = \frac{RD}{173.7178}$$

Step 2: Compute g(phi)

The scale factor reduces the impact of high-uncertainty opponents:

$$g(\phi) = \frac{1}{\sqrt{1 + \frac{3\phi^2}{\pi^2}}}$$

Step 3: Compute Expected Score

The expected score of item $i$ against opponent $j$:

$$E(\mu_i, \mu_j) = \frac{1}{1 + \exp(-g(\phi_j)(\mu_i - \mu_j))}$$

Scores are 1 for a win, 0 for a loss.

Step 4: Compute Variance

The variance of the ratings based on the game outcomes:

$$v = \left(\sum_{j=1}^{n} g(\phi_j)^2 \cdot E_j \cdot (1 - E_j)\right)^{-1}$$

Step 5: Determine New Volatility

Volatility is updated using the Illinois algorithm (a modified regula falsi method) to solve:

Let $x = \ln(\sigma'^2)$. The objective function solved by Illinois is:

$$f(x) = \frac{e^x(\Delta^2 - \phi^2 - v - e^x)}{2(\phi^2 + v + e^x)^2} - \frac{x - a}{\tau^2}$$

where $a = \ln(\sigma^2)$.

where:

$$\Delta = v \cdot \sum_{j=1}^{n} g(\phi_j)(s_j - E_j)$$

The algorithm iterates until convergence (tolerance $< 10^{-7}$ in Glicko-2 units), with a hard cap of 100 iterations.

Step 6: Update Rating and RD

$$\phi^* = \sqrt{\phi^2 + \sigma_{new}^2}$$

$$\phi_{new} = \frac{1}{\sqrt{\frac{1}{(\phi^*)^2} + \frac{1}{v}}}$$

$$\mu_{new} = \mu + \phi_{new}^2 \cdot \sum_{j=1}^{n} g(\phi_j)(s_j - E_j)$$

Finally, convert back from Glicko-2 scale to display values:

$$r_{new} = 173.7178 \cdot \mu_{new} + 1500$$

$$RD_{new} = 173.7178 \cdot \phi_{new}$$

Integer Storage Convention

To ensure deterministic results across Cloudflare isolate boundaries (which use 64-bit floats), all Glicko-2 metrics are stored as integers:

MetricDisplay FormatStorage FormatMultiplier
Rating1500.00150000x 100
RD350.0035000x 100
Volatility0.0660000x 10^6

Conversion helpers are provided in @repo/engine:

  • ratingToDisplay(value) -- storage integer to display float
  • ratingToStorage(value) -- display float to storage integer
  • rdToDisplay(value) / rdToStorage(value)
  • volatilityToDisplay(value) / volatilityToStorage(value)

System Constants

ConstantStorage ValueDisplay Value
Initial rating1500001500.00
Initial RD35000350.00
Initial volatility600000.06
System constant (tau)500000.50

Numerical Stability

  • Minimum variance enforced at 0.0001 to prevent division by near-zero.
  • Convergence tolerance for the Illinois algorithm: $10^{-7}$ in Glicko-2 units.
  • All arithmetic uses integer operations where possible to avoid floating-point divergence between isolates.