{ "cells": [ { "cell_type": "markdown", "id": "gamut-intro", "metadata": {}, "source": [ "# Generating games with GAMUT\n", "\n", "[GAMUT](http://gamut.stanford.edu/) 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.\n", "\n", "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](../../catalog.html#catalog-gamut) for full installation instructions.\n", "\n", "> **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`.\n", "\n", "This tutorial covers:\n", "- Generating classic two-player games with no additional parameters\n", "- Generating parameterised random normal-form games\n", "- Exploring how the covariance parameter in `CovariantGame` affects equilibrium structure\n", "- Generating multi-player games\n", "- Controlling payoff normalisation and obtaining integer payoffs\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "gamut-imports", "metadata": {}, "outputs": [], "source": [ "import pygambit as gbt" ] }, { "cell_type": "markdown", "id": "a08eb52d", "metadata": {}, "source": [ "## Discovering available game classes\n", "\n", "`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:\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "1a5dde4f", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ClassDescriptionPlayers
0ArmsRaceArms race with cost and demand functions chose...n
1BattleOfTheSexesCoordination game where players prefer to meet...2
2BertrandOligopolyBertrand oligopoly with arbitrary cost and dem...n
3BidirectionalLEGBidirectional local-effect game on a specified...n
4ChickenClassic 2x2 Chicken game.2
5CollaborationGameGame where all players choosing the same actio...n
6CongestionGameCongestion game where payoffs depend on how ma...n
7CoordinationGamePure coordination game rewarding matching acti...n
8CournotDuopolyCournot duopoly with arbitrary cost and invers...2
9CovariantGameGame with payoffs whose cross-player correlati...n
10DispersionGameGame where dispersed action choices are rewarded.n
11GrabTheDollarSimultaneous competition to claim a prize first.2
12GreedyGamePlayers each choose a subset from a set; payof...2
13GuessThirdsAvePlayers guess a number trying to reach 2/3 of ...n
14HawkAndDoveClassic 2x2 Hawk and Dove game.2
15LocationGameHotelling-style two-player location game on a ...2
16MajorityVotingMajority voting game with arbitrary candidate ...n
17MatchingPenniesClassic 2x2 Matching Pennies game.2
18MinimumEffortGamePayoffs depend on the minimum effort exerted a...n
19NPlayerChickenN-player Chicken game with cooperation costs a...n
20NPlayerPrisonersDilemmaN-player Prisoner's Dilemma with parameterised...n
21PolymatrixGamePolymatrix game formed by two-player edge game...n
22PrisonersDilemmaClassic 2x2 Prisoner's Dilemma.2
23RandomCompoundGameCompound game whose payoffs are sums of random...n
24RandomGameGame with payoffs drawn uniformly at random.n
25RandomGraphicalGameRandom graphical game on a specified graph.n
26RandomLEGRandom local-effect game on a specified graph.n
27RandomZeroSumTwo-player zero-sum game with random payoffs.2
28RockPaperScissorsClassic Rock, Paper, Scissors game.2
29ShapleyGameShapley's original game; no stable equilibrium...2
30SimpleInspectionGameInspection game where players choose from diff...2
31TravelersDilemmaPlayers claim a value; the lowest claim wins a...n
32TwoByTwoGame2x2 game of a specified type per Rapoport's cl...2
33UniformLEGLocal-effect game where all edges share the sa...n
34WarOfAttritionPlayers choose concession times; payoffs depen...2
\n", "
" ], "text/plain": [ " Class \\\n", "0 ArmsRace \n", "1 BattleOfTheSexes \n", "2 BertrandOligopoly \n", "3 BidirectionalLEG \n", "4 Chicken \n", "5 CollaborationGame \n", "6 CongestionGame \n", "7 CoordinationGame \n", "8 CournotDuopoly \n", "9 CovariantGame \n", "10 DispersionGame \n", "11 GrabTheDollar \n", "12 GreedyGame \n", "13 GuessThirdsAve \n", "14 HawkAndDove \n", "15 LocationGame \n", "16 MajorityVoting \n", "17 MatchingPennies \n", "18 MinimumEffortGame \n", "19 NPlayerChicken \n", "20 NPlayerPrisonersDilemma \n", "21 PolymatrixGame \n", "22 PrisonersDilemma \n", "23 RandomCompoundGame \n", "24 RandomGame \n", "25 RandomGraphicalGame \n", "26 RandomLEG \n", "27 RandomZeroSum \n", "28 RockPaperScissors \n", "29 ShapleyGame \n", "30 SimpleInspectionGame \n", "31 TravelersDilemma \n", "32 TwoByTwoGame \n", "33 UniformLEG \n", "34 WarOfAttrition \n", "\n", " Description Players \n", "0 Arms race with cost and demand functions chose... n \n", "1 Coordination game where players prefer to meet... 2 \n", "2 Bertrand oligopoly with arbitrary cost and dem... n \n", "3 Bidirectional local-effect game on a specified... n \n", "4 Classic 2x2 Chicken game. 2 \n", "5 Game where all players choosing the same actio... n \n", "6 Congestion game where payoffs depend on how ma... n \n", "7 Pure coordination game rewarding matching acti... n \n", "8 Cournot duopoly with arbitrary cost and invers... 2 \n", "9 Game with payoffs whose cross-player correlati... n \n", "10 Game where dispersed action choices are rewarded. n \n", "11 Simultaneous competition to claim a prize first. 2 \n", "12 Players each choose a subset from a set; payof... 2 \n", "13 Players guess a number trying to reach 2/3 of ... n \n", "14 Classic 2x2 Hawk and Dove game. 2 \n", "15 Hotelling-style two-player location game on a ... 2 \n", "16 Majority voting game with arbitrary candidate ... n \n", "17 Classic 2x2 Matching Pennies game. 2 \n", "18 Payoffs depend on the minimum effort exerted a... n \n", "19 N-player Chicken game with cooperation costs a... n \n", "20 N-player Prisoner's Dilemma with parameterised... n \n", "21 Polymatrix game formed by two-player edge game... n \n", "22 Classic 2x2 Prisoner's Dilemma. 2 \n", "23 Compound game whose payoffs are sums of random... n \n", "24 Game with payoffs drawn uniformly at random. n \n", "25 Random graphical game on a specified graph. n \n", "26 Random local-effect game on a specified graph. n \n", "27 Two-player zero-sum game with random payoffs. 2 \n", "28 Classic Rock, Paper, Scissors game. 2 \n", "29 Shapley's original game; no stable equilibrium... 2 \n", "30 Inspection game where players choose from diff... 2 \n", "31 Players claim a value; the lowest claim wins a... n \n", "32 2x2 game of a specified type per Rapoport's cl... 2 \n", "33 Local-effect game where all edges share the sa... n \n", "34 Players choose concession times; payoffs depen... 2 " ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gbt.catalog.gamut_games()\n" ] }, { "cell_type": "markdown", "id": "gamut-bos-intro", "metadata": {}, "source": [ "## Classic two-player games\n", "\n", "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.\n", "\n", "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.\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "gamut-bos-gen", "metadata": {}, "outputs": [ { "data": { "text/html": [ "

Battle of the Sexes

\n", "
Player2
OperaFootball
Player1Opera3,30,0
Football0,03,3
\n" ], "text/plain": [ "Game(title='Battle of the Sexes')" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g_bos = gbt.catalog.generate_gamut(\n", " \"BattleOfTheSexes\",\n", " params={\n", " \"int_payoffs\": True,\n", " \"int_mult\": 1,\n", " \"normalize\": True,\n", " \"min_payoff\": 0,\n", " \"max_payoff\": 3\n", " },\n", " gamut_jar=\"~/Downloads/gamut.jar\",\n", ")\n", "g_bos.title = \"Battle of the Sexes\"\n", "for player in g_bos.players:\n", " for strategy, label in zip(player.strategies, [\"Opera\", \"Football\"], strict=True):\n", " strategy.label = label\n", "g_bos\n" ] }, { "cell_type": "markdown", "id": "gamut-bos-eqm-intro", "metadata": {}, "source": [ "Now let's compute all Nash equilibria using the linear complementarity method, which is well-suited to two-player games:\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "gamut-bos-eqm", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_bos = gbt.nash.lcp_solve(g_bos)\n", "len(result_bos.equilibria)\n" ] }, { "cell_type": "markdown", "id": "gamut-bos-interp", "metadata": {}, "source": [ "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:\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "37294505", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\left[\\left[1,0\\right],\\left[1,0\\right]\\right]$" ], "text/plain": [ "[[Rational(1, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1)]]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_bos.equilibria[0]" ] }, { "cell_type": "code", "execution_count": 6, "id": "293a5436", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\left[\\left[\\frac{1}{2},\\frac{1}{2}\\right],\\left[\\frac{1}{2},\\frac{1}{2}\\right]\\right]$" ], "text/plain": [ "[[Rational(1, 2), Rational(1, 2)], [Rational(1, 2), Rational(1, 2)]]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_bos.equilibria[1]" ] }, { "cell_type": "code", "execution_count": 7, "id": "d2e7a8e8", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\left[\\left[0,1\\right],\\left[0,1\\right]\\right]$" ], "text/plain": [ "[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_bos.equilibria[2]" ] }, { "cell_type": "markdown", "id": "gamut-norm-intro", "metadata": {}, "source": [ "## Payoff normalisation and integer payoffs\n", "\n", "By default, GAMUT draws payoffs uniformly from the range [-100, 100]. These global parameters let you rescale and discretise payoffs:\n", "\n", "| Parameter | Type | Effect |\n", "|---|---|---|\n", "| `normalize` | boolean flag | Enable rescaling to [`min_payoff`, `max_payoff`] |\n", "| `min_payoff` | number | Lower bound after normalisation |\n", "| `max_payoff` | number | Upper bound after normalisation |\n", "| `int_payoffs` | boolean flag | Round all payoffs to integers |\n", "| `int_mult` | boolean flag | Multiplier used before rounding when converting from double to integer payoffs |\n", "\n", "See the [GAMUT documentation](http://gamut.stanford.edu/) for more info on the available Global parameters.\n" ] }, { "cell_type": "markdown", "id": "gamut-random-intro", "metadata": {}, "source": [ "## Parameterised random normal-form games\n", "\n", "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.\n", "\n", "`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:\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "gamut-random-gen", "metadata": {}, "outputs": [ { "data": { "text/html": [ "

Random Game (2 players, 3x4)

\n", "
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
\n" ], "text/plain": [ "Game(title='Random Game (2 players, 3x4)')" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g_rand = gbt.catalog.generate_gamut(\n", " \"RandomGame\",\n", " params={\"players\": 2, \"actions\": [3, 3]},\n", " gamut_jar=\"~/Downloads/gamut.jar\",\n", ")\n", "g_rand.title = \"Random Game (2 players, 3x4)\"\n", "g_rand\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "gamut-random-eqm", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\left[\\left[1,0,0\\right],\\left[0,0,1\\right]\\right]$" ], "text/plain": [ "[[Rational(1, 1), Rational(0, 1), Rational(0, 1)], [Rational(0, 1), Rational(0, 1), Rational(1, 1)]]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gbt.nash.lcp_solve(g_rand).equilibria[0]\n" ] }, { "cell_type": "markdown", "id": "gamut-covariant-intro", "metadata": {}, "source": [ "## Covariant games\n", "\n", "`CovariantGame` generates two-player games in which the degree of alignment between players' interests is controlled by a covariance parameter `r`.\n", "\n", "- When `r = 1` the game is a common-payoff game: both players receive identical payoffs.\n", "- When `r = 0` payoffs are independent — equivalent to `RandomGame`.\n", "- As `r` approaches `-1` (the minimum for a two-player game) the game approaches a zero-sum game.\n", "\n", "Let's compare an equilibrium under high positive covariance (nearly a coordination game) with one under negative covariance (a more adversarial setting):\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "gamut-cov-pos", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\left[\\left[1,0,0\\right],\\left[1,0,0\\right]\\right]$" ], "text/plain": [ "[[Rational(1, 1), Rational(0, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1), Rational(0, 1)]]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g_cov_pos = gbt.catalog.generate_gamut(\n", " \"CovariantGame\",\n", " params={\"players\": 2, \"actions\": [3, 3], \"r\": 0.8},\n", " gamut_jar=\"~/Downloads/gamut.jar\",\n", ")\n", "g_cov_pos.title = \"Covariant Game (r=0.8)\"\n", "eqm_pos = gbt.nash.lcp_solve(g_cov_pos).equilibria[0]\n", "eqm_pos\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "gamut-cov-neg", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\left[\\left[1,0,0\\right],\\left[0,0,1\\right]\\right]$" ], "text/plain": [ "[[Rational(1, 1), Rational(0, 1), Rational(0, 1)], [Rational(0, 1), Rational(0, 1), Rational(1, 1)]]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g_cov_neg = gbt.catalog.generate_gamut(\n", " \"CovariantGame\",\n", " params={\"players\": 2, \"actions\": [3, 3], \"r\": -0.5},\n", " gamut_jar=\"~/Downloads/gamut.jar\",\n", ")\n", "g_cov_neg.title = \"Covariant Game (r=-0.5)\"\n", "eqm_neg = gbt.nash.lcp_solve(g_cov_neg).equilibria[0]\n", "eqm_neg\n" ] }, { "cell_type": "markdown", "id": "gamut-cov-interp", "metadata": {}, "source": [ "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.\n" ] }, { "cell_type": "markdown", "id": "gamut-multi-intro", "metadata": {}, "source": [ "## Multi-player games\n", "\n", "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.\n", "\n", "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:\n" ] }, { "cell_type": "code", "execution_count": 12, "id": "gamut-majority-gen", "metadata": {}, "outputs": [ { "data": { "text/html": [ "

Majority Voting (3 players, 3 candidates)

\n", "
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
\n" ], "text/plain": [ "Game(title='Majority Voting (3 players, 3 candidates)')" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g_mv = gbt.catalog.generate_gamut(\n", " \"MajorityVoting\",\n", " params={\n", " \"int_payoffs\": True,\n", " \"int_mult\": 1,\n", " \"players\": 3,\n", " \"actions\": 3\n", " },\n", " gamut_jar=\"~/Downloads/gamut.jar\",\n", ")\n", "g_mv.title = \"Majority Voting (3 players, 3 candidates)\"\n", "g_mv\n" ] }, { "cell_type": "code", "execution_count": 13, "id": "gamut-majority-eqm", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\left[\\left[1,0,0\\right],\\left[1,0,0\\right],\\left[1,0,0\\right]\\right]$" ], "text/plain": [ "[[Rational(1, 1), Rational(0, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1), Rational(0, 1)], [Rational(1, 1), Rational(0, 1), Rational(0, 1)]]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_mv = gbt.nash.enumpure_solve(g_mv)\n", "result_mv.equilibria[0]\n" ] } ], "metadata": { "kernelspec": { "display_name": "dtpure", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.13" }, "nbsphinx": { "execute": "never" } }, "nbformat": 4, "nbformat_minor": 5 }