Climate coalition formation — cooperative game theory and the stability of international agreements

case-studies
cooperative-games
coalition-formation
climate-policy
Model international climate agreements as a cooperative partition function game, compute Shapley values for responsibility allocation, analyse coalition stability and free-riding incentives, and visualize why the grand coalition is unstable.
Author

Raban Heller

Published

May 8, 2026

Modified

May 8, 2026

Keywords

coalition formation, cooperative game theory, Shapley value, climate agreement, free-riding, partition function game, Paris Agreement

Introduction & motivation

International climate change mitigation is arguably the most consequential cooperation problem in human history. Every country benefits from reduced global emissions, but each country bears the full cost of its own abatement while the benefits are shared globally. This creates a textbook free-rider problem: each country has an incentive to let others bear the cost of emissions reduction while enjoying the benefits. The result, absent binding agreements, is underprovision of the global public good of climate stability.

Cooperative game theory provides the natural framework for analysing this problem. Countries can form coalitions — groups that coordinate their emissions policies — and the question is which coalition structures are stable in the sense that no country (or subgroup) has an incentive to leave or rearrange. The grand coalition (all countries cooperating) is socially optimal but typically unstable: large emitters can gain by free-riding on others’ abatement efforts. This fundamental tension between efficiency and stability is why international climate negotiations have been so protracted and why agreements like the Kyoto Protocol and the Paris Agreement have adopted very different architectural designs.

The model we implement here treats climate cooperation as a partition function game ((yi_1997?)), where the value of a coalition depends not just on its own members but on the entire partition of countries into coalitions. This is because when one coalition forms, the remaining countries adjust their behaviour — an effect called externalities across coalitions. If a coalition of major emitters agrees to reduce emissions, non-members benefit (positive externality) and may reduce their own abatement efforts (free-riding). The partition function captures these strategic feedbacks.

We focus on a simplified world with 6 stylised countries (representing major emitting regions: US, EU, China, India, Russia, and a Rest-of-World aggregate), calibrated to approximate their relative emissions shares and abatement costs. We compute the Shapley value for each country — the cooperative game theory’s canonical measure of each player’s fair share of the total surplus, based on their marginal contribution across all possible coalitions. We then analyse the stability of various coalition structures: the grand coalition, regional blocs, the Paris-style bottom-up pledge architecture, and unilateral action. The analysis reveals the fundamental trade-off that has plagued climate negotiations: cooperation is efficient but unstable, and the gap between what is collectively optimal and what is individually rational drives the architecture of real-world climate agreements.

Readers familiar with the Tragedy of the Commons will recognise the underlying logic, but the cooperative game theory framework adds structure: it quantifies each player’s power and responsibility, identifies which coalitions are viable, and prescribes surplus-sharing rules that could (in principle) sustain cooperation. This tutorial bridges abstract cooperative game theory with one of the most pressing applied problems of our time.

Mathematical formulation

Players. \(N = \{1, \ldots, n\}\) countries. Each country \(i\) has emissions \(e_i\), abatement cost function \(C_i(a_i) = \frac{1}{2} c_i a_i^2\) for abatement \(a_i \geq 0\), and climate damage \(D_i(E) = d_i \cdot E\) where \(E = \sum_j (e_j - a_j)\) is total remaining emissions.

Coalition value. For a coalition \(S \subseteq N\), members jointly minimise total cost:

\[ v(S) = -\min_{\{a_i\}_{i \in S}} \left\{ \sum_{i \in S} \left[ \frac{1}{2} c_i a_i^2 + d_i \cdot E \right] \right\} \]

where non-members \(j \notin S\) choose \(a_j\) individually (Nash behaviour). The coalition’s value accounts for the strategic reaction of outsiders.

Shapley value. The Shapley value assigns to each country \(i\) its average marginal contribution:

\[ \phi_i(v) = \sum_{S \subseteq N \setminus \{i\}} \frac{|S|! \, (n - |S| - 1)!}{n!} \left[ v(S \cup \{i\}) - v(S) \right] \]

Core stability. The grand coalition is core-stable if no subcoalition \(S\) can do better on its own:

\[ \sum_{i \in S} x_i \geq v(S) \quad \forall\, S \subseteq N \]

where \(x_i\) is country \(i\)’s allocation. If no such allocation exists, the core is empty and the grand coalition is unstable.

R implementation

# --- Country parameters (stylised) ---
countries <- c("US", "EU", "China", "India", "Russia", "RoW")
n <- length(countries)

# Emissions shares (approximate, summing to 100 units)
emissions <- c(US = 15, EU = 10, China = 30, India = 8, Russia = 5, RoW = 32)

# Marginal abatement cost coefficients (higher = more expensive to abate)
abatement_cost <- c(US = 2.0, EU = 2.5, China = 1.0, India = 0.8, Russia = 1.5, RoW = 0.6)

# Marginal damage coefficients (damage per unit of remaining emissions)
damage_coeff <- c(US = 0.8, EU = 0.7, China = 0.5, India = 0.6, Russia = 0.3, RoW = 1.0)

# --- Compute optimal abatement for a coalition ---
compute_coalition_outcome <- function(coalition_members, all_countries = countries) {
  n_all <- length(all_countries)
  in_coalition <- all_countries %in% coalition_members

  # Coalition jointly internalises its members' damages
  coalition_damage <- sum(damage_coeff[coalition_members])

  # Each non-member internalises only own damage
  # Optimal abatement: a_i = d_eff / c_i (from FOC of cost minimisation)
  abatement <- numeric(n_all)
  names(abatement) <- all_countries

  for (i in seq_along(all_countries)) {
    country <- all_countries[i]
    if (in_coalition[i]) {
      # Coalition member: internalises coalition's total marginal damage
      abatement[i] <- coalition_damage / abatement_cost[country]
    } else {
      # Non-member: internalises only own damage
      abatement[i] <- damage_coeff[country] / abatement_cost[country]
    }
    # Cap abatement at emissions level
    abatement[i] <- min(abatement[i], emissions[country])
  }

  total_emissions <- sum(emissions) - sum(abatement)
  total_emissions <- max(total_emissions, 0)

  # Payoff for each country: -(abatement cost + damage)
  payoffs <- numeric(n_all)
  names(payoffs) <- all_countries
  for (i in seq_along(all_countries)) {
    country <- all_countries[i]
    cost <- 0.5 * abatement_cost[country] * abatement[i]^2
    damage <- damage_coeff[country] * total_emissions
    payoffs[i] <- -(cost + damage)
  }

  list(abatement = abatement, total_emissions = total_emissions,
       payoffs = payoffs)
}

# --- Coalition values ---
# No cooperation (all singletons)
no_coop <- compute_coalition_outcome(character(0))
cat("=== No Cooperation (All Singletons) ===\n")
=== No Cooperation (All Singletons) ===
for (i in seq_along(countries)) {
  solo <- compute_coalition_outcome(countries[i])
  cat(sprintf("  %s: abatement=%.2f, payoff=%.2f\n",
              countries[i], solo$abatement[i], solo$payoffs[i]))
}
  US: abatement=0.40, payoff=-77.12
  EU: abatement=0.28, payoff=-67.44
  China: abatement=0.50, payoff=-48.23
  India: abatement=0.75, payoff=-57.95
  Russia: abatement=0.20, payoff=-28.89
  RoW: abatement=1.67, payoff=-97.04
# Grand coalition
grand <- compute_coalition_outcome(countries)
cat("\n=== Grand Coalition ===\n")

=== Grand Coalition ===
cat(sprintf("  Total emissions: %.2f (down from %.2f baseline)\n",
            grand$total_emissions, sum(emissions)))
  Total emissions: 78.61 (down from 100.00 baseline)
cat(sprintf("  Total reduction: %.1f%%\n",
            100 * (1 - grand$total_emissions / sum(emissions))))
  Total reduction: 21.4%
for (i in seq_along(countries)) {
  cat(sprintf("  %s: abatement=%.2f, payoff=%.2f\n",
              countries[i], grand$abatement[i], grand$payoffs[i]))
}
  US: abatement=1.95, payoff=-66.69
  EU: abatement=1.56, payoff=-58.07
  China: abatement=3.90, payoff=-46.91
  India: abatement=4.88, payoff=-56.68
  Russia: abatement=2.60, payoff=-28.65
  RoW: abatement=6.50, payoff=-91.29
# --- Shapley value computation ---
compute_shapley <- function() {
  shapley <- numeric(n)
  names(shapley) <- countries

  # Enumerate all subsets of N\{i}
  for (i in 1:n) {
    others <- countries[-i]
    n_others <- length(others)
    total_mc <- 0

    # All subsets of others
    for (k in 0:n_others) {
      if (k == 0) {
        subsets <- list(character(0))
      } else {
        idx_combos <- combn(n_others, k, simplify = FALSE)
        subsets <- lapply(idx_combos, function(idx) others[idx])
      }

      weight <- factorial(k) * factorial(n - k - 1) / factorial(n)

      for (S in subsets) {
        # v(S u {i}) - v(S)
        S_with_i <- c(S, countries[i])
        outcome_with <- compute_coalition_outcome(S_with_i)
        outcome_without <- compute_coalition_outcome(S)

        v_with <- sum(outcome_with$payoffs)
        v_without <- sum(outcome_without$payoffs)

        total_mc <- total_mc + weight * (v_with - v_without)
      }
    }
    shapley[i] <- total_mc
  }
  shapley
}

shapley_values <- compute_shapley()
cat("\n=== Shapley Values (marginal contribution to cooperation) ===\n")

=== Shapley Values (marginal contribution to cooperation) ===
for (i in seq_along(countries)) {
  cat(sprintf("  %s: phi = %.4f\n", countries[i], shapley_values[i]))
}
  US: phi = 3.9146
  EU: phi = 3.3975
  China: phi = 4.9141
  India: phi = 5.7535
  Russia: phi = 3.5233
  RoW: phi = 6.8619
cat(sprintf("  Sum of Shapley values: %.4f\n", sum(shapley_values)))
  Sum of Shapley values: 28.3651
cat(sprintf("  Grand coalition total payoff: %.4f\n", sum(grand$payoffs)))
  Grand coalition total payoff: -348.2992
# --- Stability analysis ---
cat("\n=== Coalition Stability Analysis ===\n")

=== Coalition Stability Analysis ===
# Check if any single country benefits from leaving grand coalition
for (i in 1:n) {
  remaining <- countries[-i]
  outcome_defect <- compute_coalition_outcome(remaining)
  # Defector's payoff when others still cooperate
  defector_payoff <- outcome_defect$payoffs[countries[i]]
  coalition_payoff <- grand$payoffs[countries[i]]
  gain <- defector_payoff - coalition_payoff
  cat(sprintf("  %s leaves: payoff %.2f -> %.2f (gain = %+.2f) %s\n",
              countries[i], coalition_payoff, defector_payoff, gain,
              ifelse(gain > 0, "** WANTS TO LEAVE **", "stays")))
}
  US leaves: payoff -66.69 -> -67.48 (gain = -0.79) stays
  EU leaves: payoff -58.07 -> -58.52 (gain = -0.44) stays
  China leaves: payoff -46.91 -> -42.25 (gain = +4.66) ** WANTS TO LEAVE **
  India leaves: payoff -56.68 -> -51.39 (gain = +5.28) ** WANTS TO LEAVE **
  Russia leaves: payoff -28.65 -> -24.77 (gain = +3.89) ** WANTS TO LEAVE **
  RoW leaves: payoff -91.29 -> -88.10 (gain = +3.19) ** WANTS TO LEAVE **

Static publication-ready figure

# Compute defection incentives
defection_data <- tibble(
  country = countries,
  shapley = shapley_values,
  grand_payoff = grand$payoffs
) |>
  rowwise() |>
  mutate(
    defect_payoff = {
      remaining <- setdiff(countries, country)
      outcome <- compute_coalition_outcome(remaining)
      outcome$payoffs[country]
    },
    defection_gain = defect_payoff - grand_payoff
  ) |>
  ungroup() |>
  mutate(country = factor(country, levels = countries))

p1 <- ggplot(defection_data, aes(x = country, y = shapley, fill = country)) +
  geom_col(width = 0.6) +
  scale_fill_manual(values = okabe_ito[1:6], guide = "none") +
  labs(title = "Shapley values",
       subtitle = "Marginal contribution to cooperation",
       x = NULL, y = "Shapley value") +
  theme_publication()

p2 <- ggplot(defection_data, aes(x = country, y = defection_gain, fill = country)) +
  geom_col(width = 0.6) +
  geom_hline(yintercept = 0, linewidth = 0.3) +
  scale_fill_manual(values = okabe_ito[1:6], guide = "none") +
  labs(title = "Defection incentive",
       subtitle = "Payoff gain from leaving grand coalition",
       x = NULL, y = "Payoff gain from defection") +
  theme_publication()

# Combine using base ggplot side-by-side via grid
gridExtra_available <- requireNamespace("gridExtra", quietly = TRUE)
if (gridExtra_available) {
  gridExtra::grid.arrange(p1, p2, ncol = 2)
} else {
  # Fallback: combine data for faceting
  plot_data <- defection_data |>
    select(country, shapley, defection_gain) |>
    pivot_longer(cols = c(shapley, defection_gain),
                 names_to = "metric", values_to = "value") |>
    mutate(metric = ifelse(metric == "shapley", "Shapley value",
                           "Defection incentive"))

  ggplot(plot_data, aes(x = country, y = value, fill = country)) +
    geom_col(width = 0.6) +
    geom_hline(yintercept = 0, linewidth = 0.3) +
    facet_wrap(~metric, scales = "free_y") +
    scale_fill_manual(values = okabe_ito[1:6], guide = "none") +
    labs(title = "Climate coalition: Shapley values and defection incentives",
         subtitle = "All countries gain from leaving the grand coalition (empty core)",
         x = NULL, y = "Value") +
    theme_publication() +
    theme(strip.text = element_text(face = "bold"))
}
Figure 1: Figure 1. Left: Shapley values showing each country’s marginal contribution to international climate cooperation. China has the largest Shapley value due to high emissions and low abatement costs, meaning it contributes most to coalition surplus. Right: Incentive to defect from the grand coalition — positive values indicate a country gains from leaving while others cooperate. All major emitters have positive defection incentives, demonstrating that the grand coalition is unstable (empty core). This is the fundamental free-rider problem in climate cooperation. Okabe-Ito palette.

Interactive figure

# Compare coalition structures: grand, regional, bilateral, none
coalition_structures <- list(
  "No cooperation" = list(),
  "US-EU bilateral" = list(c("US", "EU")),
  "Major emitters (US+EU+China)" = list(c("US", "EU", "China")),
  "North-South (US+EU+Russia vs China+India+RoW)" = list(
    c("US", "EU", "Russia"), c("China", "India", "RoW")),
  "Grand coalition" = list(countries)
)

structure_results <- lapply(names(coalition_structures), function(name) {
  coalitions <- coalition_structures[[name]]
  if (length(coalitions) == 0) {
    # No cooperation: each country is a singleton coalition
    outcome <- compute_coalition_outcome(character(0))
  } else {
    # Use the first (or largest) coalition for simplicity
    # For multi-coalition, use the largest
    largest <- coalitions[[which.max(sapply(coalitions, length))]]
    outcome <- compute_coalition_outcome(largest)
  }
  tibble(
    structure = name,
    total_emissions = outcome$total_emissions,
    total_payoff = sum(outcome$payoffs),
    reduction_pct = 100 * (1 - outcome$total_emissions / sum(emissions))
  )
}) |> bind_rows() |>
  mutate(
    structure = factor(structure, levels = names(coalition_structures)),
    text = paste0("Structure: ", structure,
                  "\nEmissions: ", round(total_emissions, 1),
                  "\nReduction: ", round(reduction_pct, 1), "%",
                  "\nTotal welfare: ", round(total_payoff, 1))
  )

p_int <- ggplot(structure_results,
                aes(x = reduction_pct, y = total_payoff,
                    color = structure, text = text)) +
  geom_point(size = 4) +
  scale_color_manual(values = okabe_ito[1:5], name = "Coalition structure") +
  labs(title = "Emissions reduction vs total welfare across coalition structures",
       subtitle = "Hover for details; grand coalition is most efficient but unstable",
       x = "Emissions reduction (%)", y = "Total welfare (negative cost)") +
  theme_publication()

ggplotly(p_int, tooltip = "text") |>
  config(displaylogo = FALSE, modeBarButtonsToRemove = c("select2d", "lasso2d"))
Figure 2

Interpretation

The cooperative game theory analysis reveals the central paradox of international climate cooperation: the grand coalition is the most efficient outcome but is inherently unstable. Every major emitter has a positive incentive to defect — to let others bear abatement costs while enjoying the benefits of their reduced emissions. This is not a theoretical curiosity; it is the structural reason why binding international climate agreements have been so difficult to achieve and maintain.

The Shapley values provide a principled allocation of responsibility. China’s large Shapley value reflects its combination of high emissions and relatively low abatement costs, meaning it has the most to contribute to efficient global abatement. The US and EU have large Shapley values due to their high marginal damage costs (they have much to lose from climate change) and moderate abatement costs. India and the Rest-of-World aggregate have lower per-unit costs but high aggregate emissions. Russia’s low damage coefficient and moderate emissions give it a relatively small Shapley value, explaining why it has historically been a reluctant participant in climate negotiations.

The instability of the grand coalition helps explain the evolution of climate governance architecture. The Kyoto Protocol attempted a binding top-down grand coalition approach, which largely failed as major emitters withdrew or never joined. The Paris Agreement shifted to a bottom-up pledge-and-review system precisely because the cooperative game theory problem is so severe: rather than trying to enforce an unstable grand coalition, Paris allows countries to make voluntary nationally determined contributions (NDCs). This is less efficient than the grand coalition but may be more stable, because it does not require countries to commit to levels of abatement that they individually have an incentive to defect from. The lesson from cooperative game theory is sobering: in the absence of an enforcement mechanism, the free-riding incentive may dominate, and institutional design must work around this constraint rather than ignore it.

References

Back to top

Reuse

Citation

BibTeX citation:
@online{heller2026,
  author = {Heller, Raban},
  title = {Climate Coalition Formation — Cooperative Game Theory and the
    Stability of International Agreements},
  date = {2026-05-08},
  url = {https://r-heller.github.io/equilibria/tutorials/case-studies/climate-coalition-formation/},
  langid = {en}
}
For attribution, please cite this work as:
Heller, Raban. 2026. “Climate Coalition Formation — Cooperative Game Theory and the Stability of International Agreements.” May 8. https://r-heller.github.io/equilibria/tutorials/case-studies/climate-coalition-formation/.