What is Gambit ?

Gambitとは戦略型ゲームや展開型ゲームに関する分析を手助けしてくれるゲーム理論分析ライブラリーです。GUIにも優れており、コマンドラインを使わずに直感的にもゲーム理論分析が出来るという特徴も持ちます。
そして僕らPythonistaとしてはPythonのライブラリーとして使用する事が出来るということが最も大きなメリットとなります。Pythonのゲーム理論分析ライブラリは他にも少しだけ存在するようですが、おそらくこのGambitが一番整っていると思われます。
また、GambitのライセンスはGNU General Public Licenseのもとリリースされています。

How to install ?

Downloadページから最新版のgambitの.tar.gzファイルをダウンロードして展開する。

②ターミナルで展開したフォルダをディレクトリに変更し、

./configure
make
sudo make install

を入力する。

③ その後、

cd src/python
python setup.py build
sudo python setup.py install

を入力するとインストール完了。

④用意されているテストを試してみる。

cd src/python/gambit/tests
nosetests

なお、詳しい説明についてはGambitホームページ(英語)に書かれておりました。

Let's use Gambit !

Gambitのチュートリアルに沿って、実際に動かしてみる。


In [1]:
import gambit

展開型ゲーム(extensive game)

Game.new_tree()

Game.new_tree()で新しくゲームを生成する。このときのプレイヤー人数は0人。


In [2]:
g = gambit.Game.new_tree()

In [3]:
len(g.players)


Out[3]:
0

title

title属性によりゲームタイトルを入力出来る。


In [4]:
str(g)


Out[4]:
"<Game ''>"

In [5]:
g.title = "A simple poker example"
g.title


Out[5]:
'A simple poker example'

In [6]:
str(g)


Out[6]:
"<Game 'A simple poker example'>"

players

players属性によりプレイヤーの設定が出来ます。len()を使って人数を確認したり、add()でプレイヤーを増やすことが出来ます。


In [7]:
p = g.players.add("Alice")

In [8]:
p


Out[8]:
<Player [0] 'Alice' in game 'A simple poker example'>

それぞれのplayersはlabel属性を持ち、プレイヤーの名前を確認することが出来ます。


In [9]:
p.label


Out[9]:
'Alice'

In [10]:
len(g.players)


Out[10]:
1

Game.playersはpythonのリストのような扱い方もできます。


In [11]:
g.players[0]


Out[11]:
<Player [0] 'Alice' in game 'A simple poker example'>

In [12]:
g.players


Out[12]:
[<Player [0] 'Alice' in game 'A simple poker example'>]

戦略型ゲーム(strategic game)

ここでは2x2の囚人のジレンマを例として取り扱う。

Game.new_table()

新しいゲームを生成する。それぞれのプレイヤーにおける戦略の数の組を整数で構成されるリストとして引く。


In [13]:
g = gambit.Game.new_table([2,2])
g.title = "A prisoner's dilemma game"
g.players[0].label = "Alphonse"
g.players[1].label = "Gaston"
g


Out[13]:
NFG 1 R "A prisoner's dilemma game" { "Alphonse" "Gaston" }

{ { "1" "2" }
{ "1" "2" }
}
""

{
{ "" 0, 0 }
{ "" 0, 0 }
{ "" 0, 0 }
{ "" 0, 0 }
}
1 2 3 4 

strategies

playersが持つstrategiesはプレイヤーが持つ全ての戦略について並べてくれる。


In [14]:
g.players[0].strategies


Out[14]:
[<Strategy [0] '1' for player 'Alphonse' in game 'A prisoner's dilemma game'>, <Strategy [1] '2' for player 'Alphonse' in game 'A prisoner's dilemma game'>]

In [15]:
len(g.players[0].strategies)


Out[15]:
2

In [16]:
g.players[0].strategies[0].label = "Cooperate"
g.players[0].strategies[1].label = "Defect"

In [17]:
g.players[0].strategies


Out[17]:
[<Strategy [0] 'Cooperate' for player 'Alphonse' in game 'A prisoner's dilemma game'>, <Strategy [1] 'Defect' for player 'Alphonse' in game 'A prisoner's dilemma game'>]

利得表はarrayのような形でアクセスできます。
g[i, j]は最初のプレイヤーがi番目の戦略を、次のプレイヤーがj番目の戦略を取った時の利得となる。


In [18]:
g[0,0][0] = 8
g[0,0][1] = 8
g[0,1][0] = 2
g[0,1][1] = 10
g[1,0][0] = 10
g[1,1][1] = 2
g[1,0][1] = 2
g[1,1][0] = 5
g[1,1][1] = 5

In [19]:
g


Out[19]:
NFG 1 R "A prisoner's dilemma game" { "Alphonse" "Gaston" }

{ { "Cooperate" "Defect" }
{ "1" "2" }
}
""

{
{ "" 8, 8 }
{ "" 10, 2 }
{ "" 2, 10 }
{ "" 5, 5 }
}
1 2 3 4 

ゲームの読み込み(Reading a game from a file)

Game.read_game()

Gambitにもとから入っているサンプルファイルをGame.read_game()を使って読み込むことが出来る。
ためしにmixed_strategy.nfgを読み込んでみる。


In [20]:
g = gambit.Game.read_game("test_games/mixed_strategy.nfg")
g


Out[20]:
NFG 1 R "" { "Player 1" "Player 2" }

{ { "1" "2" "3" }
{ "1" "2" }
}
""

{
{ "" 1, 1 }
{ "" 0, 2 }
{ "" 0, 2 }
{ "" 1, 1 }
{ "" 0, 3 }
{ "" 2, 0 }
}
1 2 3 4 5 6 

contingencies

contingencies属性は純粋戦略のすべての組となっている。


In [21]:
list(g.contingencies)


Out[21]:
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]

In [22]:
for profile in g.contingencies:
    print profile, g[profile][0], g[profile][1]


[0, 0] 1 1
[0, 1] 1 1
[1, 0] 0 2
[1, 1] 0 3
[2, 0] 0 2
[2, 1] 2 0

混合戦略と行動戦略(Mixed strategy and behavior profiles)

混合戦略(Mixed strategy)

mixed_strategy_profile()

mixed_strategy_profile()によって各プレイヤーの純戦略における確率分布を表すことが出来る。


In [23]:
p = g.mixed_strategy_profile()

In [24]:
list(p)


Out[24]:
[0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.5, 0.5]

In [25]:
p[g.players[0]]


Out[25]:
[0.3333333333333333, 0.3333333333333333, 0.3333333333333333]

In [26]:
p[g.players[1].strategies[0]]


Out[26]:
0.5

payoff()

payoff()によってプレイヤーに対する期待利得を得ることが出来る。


In [27]:
p.payoff(g.players[0])


Out[27]:
0.6666666666666666

strategy_value()

strategy_value()によってプレイヤーが与えられた戦略を行うときの期待利得を得る。


In [28]:
p.strategy_value(g.players[0].strategies[2])


Out[28]:
1.0

行動戦略(behavior strategy)

行動戦略オブジェクトを使うためには、ゲームは展開型ゲームである必要がある。
おそらくtest_gamesの中で拡張子がnfgのものは戦略型、efgのものは展開型である。
ここでは、sample_extensive_game.efgを読み込む。
p "1" 1 1 "" { "1" "2" } 0は、おそらくpoint"1"における情報集合1の1番さんの行動プロファイル[1, 2]という意味で、 t "" 1 "" { 2, 3 }は、おそらくtop"1"における利得は[2, 3]という意味だと思われる。


In [29]:
g = gambit.Game.read_game("test_games/sample_extensive_game.efg")
g


Out[29]:
EFG 2 R "Untitled Extensive Game" { "Player 1" "Player 2" }
""

p "1" 1 1 "" { "1" "2" } 0
p "2" 2 1 "" { "1" "2" } 0
t "" 1 "" { 2, 3 }
t "" 1 "" { 2, 3 }
p "3" 2 2 "" { "1" "2" } 0
t "" 2 "" { 4, 5 }
t "" 3 "" { 6, 7 }

mixed_behavior_profile()

それぞれの情報集合(information set)における行動の確率分布を表す。
行動プロファイルの初期値はそれぞれの情報集合において一様分布で導かれる。


In [30]:
p = g.mixed_behavior_profile()

In [31]:
list(p)


Out[31]:
[0.5, 0.5, 0.5, 0.5, 0.5, 0.5]

mixed_strategy_profile()のときと扱い方はほとんど変わらないが、infosetsが増えたところを注意して扱う必要がある。


In [32]:
p[g.players[0]]


Out[32]:
[[0.5, 0.5]]

In [33]:
p[g.players[0].infosets[0]]


Out[33]:
[0.5, 0.5]

In [34]:
p[g.players[0].infosets[0].actions[0]]


Out[34]:
0.5

ナッシュ均衡

戦略型ゲーム

mixed_strategy.nfgのゲームを例に扱う。
Player1は戦略0を確率1で行うが、Player2は戦略0を確率0.5以上で混合戦略をとる。


In [35]:
g = gambit.Game.read_game("test_games/mixed_strategy.nfg")
g


Out[35]:
NFG 1 R "" { "Player 1" "Player 2" }

{ { "1" "2" "3" }
{ "1" "2" }
}
""

{
{ "" 1, 1 }
{ "" 0, 2 }
{ "" 0, 2 }
{ "" 1, 1 }
{ "" 0, 3 }
{ "" 2, 0 }
}
1 2 3 4 5 6 

nash.ExternalEnumPureSolver()

純戦略における解を返す。


In [36]:
solver = gambit.nash.ExternalEnumPureSolver()
solver.solve(g)


Out[36]:
[<NashProfile for '': [[Fraction(1, 1), Fraction(0, 1), Fraction(0, 1)], [Fraction(1, 1), Fraction(0, 1)]]>]

nash.ExternalEnumMixedSolver()

混合戦略における解を返す。
この場合は解となる均衡点の組の端点である2つの均衡点を返している。


In [37]:
solver = gambit.nash.ExternalEnumMixedSolver()
solver.solve(g)


Out[37]:
[<NashProfile for '': [[1.0, 0.0, 0.0], [1.0, 0.0]]>,
 <NashProfile for '': [[1.0, 0.0, 0.0], [0.5, 0.5]]>]

In [38]:
solver = gambit.nash.ExternalLogitSolver()
solver.solve(g)


Out[38]:
[<NashProfile for '': [[0.9999999999788117, 0.0, 2.1188337212738607e-11], [0.500011410054953, 0.499988589945047]]>]

展開型ゲーム

sample_extensive_game.efgを例として扱う。


In [39]:
g = gambit.Game.read_game("test_games/sample_extensive_game.efg")
g


Out[39]:
EFG 2 R "Untitled Extensive Game" { "Player 1" "Player 2" }
""

p "1" 1 1 "" { "1" "2" } 0
p "2" 2 1 "" { "1" "2" } 0
t "" 1 "" { 2, 3 }
t "" 1 "" { 2, 3 }
p "3" 2 2 "" { "1" "2" } 0
t "" 2 "" { 4, 5 }
t "" 3 "" { 6, 7 }

In [40]:
solver = gambit.nash.ExternalLCPSolver()
solver.solve(g)


Out[40]:
[<NashProfile for 'Untitled Extensive Game': [[[0.0, 1.0]], [[0.0, 1.0], [0.0, 1.0]]]>]

In [41]:
solver.solve(g, use_strategic=True)
solver.solve(g)


Out[41]:
[<NashProfile for 'Untitled Extensive Game': [[[0.0, 1.0]], [[0.0, 1.0], [0.0, 1.0]]]>]