Generating games with GAMUT#

GAMUT is a suite of parameterised game generators covering a wide range of game families studied in the game theory literature. Written in Java, GAMUT can generate instances of 35 game classes, including random games, coordination games, covariant games, voting games, and many more.

PyGambit’s generate_gamut function calls GAMUT as an external subprocess and returns the resulting game as a Game object, ready for analysis with PyGambit’s full suite of tools. Before running this tutorial, you will need Java and gamut.jar installed; see the catalog documentation for full installation instructions.

Note: The cell outputs in this notebook were generated locally. To reproduce them, update the gamut_jar argument in each cell to the path of your local gamut.jar.

This tutorial covers:

  • Generating classic two-player games with no additional parameters

  • Generating parameterised random normal-form games

  • Exploring how the covariance parameter in CovariantGame affects equilibrium structure

  • Generating multi-player games

  • Controlling payoff normalisation and obtaining integer payoffs

[1]:
import pygambit as gbt

Discovering available game classes#

gbt.catalog.gamut_games() returns a DataFrame listing all 35 GAMUT game classes, their descriptions, and whether they support more than two players. Use this as a quick reference when choosing a game to generate:

[2]:
gbt.catalog.gamut_games()

[2]:
Class Description Players
0 ArmsRace Arms race with cost and demand functions chose... n
1 BattleOfTheSexes Coordination game where players prefer to meet... 2
2 BertrandOligopoly Bertrand oligopoly with arbitrary cost and dem... n
3 BidirectionalLEG Bidirectional local-effect game on a specified... n
4 Chicken Classic 2x2 Chicken game. 2
5 CollaborationGame Game where all players choosing the same actio... n
6 CongestionGame Congestion game where payoffs depend on how ma... n
7 CoordinationGame Pure coordination game rewarding matching acti... n
8 CournotDuopoly Cournot duopoly with arbitrary cost and invers... 2
9 CovariantGame Game with payoffs whose cross-player correlati... n
10 DispersionGame Game where dispersed action choices are rewarded. n
11 GrabTheDollar Simultaneous competition to claim a prize first. 2
12 GreedyGame Players each choose a subset from a set; payof... 2
13 GuessThirdsAve Players guess a number trying to reach 2/3 of ... n
14 HawkAndDove Classic 2x2 Hawk and Dove game. 2
15 LocationGame Hotelling-style two-player location game on a ... 2
16 MajorityVoting Majority voting game with arbitrary candidate ... n
17 MatchingPennies Classic 2x2 Matching Pennies game. 2
18 MinimumEffortGame Payoffs depend on the minimum effort exerted a... n
19 NPlayerChicken N-player Chicken game with cooperation costs a... n
20 NPlayerPrisonersDilemma N-player Prisoner's Dilemma with parameterised... n
21 PolymatrixGame Polymatrix game formed by two-player edge game... n
22 PrisonersDilemma Classic 2x2 Prisoner's Dilemma. 2
23 RandomCompoundGame Compound game whose payoffs are sums of random... n
24 RandomGame Game with payoffs drawn uniformly at random. n
25 RandomGraphicalGame Random graphical game on a specified graph. n
26 RandomLEG Random local-effect game on a specified graph. n
27 RandomZeroSum Two-player zero-sum game with random payoffs. 2
28 RockPaperScissors Classic Rock, Paper, Scissors game. 2
29 ShapleyGame Shapley's original game; no stable equilibrium... 2
30 SimpleInspectionGame Inspection game where players choose from diff... 2
31 TravelersDilemma Players claim a value; the lowest claim wins a... n
32 TwoByTwoGame 2x2 game of a specified type per Rapoport's cl... 2
33 UniformLEG Local-effect game where all edges share the sa... n
34 WarOfAttrition Players choose concession times; payoffs depen... 2

Classic two-player games#

Many of GAMUT’s game classes correspond directly to well-known games from the game theory literature and require no additional parameters to generate. Here we generate Battle of the Sexes, a canonical 2×2 coordination game.

In Battle of the Sexes, two players must independently decide whether to go to the Opera or a Football match. Both prefer to attend the same event, but player 1 prefers the Opera while player 2 prefers Football. The game has two pure-strategy Nash equilibria — both go to the Opera, or both go to Football — and one mixed-strategy equilibrium.

[3]:
g_bos = gbt.catalog.generate_gamut(
    "BattleOfTheSexes",
    params={
        "int_payoffs": True,
        "int_mult": 1,
        "normalize": True,
        "min_payoff": 0,
        "max_payoff": 3
    },
    gamut_jar="~/Downloads/gamut.jar",
)
g_bos.title = "Battle of the Sexes"
for player in g_bos.players:
    for strategy, label in zip(player.strategies, ["Opera", "Football"], strict=True):
        strategy.label = label
g_bos

[3]:

Battle of the Sexes

Player2
OperaFootball
Player1Opera3,30,0
Football0,03,3

Now let’s compute all Nash equilibria using the linear complementarity method, which is well-suited to two-player games:

[4]:
result_bos = gbt.nash.lcp_solve(g_bos)
len(result_bos.equilibria)

[4]:
3

As expected, the solver finds three equilibria: two pure-strategy equilibria (both play Opera, or both play Football) and one mixed-strategy equilibrium in which each player randomises between the two options:

[5]:
result_bos.equilibria[0]
[5]:
$\left[\left[1,0\right],\left[1,0\right]\right]$
[6]:
result_bos.equilibria[1]
[6]:
$\left[\left[\frac{1}{2},\frac{1}{2}\right],\left[\frac{1}{2},\frac{1}{2}\right]\right]$
[7]:
result_bos.equilibria[2]
[7]:
$\left[\left[0,1\right],\left[0,1\right]\right]$

Payoff normalisation and integer payoffs#

By default, GAMUT draws payoffs uniformly from the range [-100, 100]. These global parameters let you rescale and discretise payoffs:

Parameter

Type

Effect

normalize

boolean flag

Enable rescaling to [min_payoff, max_payoff]

min_payoff

number

Lower bound after normalisation

max_payoff

number

Upper bound after normalisation

int_payoffs

boolean flag

Round all payoffs to integers

int_mult

boolean flag

Multiplier used before rounding when converting from double to integer payoffs

See the GAMUT documentation for more info on the available Global parameters.

Parameterised random normal-form games#

Most GAMUT game classes accept parameters to control the number of players, the number of actions, and the structure of payoffs. These are passed as a dictionary to the params argument; each key maps to a GAMUT command-line flag.

RandomGame is the most general generator: payoffs are drawn independently and uniformly at random from a fixed range. It serves as a useful baseline for testing algorithms. The players parameter controls the number of players, and actions controls the number of actions per player. When actions is a list, each element gives the action count for the corresponding player, allowing asymmetric games:

[8]:
g_rand = gbt.catalog.generate_gamut(
    "RandomGame",
    params={"players": 2, "actions": [3, 3]},
    gamut_jar="~/Downloads/gamut.jar",
)
g_rand.title = "Random Game (2 players, 3x4)"
g_rand

[8]:

Random Game (2 players, 3x4)

Player2
123
Player11-24.90896560296312,-41.46093893377729-97.04833183504611,-23.56380990697073250.0831929786506,26.051862305230316
2-65.96410417734546,44.09018185830413530.77026176277343,-17.52125395472777-10.707266835174579,26.28680487237078
3-65.52630679123462,-87.74228077603547-3.9604024034780565,-61.10491491476051-94.29034279305093,-45.34942611324284
[9]:
gbt.nash.lcp_solve(g_rand).equilibria[0]

[9]:
$\left[\left[1,0,0\right],\left[0,0,1\right]\right]$

Covariant games#

CovariantGame generates two-player games in which the degree of alignment between players’ interests is controlled by a covariance parameter r.

  • When r = 1 the game is a common-payoff game: both players receive identical payoffs.

  • When r = 0 payoffs are independent — equivalent to RandomGame.

  • As r approaches -1 (the minimum for a two-player game) the game approaches a zero-sum game.

Let’s compare an equilibrium under high positive covariance (nearly a coordination game) with one under negative covariance (a more adversarial setting):

[10]:
g_cov_pos = gbt.catalog.generate_gamut(
    "CovariantGame",
    params={"players": 2, "actions": [3, 3], "r": 0.8},
    gamut_jar="~/Downloads/gamut.jar",
)
g_cov_pos.title = "Covariant Game (r=0.8)"
eqm_pos = gbt.nash.lcp_solve(g_cov_pos).equilibria[0]
eqm_pos

[10]:
$\left[\left[1,0,0\right],\left[1,0,0\right]\right]$
[11]:
g_cov_neg = gbt.catalog.generate_gamut(
    "CovariantGame",
    params={"players": 2, "actions": [3, 3], "r": -0.5},
    gamut_jar="~/Downloads/gamut.jar",
)
g_cov_neg.title = "Covariant Game (r=-0.5)"
eqm_neg = gbt.nash.lcp_solve(g_cov_neg).equilibria[0]
eqm_neg

[11]:
$\left[\left[1,0,0\right],\left[0,0,1\right]\right]$

With high positive covariance (r = 0.8) the game is close to a coordination game, so an equilibrium in pure or near-pure strategies is typical. With negative covariance (r = -0.5) the game is more adversarial, making genuinely mixed equilibria more likely.

Multi-player games#

GAMUT includes several n-player game families. Here we use MajorityVoting, a model of a committee in which each player votes for one of several candidates. The candidate who receives the most votes wins, and each player has a privately known preferred candidate.

Voting games naturally lend themselves to pure-strategy analysis — each player simply votes for their preferred candidate. gbt.nash.enumpure_solve searches exhaustively for pure-strategy Nash equilibria and works for games with any number of players:

[12]:
g_mv = gbt.catalog.generate_gamut(
    "MajorityVoting",
    params={
        "int_payoffs": True,
        "int_mult": 1,
        "players": 3,
        "actions": 3
    },
    gamut_jar="~/Downloads/gamut.jar",
)
g_mv.title = "Majority Voting (3 players, 3 candidates)"
g_mv

[12]:

Majority Voting (3 players, 3 candidates)

Subtable with strategies:
Player 3 Strategy 1
Player2
123
Player1139,54,9739,54,9739,54,97
239,54,97-42,-25,8739,54,97
339,54,9739,54,9732,-98,-29
Subtable with strategies:
Player 3 Strategy 2
Player2
123
Player1139,54,97-42,-25,8739,54,97
2-42,-25,87-42,-25,87-42,-25,87
339,54,97-42,-25,8732,-98,-29
Subtable with strategies:
Player 3 Strategy 3
Player2
123
Player1139,54,9739,54,9732,-98,-29
239,54,97-42,-25,8732,-98,-29
332,-98,-2932,-98,-2932,-98,-29
[13]:
result_mv = gbt.nash.enumpure_solve(g_mv)
result_mv.equilibria[0]

[13]:
$\left[\left[1,0,0\right],\left[1,0,0\right],\left[1,0,0\right]\right]$