noregret 0.0.0.dev6__tar.gz → 0.0.0.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/PKG-INFO +6 -6
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/README.rst +5 -5
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/__init__.py +8 -6
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/__init__.py +6 -4
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/black_box.py +2 -2
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/extensive_form/__init__.py +2 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/extensive_form/games.py +131 -1
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/__init__.py +2 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/games.py +16 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/solvers/regret_minimization.py +25 -15
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/tests/test_games.py +13 -3
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/tests/test_linear_programming.py +2 -2
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/tests/test_regret_minimization.py +27 -5
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret.egg-info/PKG-INFO +6 -6
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret.egg-info/SOURCES.txt +0 -1
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/setup.py +1 -1
- noregret-0.0.0.dev6/noregret/games/utilities.py +0 -141
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/LICENSE +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/games.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/multilinear.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/assurance-game.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/battle-of-the-sexes.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/chicken.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/gift-exchange-game.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/matching-pennies.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/prisoners-dilemma.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/pure-coordination.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/rock-paper-scissors-plus.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/rock-paper-scissors.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/rock-paper-superscissors.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/stag-hunt.json +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/kernels.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/regret_minimizers/__init__.py +4 -4
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/regret_minimizers/probability_simplices.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/regret_minimizers/regret_minimizers.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/regret_minimizers/sequence_form_polytopes.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/sequence_form_polytopes.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/solvers/__init__.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/solvers/linear_programming.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/tests/__init__.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/tests/test_sequence_form_polytopes.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/utilities.py +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret.egg-info/dependency_links.txt +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret.egg-info/requires.txt +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret.egg-info/top_level.txt +0 -0
- {noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: noregret
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev7
|
|
4
4
|
Summary: No-regret learning dynamics
|
|
5
5
|
Home-page: https://github.com/uoftcprg/noregret
|
|
6
6
|
Author: Universal, Open, Free, and Transparent Computer Poker Research Group
|
|
@@ -94,8 +94,8 @@ The code snippet below demonstrates how one can solve games via regret minimizat
|
|
|
94
94
|
KERNEL = nr.FloatingPointKernel()
|
|
95
95
|
GAMES = {
|
|
96
96
|
'Rock paper superscissors': nr.to_efg(nr.RockPaperSuperscissors(KERNEL)),
|
|
97
|
-
'Kuhn poker': nr.to_efg(KERNEL, nr.
|
|
98
|
-
'Leduc poker': nr.to_efg(KERNEL, nr.
|
|
97
|
+
'Kuhn poker': nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
98
|
+
'Leduc poker': nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
99
99
|
}
|
|
100
100
|
PARAMETERS = {
|
|
101
101
|
'CFR': (nr.CFR, False, False),
|
|
@@ -180,7 +180,7 @@ The code snippet below demonstrates how one can solve games while leveraging GPU
|
|
|
180
180
|
import noregret as nr
|
|
181
181
|
|
|
182
182
|
KERNEL = nr.CUDAKernel()
|
|
183
|
-
GAME = nr.to_efg(KERNEL, nr.
|
|
183
|
+
GAME = nr.to_efg(KERNEL, nr.open_spiel_game('liars_dice'))
|
|
184
184
|
PARAMETERS = nr.CFR, True, False
|
|
185
185
|
|
|
186
186
|
|
|
@@ -220,8 +220,8 @@ The code snippet below demonstrates how one can solve games via linear programmi
|
|
|
220
220
|
KERNEL = nr.FloatingPointKernel()
|
|
221
221
|
GAMES = {
|
|
222
222
|
'Rock paper superscissors': nr.RockPaperSuperscissors(KERNEL),
|
|
223
|
-
'Kuhn poker': nr.to_efg(KERNEL, nr.
|
|
224
|
-
'Leduc poker': nr.to_efg(KERNEL, nr.
|
|
223
|
+
'Kuhn poker': nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
224
|
+
'Leduc poker': nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
|
|
@@ -44,8 +44,8 @@ The code snippet below demonstrates how one can solve games via regret minimizat
|
|
|
44
44
|
KERNEL = nr.FloatingPointKernel()
|
|
45
45
|
GAMES = {
|
|
46
46
|
'Rock paper superscissors': nr.to_efg(nr.RockPaperSuperscissors(KERNEL)),
|
|
47
|
-
'Kuhn poker': nr.to_efg(KERNEL, nr.
|
|
48
|
-
'Leduc poker': nr.to_efg(KERNEL, nr.
|
|
47
|
+
'Kuhn poker': nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
48
|
+
'Leduc poker': nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
49
49
|
}
|
|
50
50
|
PARAMETERS = {
|
|
51
51
|
'CFR': (nr.CFR, False, False),
|
|
@@ -130,7 +130,7 @@ The code snippet below demonstrates how one can solve games while leveraging GPU
|
|
|
130
130
|
import noregret as nr
|
|
131
131
|
|
|
132
132
|
KERNEL = nr.CUDAKernel()
|
|
133
|
-
GAME = nr.to_efg(KERNEL, nr.
|
|
133
|
+
GAME = nr.to_efg(KERNEL, nr.open_spiel_game('liars_dice'))
|
|
134
134
|
PARAMETERS = nr.CFR, True, False
|
|
135
135
|
|
|
136
136
|
|
|
@@ -170,8 +170,8 @@ The code snippet below demonstrates how one can solve games via linear programmi
|
|
|
170
170
|
KERNEL = nr.FloatingPointKernel()
|
|
171
171
|
GAMES = {
|
|
172
172
|
'Rock paper superscissors': nr.RockPaperSuperscissors(KERNEL),
|
|
173
|
-
'Kuhn poker': nr.to_efg(KERNEL, nr.
|
|
174
|
-
'Leduc poker': nr.to_efg(KERNEL, nr.
|
|
173
|
+
'Kuhn poker': nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
174
|
+
'Leduc poker': nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
|
|
@@ -5,19 +5,20 @@ from noregret.games import (
|
|
|
5
5
|
BlackBoxGame,
|
|
6
6
|
Chicken,
|
|
7
7
|
ExtensiveFormGame,
|
|
8
|
-
from_open_spiel,
|
|
9
8
|
Game,
|
|
10
9
|
GiftExchangeGame,
|
|
11
10
|
MatchingPennies,
|
|
11
|
+
matrix_game,
|
|
12
12
|
MultilinearGame,
|
|
13
13
|
NormalFormGame,
|
|
14
|
+
open_spiel_game,
|
|
14
15
|
PrisonersDilemma,
|
|
15
16
|
PureCoordination,
|
|
16
17
|
RockPaperScissors,
|
|
17
18
|
RockPaperScissorsPlus,
|
|
18
19
|
RockPaperSuperscissors,
|
|
19
20
|
StagHunt,
|
|
20
|
-
|
|
21
|
+
to_extensive_form_game,
|
|
21
22
|
TwoPlayerExtensiveFormGame,
|
|
22
23
|
TwoPlayerGame,
|
|
23
24
|
TwoPlayerMultilinearGame,
|
|
@@ -109,8 +110,8 @@ rm = regret_minimization
|
|
|
109
110
|
"""Alias for :func:`noregret.regret_minimization`."""
|
|
110
111
|
symmetric_rm = symmetric_regret_minimization
|
|
111
112
|
"""Alias for :func:`noregret.symmetric_regret_minimization`."""
|
|
112
|
-
to_efg =
|
|
113
|
-
"""Alias for :func:`noregret.
|
|
113
|
+
to_efg = to_extensive_form_game
|
|
114
|
+
"""Alias for :func:`noregret.to_extensive_form_game`."""
|
|
114
115
|
|
|
115
116
|
__all__ = (
|
|
116
117
|
'AssuranceGame',
|
|
@@ -138,7 +139,7 @@ __all__ = (
|
|
|
138
139
|
'ExtensiveFormGame',
|
|
139
140
|
'FloatingPointKernel',
|
|
140
141
|
'FollowTheRegularizedLeader',
|
|
141
|
-
'
|
|
142
|
+
'open_spiel_game',
|
|
142
143
|
'FTRL',
|
|
143
144
|
'Game',
|
|
144
145
|
'GiftExchangeGame',
|
|
@@ -148,6 +149,7 @@ __all__ = (
|
|
|
148
149
|
'linear_programming',
|
|
149
150
|
'lp',
|
|
150
151
|
'MatchingPennies',
|
|
152
|
+
'matrix_game',
|
|
151
153
|
'MD',
|
|
152
154
|
'MirrorDescent',
|
|
153
155
|
'MultilinearGame',
|
|
@@ -181,7 +183,7 @@ __all__ = (
|
|
|
181
183
|
'symmetric_regret_minimization',
|
|
182
184
|
'symmetric_rm',
|
|
183
185
|
'to_efg',
|
|
184
|
-
'
|
|
186
|
+
'to_extensive_form_game',
|
|
185
187
|
'tuple_or_none',
|
|
186
188
|
'TwoPlayerExtensiveFormGame',
|
|
187
189
|
'TwoPlayerGame',
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""Module for games."""
|
|
2
|
-
from noregret.games.black_box import BlackBoxGame,
|
|
2
|
+
from noregret.games.black_box import BlackBoxGame, open_spiel_game
|
|
3
3
|
from noregret.games.extensive_form import (
|
|
4
4
|
ExtensiveFormGame,
|
|
5
|
+
to_extensive_form_game,
|
|
5
6
|
TwoPlayerExtensiveFormGame,
|
|
6
7
|
TwoPlayerZeroSumExtensiveFormGame,
|
|
7
8
|
)
|
|
@@ -17,6 +18,7 @@ from noregret.games.normal_form import (
|
|
|
17
18
|
Chicken,
|
|
18
19
|
GiftExchangeGame,
|
|
19
20
|
MatchingPennies,
|
|
21
|
+
matrix_game,
|
|
20
22
|
NormalFormGame,
|
|
21
23
|
PrisonersDilemma,
|
|
22
24
|
PureCoordination,
|
|
@@ -27,7 +29,6 @@ from noregret.games.normal_form import (
|
|
|
27
29
|
TwoPlayerNormalFormGame,
|
|
28
30
|
TwoPlayerZeroSumNormalFormGame,
|
|
29
31
|
)
|
|
30
|
-
from noregret.games.utilities import to_extensive_form
|
|
31
32
|
|
|
32
33
|
__all__ = (
|
|
33
34
|
'AssuranceGame',
|
|
@@ -35,19 +36,20 @@ __all__ = (
|
|
|
35
36
|
'BlackBoxGame',
|
|
36
37
|
'Chicken',
|
|
37
38
|
'ExtensiveFormGame',
|
|
38
|
-
'from_open_spiel',
|
|
39
39
|
'Game',
|
|
40
40
|
'GiftExchangeGame',
|
|
41
41
|
'MatchingPennies',
|
|
42
|
+
'matrix_game',
|
|
42
43
|
'MultilinearGame',
|
|
43
44
|
'NormalFormGame',
|
|
45
|
+
'open_spiel_game',
|
|
44
46
|
'PrisonersDilemma',
|
|
45
47
|
'PureCoordination',
|
|
46
48
|
'RockPaperScissors',
|
|
47
49
|
'RockPaperScissorsPlus',
|
|
48
50
|
'RockPaperSuperscissors',
|
|
49
51
|
'StagHunt',
|
|
50
|
-
'
|
|
52
|
+
'to_extensive_form_game',
|
|
51
53
|
'TwoPlayerExtensiveFormGame',
|
|
52
54
|
'TwoPlayerGame',
|
|
53
55
|
'TwoPlayerMultilinearGame',
|
|
@@ -171,7 +171,7 @@ class _OpenSpielBlackBoxGame(BlackBoxGame):
|
|
|
171
171
|
def player(self, node):
|
|
172
172
|
i = node.current_player()
|
|
173
173
|
|
|
174
|
-
return None if i
|
|
174
|
+
return None if i < 0 else i
|
|
175
175
|
|
|
176
176
|
def utility(self, node, player):
|
|
177
177
|
return node.player_reward(player)
|
|
@@ -189,7 +189,7 @@ class _OpenSpielBlackBoxGame(BlackBoxGame):
|
|
|
189
189
|
return [p for _, p in node.chance_outcomes()]
|
|
190
190
|
|
|
191
191
|
|
|
192
|
-
def
|
|
192
|
+
def open_spiel_game(game):
|
|
193
193
|
"""Load a game from OpenSpiel.
|
|
194
194
|
|
|
195
195
|
:param game: Game in OpenSpiel.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"""Module for extensive-form games (EFGs)."""
|
|
2
2
|
from noregret.games.extensive_form.games import (
|
|
3
3
|
ExtensiveFormGame,
|
|
4
|
+
to_extensive_form_game,
|
|
4
5
|
TwoPlayerExtensiveFormGame,
|
|
5
6
|
TwoPlayerZeroSumExtensiveFormGame,
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
__all__ = (
|
|
9
10
|
'ExtensiveFormGame',
|
|
11
|
+
'to_extensive_form_game',
|
|
10
12
|
'TwoPlayerExtensiveFormGame',
|
|
11
13
|
'TwoPlayerZeroSumExtensiveFormGame',
|
|
12
14
|
)
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
"""Module for extensive-form games (EFGs)."""
|
|
2
|
+
from collections import defaultdict
|
|
2
3
|
from dataclasses import dataclass
|
|
4
|
+
from functools import partial, singledispatch
|
|
3
5
|
from io import BytesIO
|
|
6
|
+
from itertools import starmap
|
|
4
7
|
|
|
5
8
|
from ordered_set import OrderedSet
|
|
6
9
|
from orjson import dumps, loads
|
|
7
|
-
from scipy.sparse import load_npz, save_npz
|
|
10
|
+
from scipy.sparse import lil_array, load_npz, save_npz
|
|
8
11
|
|
|
12
|
+
from noregret.games.black_box import BlackBoxGame
|
|
13
|
+
from noregret.games.games import Game
|
|
9
14
|
from noregret.games.multilinear import (
|
|
10
15
|
MultilinearGame,
|
|
11
16
|
TwoPlayerMultilinearGame,
|
|
12
17
|
TwoPlayerZeroSumMultilinearGame,
|
|
13
18
|
)
|
|
19
|
+
from noregret.games.normal_form.games import (
|
|
20
|
+
NormalFormGame,
|
|
21
|
+
TwoPlayerNormalFormGame,
|
|
22
|
+
TwoPlayerZeroSumNormalFormGame,
|
|
23
|
+
)
|
|
14
24
|
from noregret.kernels import Serializable
|
|
15
25
|
from noregret.sequence_form_polytopes import SequenceFormPolytope
|
|
16
26
|
from noregret.utilities import tuple_or_none
|
|
@@ -143,3 +153,123 @@ class TwoPlayerZeroSumExtensiveFormGame(
|
|
|
143
153
|
neg_v = self.column_sequence_form_polytope.worst_response_value(neg_v)
|
|
144
154
|
|
|
145
155
|
return u, neg_v
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _nfg2efg(kernel, game, decision_points='p{}'.format):
|
|
159
|
+
np = kernel.numpy
|
|
160
|
+
scipy = kernel.scipy
|
|
161
|
+
dtype = kernel.data_type
|
|
162
|
+
|
|
163
|
+
if isinstance(game, TwoPlayerZeroSumNormalFormGame):
|
|
164
|
+
type_ = TwoPlayerZeroSumExtensiveFormGame
|
|
165
|
+
elif isinstance(game, TwoPlayerNormalFormGame):
|
|
166
|
+
type_ = TwoPlayerExtensiveFormGame
|
|
167
|
+
else:
|
|
168
|
+
type_ = ExtensiveFormGame
|
|
169
|
+
|
|
170
|
+
d = game.dimensions
|
|
171
|
+
|
|
172
|
+
if isinstance(game, TwoPlayerZeroSumNormalFormGame):
|
|
173
|
+
payoffs = np.zeros(tuple(n + 1 for n in d), dtype)
|
|
174
|
+
payoffs[tuple(slice(1, None) for _ in d)] = game.payoffs
|
|
175
|
+
else:
|
|
176
|
+
payoffs = np.zeros((game.player_count, *(n + 1 for n in d)), dtype)
|
|
177
|
+
payoffs[:, *(slice(1, None) for _ in d)] = game.payoffs
|
|
178
|
+
|
|
179
|
+
payoffs = scipy.sparse.csr_array(payoffs)
|
|
180
|
+
sfps = []
|
|
181
|
+
|
|
182
|
+
for i, A_j in enumerate(game.actions):
|
|
183
|
+
j = decision_points(i)
|
|
184
|
+
sfp = SequenceFormPolytope(kernel, {j: A_j}, {j: None})
|
|
185
|
+
|
|
186
|
+
sfps.append(sfp)
|
|
187
|
+
|
|
188
|
+
sfps = tuple(sfps)
|
|
189
|
+
|
|
190
|
+
return type_(kernel, payoffs, sfps)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _bbg2efg(kernel, game):
|
|
194
|
+
scipy = kernel.scipy
|
|
195
|
+
dtype = kernel.data_type
|
|
196
|
+
P = range(game.player_count)
|
|
197
|
+
A_js = [defaultdict(OrderedSet) for _ in P]
|
|
198
|
+
p_js = [{} for _ in P]
|
|
199
|
+
raw_payoffs = [defaultdict(int) for _ in P]
|
|
200
|
+
|
|
201
|
+
def dfs(h, p, seqs, us):
|
|
202
|
+
A_j, h_primes = game.actions_and_children(h)
|
|
203
|
+
i = game.player(h)
|
|
204
|
+
us = us.copy()
|
|
205
|
+
|
|
206
|
+
for i_prime, v in enumerate(game.utilities(h)):
|
|
207
|
+
us[i_prime] += v
|
|
208
|
+
|
|
209
|
+
if not A_j:
|
|
210
|
+
seqs = tuple(seqs)
|
|
211
|
+
|
|
212
|
+
for i_prime, u in enumerate(us):
|
|
213
|
+
raw_payoffs[i_prime][seqs] += p * u
|
|
214
|
+
elif i is None:
|
|
215
|
+
p_primes = game.chance_probabilities(h)
|
|
216
|
+
|
|
217
|
+
for h_prime, p_prime in zip(h_primes, p_primes):
|
|
218
|
+
dfs(h_prime, p_prime * p, seqs, us)
|
|
219
|
+
else:
|
|
220
|
+
j = game.information_set(h)
|
|
221
|
+
p_j = seqs[i]
|
|
222
|
+
p_js[i][j] = p_j
|
|
223
|
+
|
|
224
|
+
for a, h_prime in zip(A_j, h_primes):
|
|
225
|
+
next_seqs = seqs.copy()
|
|
226
|
+
next_seqs[i] = j, a
|
|
227
|
+
|
|
228
|
+
A_js[i][j].add(a)
|
|
229
|
+
dfs(h_prime, p, next_seqs, us)
|
|
230
|
+
|
|
231
|
+
dfs(game.root_node, 1, [None for _ in P], [0 for _ in P])
|
|
232
|
+
|
|
233
|
+
SFP = partial(SequenceFormPolytope, kernel)
|
|
234
|
+
sfps = tuple(starmap(SFP, zip(A_js, p_js)))
|
|
235
|
+
dimensions = tuple(sfp.column_count for sfp in sfps)
|
|
236
|
+
|
|
237
|
+
if game.is_two_player and game.is_zero_sum:
|
|
238
|
+
type_ = TwoPlayerZeroSumExtensiveFormGame
|
|
239
|
+
payoffs = lil_array(dimensions, dtype=dtype)
|
|
240
|
+
|
|
241
|
+
for seqs, u in raw_payoffs[0].items():
|
|
242
|
+
indices = []
|
|
243
|
+
|
|
244
|
+
for sfp, seq in zip(sfps, seqs):
|
|
245
|
+
indices.append(sfp.column(seq))
|
|
246
|
+
|
|
247
|
+
payoffs[tuple(indices)] = u
|
|
248
|
+
|
|
249
|
+
payoffs = scipy.sparse.csr_array(payoffs)
|
|
250
|
+
else:
|
|
251
|
+
raise NotImplementedError
|
|
252
|
+
|
|
253
|
+
return type_(kernel, payoffs, sfps)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
@singledispatch
|
|
257
|
+
def to_extensive_form_game(kernel, game):
|
|
258
|
+
"""Convert a given game to an extensive-form game.
|
|
259
|
+
|
|
260
|
+
:param game: Game.
|
|
261
|
+
:return: Extensive-form game.
|
|
262
|
+
"""
|
|
263
|
+
if isinstance(game, NormalFormGame):
|
|
264
|
+
game = _nfg2efg(kernel, game)
|
|
265
|
+
elif isinstance(game, BlackBoxGame):
|
|
266
|
+
game = _bbg2efg(kernel, game)
|
|
267
|
+
else:
|
|
268
|
+
raise ValueError('unknown game')
|
|
269
|
+
|
|
270
|
+
return game
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@to_extensive_form_game.register
|
|
274
|
+
def _(game: Game):
|
|
275
|
+
return to_extensive_form_game(game.kernel, game)
|
|
@@ -5,6 +5,7 @@ from noregret.games.normal_form.games import (
|
|
|
5
5
|
Chicken,
|
|
6
6
|
GiftExchangeGame,
|
|
7
7
|
MatchingPennies,
|
|
8
|
+
matrix_game,
|
|
8
9
|
NormalFormGame,
|
|
9
10
|
PrisonersDilemma,
|
|
10
11
|
PureCoordination,
|
|
@@ -22,6 +23,7 @@ __all__ = (
|
|
|
22
23
|
'Chicken',
|
|
23
24
|
'GiftExchangeGame',
|
|
24
25
|
'MatchingPennies',
|
|
26
|
+
'matrix_game',
|
|
25
27
|
'NormalFormGame',
|
|
26
28
|
'PrisonersDilemma',
|
|
27
29
|
'PureCoordination',
|
|
@@ -115,6 +115,22 @@ class TwoPlayerZeroSumNormalFormGame(
|
|
|
115
115
|
return u, neg_v
|
|
116
116
|
|
|
117
117
|
|
|
118
|
+
def matrix_game(kernel, matrix):
|
|
119
|
+
"""Create a matrix game.
|
|
120
|
+
|
|
121
|
+
:param kernel: Kernel.
|
|
122
|
+
:param matrix: Matrix.
|
|
123
|
+
:return: Game.
|
|
124
|
+
"""
|
|
125
|
+
R, C = matrix.shape
|
|
126
|
+
actions = (
|
|
127
|
+
OrderedSet(map('r{}'.format, range(R))),
|
|
128
|
+
OrderedSet(map('c{}'.format, range(C))),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
return TwoPlayerZeroSumNormalFormGame(kernel, matrix, actions)
|
|
132
|
+
|
|
133
|
+
|
|
118
134
|
def _2p_nfg(name, kernel):
|
|
119
135
|
with open(Path(__file__).parent / f'{name}.json', 'rb') as file:
|
|
120
136
|
return TwoPlayerNormalFormGame.loads(kernel, file.read())
|
|
@@ -62,27 +62,32 @@ def regret_minimization(
|
|
|
62
62
|
for R in regret_minimizers:
|
|
63
63
|
s.append(R.output(prediction))
|
|
64
64
|
|
|
65
|
-
for
|
|
65
|
+
for t in iterations:
|
|
66
66
|
if alternation:
|
|
67
|
-
for
|
|
68
|
-
R.observe(game.utility(
|
|
67
|
+
for i, R in enumerate(regret_minimizers):
|
|
68
|
+
R.observe(game.utility(i, *s[:i], *s[i + 1:]))
|
|
69
69
|
|
|
70
|
-
s[
|
|
70
|
+
s[i] = R.output(prediction)
|
|
71
71
|
else:
|
|
72
72
|
U = game.utilities(*s)
|
|
73
73
|
|
|
74
|
-
for
|
|
74
|
+
for i, (R, u) in enumerate(zip(regret_minimizers, U)):
|
|
75
75
|
R.observe(u)
|
|
76
76
|
|
|
77
|
-
s[
|
|
77
|
+
s[i] = R.output(prediction)
|
|
78
78
|
|
|
79
|
-
if not checkpoints or
|
|
79
|
+
if not checkpoints or t in checkpoints:
|
|
80
80
|
if update is not None:
|
|
81
|
-
update()
|
|
81
|
+
status = update()
|
|
82
|
+
else:
|
|
83
|
+
status = False
|
|
82
84
|
|
|
83
85
|
if (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
status
|
|
87
|
+
or (
|
|
88
|
+
target_exploitability is not None
|
|
89
|
+
and exploitability() < target_exploitability
|
|
90
|
+
)
|
|
86
91
|
):
|
|
87
92
|
break
|
|
88
93
|
|
|
@@ -138,18 +143,23 @@ def symmetric_regret_minimization(
|
|
|
138
143
|
|
|
139
144
|
s_neg_1 = [R.output(prediction)] * (game.player_count - 1)
|
|
140
145
|
|
|
141
|
-
for
|
|
146
|
+
for t in iterations:
|
|
142
147
|
R.observe(game.utility(0, *s_neg_1))
|
|
143
148
|
|
|
144
149
|
s_neg_1 = [R.output(prediction)] * (game.player_count - 1)
|
|
145
150
|
|
|
146
|
-
if not checkpoints or
|
|
151
|
+
if not checkpoints or t in checkpoints:
|
|
147
152
|
if update is not None:
|
|
148
|
-
update()
|
|
153
|
+
status = update()
|
|
154
|
+
else:
|
|
155
|
+
status = False
|
|
149
156
|
|
|
150
157
|
if (
|
|
151
|
-
|
|
152
|
-
|
|
158
|
+
status
|
|
159
|
+
or (
|
|
160
|
+
target_exploitability is not None
|
|
161
|
+
and exploitability() < target_exploitability
|
|
162
|
+
)
|
|
153
163
|
):
|
|
154
164
|
break
|
|
155
165
|
|
|
@@ -85,6 +85,16 @@ class NormalFormGameTestCase(GameTestCaseMixin, TestCase):
|
|
|
85
85
|
self.assertTrue((game.payoffs == game2.payoffs).all())
|
|
86
86
|
self.assertEqual(game.actions, game2.actions)
|
|
87
87
|
|
|
88
|
+
def test_matrix_game(self):
|
|
89
|
+
np = self.KERNEL.numpy
|
|
90
|
+
dtype = self.KERNEL.data_type
|
|
91
|
+
A = np.array([[3, 0, -3], [0, 3, -4], [0, 0, 1]], dtype)
|
|
92
|
+
game = nr.matrix_game(self.KERNEL, A)
|
|
93
|
+
x, y = nr.linear_programming(game)
|
|
94
|
+
v = game.expected_row_utility(x, y)
|
|
95
|
+
|
|
96
|
+
self.assertAlmostEqual(v, 0.25)
|
|
97
|
+
|
|
88
98
|
|
|
89
99
|
class ExtensiveFormGameTestCase(GameTestCaseMixin, TestCase):
|
|
90
100
|
KERNEL = nr.FloatingPointKernel()
|
|
@@ -93,8 +103,8 @@ class ExtensiveFormGameTestCase(GameTestCaseMixin, TestCase):
|
|
|
93
103
|
nr.to_efg(nr.RockPaperScissors(KERNEL)),
|
|
94
104
|
nr.to_efg(nr.RockPaperScissorsPlus(KERNEL)),
|
|
95
105
|
nr.to_efg(nr.RockPaperSuperscissors(KERNEL)),
|
|
96
|
-
nr.to_efg(KERNEL, nr.
|
|
97
|
-
nr.to_efg(KERNEL, nr.
|
|
106
|
+
nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
107
|
+
nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
98
108
|
)
|
|
99
109
|
|
|
100
110
|
def uniform_strategy_profile(self, game):
|
|
@@ -134,7 +144,7 @@ class ExtensiveFormGameTestCase(GameTestCaseMixin, TestCase):
|
|
|
134
144
|
|
|
135
145
|
|
|
136
146
|
class BlackBoxGameTestCase(TestCase):
|
|
137
|
-
GAMES = nr.
|
|
147
|
+
GAMES = nr.open_spiel_game('kuhn_poker'), nr.open_spiel_game('leduc_poker')
|
|
138
148
|
|
|
139
149
|
def test_actions_and_children(self):
|
|
140
150
|
for game in self.GAMES:
|
|
@@ -14,8 +14,8 @@ class LinearProgrammingTestCase(TestCase):
|
|
|
14
14
|
(nr.to_efg(nr.RockPaperScissors(KERNEL)), 0),
|
|
15
15
|
(nr.to_efg(nr.RockPaperScissorsPlus(KERNEL)), 0),
|
|
16
16
|
(nr.to_efg(nr.RockPaperSuperscissors(KERNEL)), 0),
|
|
17
|
-
(nr.to_efg(KERNEL, nr.
|
|
18
|
-
(nr.to_efg(KERNEL, nr.
|
|
17
|
+
(nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')), -1 / 18),
|
|
18
|
+
(nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')), -0.08560642408),
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
def test_linear_programming(self):
|
|
@@ -110,8 +110,8 @@ class SequenceFormPolytopeRegretMinimizationTestCase(TestCase):
|
|
|
110
110
|
(nr.to_efg(nr.RockPaperScissors(KERNEL)), 0),
|
|
111
111
|
(nr.to_efg(nr.RockPaperScissorsPlus(KERNEL)), 0),
|
|
112
112
|
(nr.to_efg(nr.RockPaperSuperscissors(KERNEL)), 0),
|
|
113
|
-
(nr.to_efg(KERNEL, nr.
|
|
114
|
-
(nr.to_efg(KERNEL, nr.
|
|
113
|
+
(nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')), -1 / 18),
|
|
114
|
+
(nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')), -0.08560642408),
|
|
115
115
|
)
|
|
116
116
|
REGRET_MINIMIZION_PARAMETERS = (
|
|
117
117
|
(partial(nr.CFR, KERNEL), False, False),
|
|
@@ -157,10 +157,10 @@ class SequenceFormPolytopeRegretMinimization2TestCase(TestCase):
|
|
|
157
157
|
nr.to_efg(nr.RockPaperScissors(KERNEL)),
|
|
158
158
|
nr.to_efg(nr.RockPaperScissorsPlus(KERNEL)),
|
|
159
159
|
nr.to_efg(nr.RockPaperSuperscissors(KERNEL)),
|
|
160
|
-
nr.to_efg(KERNEL, nr.
|
|
161
|
-
nr.to_efg(KERNEL, nr.
|
|
160
|
+
nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
161
|
+
nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
162
162
|
)
|
|
163
|
-
PLACES =
|
|
163
|
+
PLACES = 2
|
|
164
164
|
|
|
165
165
|
def test_equivalence(self):
|
|
166
166
|
for game in self.GAMES:
|
|
@@ -186,6 +186,28 @@ class SequenceFormPolytopeRegretMinimization2TestCase(TestCase):
|
|
|
186
186
|
self.assertAlmostEqual(e, e2, self.PLACES)
|
|
187
187
|
self.assertAlmostEqual(v, v2, self.PLACES)
|
|
188
188
|
|
|
189
|
+
x_bar, y_bar = nr.regret_minimization(
|
|
190
|
+
game,
|
|
191
|
+
nr.CFR(self.KERNEL, game.row_sequence_form_polytope),
|
|
192
|
+
nr.CFR(self.KERNEL, game.column_sequence_form_polytope),
|
|
193
|
+
prediction=True,
|
|
194
|
+
progress_bar=False,
|
|
195
|
+
)
|
|
196
|
+
e = game.exploitability(x_bar, y_bar)
|
|
197
|
+
v = game.expected_row_utility(x_bar, y_bar)
|
|
198
|
+
x_bar2, y_bar2 = nr.regret_minimization(
|
|
199
|
+
game,
|
|
200
|
+
nr.CFR2(self.KERNEL, game.row_sequence_form_polytope),
|
|
201
|
+
nr.CFR2(self.KERNEL, game.column_sequence_form_polytope),
|
|
202
|
+
prediction=True,
|
|
203
|
+
progress_bar=False,
|
|
204
|
+
)
|
|
205
|
+
e2 = game.exploitability(x_bar2, y_bar2)
|
|
206
|
+
v2 = game.expected_row_utility(x_bar2, y_bar2)
|
|
207
|
+
|
|
208
|
+
self.assertAlmostEqual(e, e2, self.PLACES)
|
|
209
|
+
self.assertAlmostEqual(v, v2, self.PLACES)
|
|
210
|
+
|
|
189
211
|
|
|
190
212
|
if __name__ == '__main__':
|
|
191
213
|
main() # pragma: no cover
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: noregret
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev7
|
|
4
4
|
Summary: No-regret learning dynamics
|
|
5
5
|
Home-page: https://github.com/uoftcprg/noregret
|
|
6
6
|
Author: Universal, Open, Free, and Transparent Computer Poker Research Group
|
|
@@ -94,8 +94,8 @@ The code snippet below demonstrates how one can solve games via regret minimizat
|
|
|
94
94
|
KERNEL = nr.FloatingPointKernel()
|
|
95
95
|
GAMES = {
|
|
96
96
|
'Rock paper superscissors': nr.to_efg(nr.RockPaperSuperscissors(KERNEL)),
|
|
97
|
-
'Kuhn poker': nr.to_efg(KERNEL, nr.
|
|
98
|
-
'Leduc poker': nr.to_efg(KERNEL, nr.
|
|
97
|
+
'Kuhn poker': nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
98
|
+
'Leduc poker': nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
99
99
|
}
|
|
100
100
|
PARAMETERS = {
|
|
101
101
|
'CFR': (nr.CFR, False, False),
|
|
@@ -180,7 +180,7 @@ The code snippet below demonstrates how one can solve games while leveraging GPU
|
|
|
180
180
|
import noregret as nr
|
|
181
181
|
|
|
182
182
|
KERNEL = nr.CUDAKernel()
|
|
183
|
-
GAME = nr.to_efg(KERNEL, nr.
|
|
183
|
+
GAME = nr.to_efg(KERNEL, nr.open_spiel_game('liars_dice'))
|
|
184
184
|
PARAMETERS = nr.CFR, True, False
|
|
185
185
|
|
|
186
186
|
|
|
@@ -220,8 +220,8 @@ The code snippet below demonstrates how one can solve games via linear programmi
|
|
|
220
220
|
KERNEL = nr.FloatingPointKernel()
|
|
221
221
|
GAMES = {
|
|
222
222
|
'Rock paper superscissors': nr.RockPaperSuperscissors(KERNEL),
|
|
223
|
-
'Kuhn poker': nr.to_efg(KERNEL, nr.
|
|
224
|
-
'Leduc poker': nr.to_efg(KERNEL, nr.
|
|
223
|
+
'Kuhn poker': nr.to_efg(KERNEL, nr.open_spiel_game('kuhn_poker')),
|
|
224
|
+
'Leduc poker': nr.to_efg(KERNEL, nr.open_spiel_game('leduc_poker')),
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
|
|
@@ -14,7 +14,6 @@ noregret/games/__init__.py
|
|
|
14
14
|
noregret/games/black_box.py
|
|
15
15
|
noregret/games/games.py
|
|
16
16
|
noregret/games/multilinear.py
|
|
17
|
-
noregret/games/utilities.py
|
|
18
17
|
noregret/games/extensive_form/__init__.py
|
|
19
18
|
noregret/games/extensive_form/games.py
|
|
20
19
|
noregret/games/normal_form/__init__.py
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
"""Module for utilities."""
|
|
2
|
-
from collections import defaultdict
|
|
3
|
-
from functools import partial, singledispatch
|
|
4
|
-
from itertools import starmap
|
|
5
|
-
|
|
6
|
-
from ordered_set import OrderedSet
|
|
7
|
-
from scipy.sparse import lil_array
|
|
8
|
-
|
|
9
|
-
from noregret.games.black_box import BlackBoxGame
|
|
10
|
-
from noregret.games.extensive_form.games import (
|
|
11
|
-
ExtensiveFormGame,
|
|
12
|
-
TwoPlayerExtensiveFormGame,
|
|
13
|
-
TwoPlayerZeroSumExtensiveFormGame,
|
|
14
|
-
)
|
|
15
|
-
from noregret.games.games import Game
|
|
16
|
-
from noregret.games.normal_form.games import (
|
|
17
|
-
NormalFormGame,
|
|
18
|
-
TwoPlayerNormalFormGame,
|
|
19
|
-
TwoPlayerZeroSumNormalFormGame,
|
|
20
|
-
)
|
|
21
|
-
from noregret.sequence_form_polytopes import SequenceFormPolytope
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _nfg2efg(kernel, game, decision_points=str):
|
|
25
|
-
np = kernel.numpy
|
|
26
|
-
scipy = kernel.scipy
|
|
27
|
-
dtype = kernel.data_type
|
|
28
|
-
|
|
29
|
-
if isinstance(game, TwoPlayerZeroSumNormalFormGame):
|
|
30
|
-
type_ = TwoPlayerZeroSumExtensiveFormGame
|
|
31
|
-
elif isinstance(game, TwoPlayerNormalFormGame):
|
|
32
|
-
type_ = TwoPlayerExtensiveFormGame
|
|
33
|
-
else:
|
|
34
|
-
type_ = ExtensiveFormGame
|
|
35
|
-
|
|
36
|
-
d = game.dimensions
|
|
37
|
-
|
|
38
|
-
if isinstance(game, TwoPlayerZeroSumNormalFormGame):
|
|
39
|
-
payoffs = np.zeros(tuple(n + 1 for n in d), dtype)
|
|
40
|
-
payoffs[tuple(slice(1, None) for _ in d)] = game.payoffs
|
|
41
|
-
else:
|
|
42
|
-
payoffs = np.zeros((game.player_count, *(n + 1 for n in d)), dtype)
|
|
43
|
-
payoffs[:, *(slice(1, None) for _ in d)] = game.payoffs
|
|
44
|
-
|
|
45
|
-
payoffs = scipy.sparse.csr_array(payoffs)
|
|
46
|
-
sfps = []
|
|
47
|
-
|
|
48
|
-
for i, A_j in enumerate(game.actions):
|
|
49
|
-
j = decision_points(i)
|
|
50
|
-
sfp = SequenceFormPolytope(kernel, {j: A_j}, {j: None})
|
|
51
|
-
|
|
52
|
-
sfps.append(sfp)
|
|
53
|
-
|
|
54
|
-
sfps = tuple(sfps)
|
|
55
|
-
|
|
56
|
-
return type_(kernel, payoffs, sfps)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def _bbg2efg(kernel, game):
|
|
60
|
-
scipy = kernel.scipy
|
|
61
|
-
dtype = kernel.data_type
|
|
62
|
-
P = range(game.player_count)
|
|
63
|
-
A_js = [defaultdict(OrderedSet) for _ in P]
|
|
64
|
-
p_js = [{} for _ in P]
|
|
65
|
-
raw_payoffs = [defaultdict(int) for _ in P]
|
|
66
|
-
|
|
67
|
-
def dfs(h, p, seqs, us):
|
|
68
|
-
A_j, h_primes = game.actions_and_children(h)
|
|
69
|
-
i = game.player(h)
|
|
70
|
-
us = us.copy()
|
|
71
|
-
|
|
72
|
-
for i_prime, v in enumerate(game.utilities(h)):
|
|
73
|
-
us[i_prime] += v
|
|
74
|
-
|
|
75
|
-
if not A_j:
|
|
76
|
-
seqs = tuple(seqs)
|
|
77
|
-
|
|
78
|
-
for i_prime, u in enumerate(us):
|
|
79
|
-
raw_payoffs[i_prime][seqs] += p * u
|
|
80
|
-
elif i is None:
|
|
81
|
-
p_primes = game.chance_probabilities(h)
|
|
82
|
-
|
|
83
|
-
for h_prime, p_prime in zip(h_primes, p_primes):
|
|
84
|
-
dfs(h_prime, p_prime * p, seqs, us)
|
|
85
|
-
else:
|
|
86
|
-
j = game.information_set(h)
|
|
87
|
-
p_j = seqs[i]
|
|
88
|
-
p_js[i][j] = p_j
|
|
89
|
-
|
|
90
|
-
for a, h_prime in zip(A_j, h_primes):
|
|
91
|
-
next_seqs = seqs.copy()
|
|
92
|
-
next_seqs[i] = j, a
|
|
93
|
-
|
|
94
|
-
A_js[i][j].add(a)
|
|
95
|
-
dfs(h_prime, p, next_seqs, us)
|
|
96
|
-
|
|
97
|
-
dfs(game.root_node, 1, [None for _ in P], [0 for _ in P])
|
|
98
|
-
|
|
99
|
-
SFP = partial(SequenceFormPolytope, kernel)
|
|
100
|
-
sfps = tuple(starmap(SFP, zip(A_js, p_js)))
|
|
101
|
-
dimensions = tuple(sfp.column_count for sfp in sfps)
|
|
102
|
-
|
|
103
|
-
if game.is_two_player and game.is_zero_sum:
|
|
104
|
-
type_ = TwoPlayerZeroSumExtensiveFormGame
|
|
105
|
-
payoffs = lil_array(dimensions, dtype=dtype)
|
|
106
|
-
|
|
107
|
-
for seqs, u in raw_payoffs[0].items():
|
|
108
|
-
indices = []
|
|
109
|
-
|
|
110
|
-
for sfp, seq in zip(sfps, seqs):
|
|
111
|
-
indices.append(sfp.column(seq))
|
|
112
|
-
|
|
113
|
-
payoffs[tuple(indices)] = u
|
|
114
|
-
|
|
115
|
-
payoffs = scipy.sparse.csr_array(payoffs)
|
|
116
|
-
else:
|
|
117
|
-
raise NotImplementedError
|
|
118
|
-
|
|
119
|
-
return type_(kernel, payoffs, sfps)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
@singledispatch
|
|
123
|
-
def to_extensive_form(kernel, game):
|
|
124
|
-
"""Convert a given game to an extensive-form game.
|
|
125
|
-
|
|
126
|
-
:param game: Game.
|
|
127
|
-
:return: Extensive-form game.
|
|
128
|
-
"""
|
|
129
|
-
if isinstance(game, NormalFormGame):
|
|
130
|
-
game = _nfg2efg(kernel, game)
|
|
131
|
-
elif isinstance(game, BlackBoxGame):
|
|
132
|
-
game = _bbg2efg(kernel, game)
|
|
133
|
-
else:
|
|
134
|
-
raise ValueError('unknown game')
|
|
135
|
-
|
|
136
|
-
return game
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
@to_extensive_form.register
|
|
140
|
-
def _(game: Game):
|
|
141
|
-
return to_extensive_form(game.kernel, game)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/battle-of-the-sexes.json
RENAMED
|
File without changes
|
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/gift-exchange-game.json
RENAMED
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/matching-pennies.json
RENAMED
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/prisoners-dilemma.json
RENAMED
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/pure-coordination.json
RENAMED
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/rock-paper-scissors-plus.json
RENAMED
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/rock-paper-scissors.json
RENAMED
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/games/normal_form/rock-paper-superscissors.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
"""Module for regret minimizers."""
|
|
2
|
-
from noregret.regret_minimizers.regret_minimizers import (
|
|
3
|
-
RegretMinimizer,
|
|
4
|
-
SwapRegretMinimizer,
|
|
5
|
-
)
|
|
6
2
|
from noregret.regret_minimizers.probability_simplices import (
|
|
7
3
|
BlumMansour,
|
|
8
4
|
DiscountedRegretMatching,
|
|
@@ -17,6 +13,10 @@ from noregret.regret_minimizers.probability_simplices import (
|
|
|
17
13
|
RegretMatching,
|
|
18
14
|
RegretMatchingPlus,
|
|
19
15
|
)
|
|
16
|
+
from noregret.regret_minimizers.regret_minimizers import (
|
|
17
|
+
RegretMinimizer,
|
|
18
|
+
SwapRegretMinimizer,
|
|
19
|
+
)
|
|
20
20
|
from noregret.regret_minimizers.sequence_form_polytopes import (
|
|
21
21
|
CounterfactualRegretMinimization,
|
|
22
22
|
CounterfactualRegretMinimization2,
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/regret_minimizers/probability_simplices.py
RENAMED
|
File without changes
|
|
File without changes
|
{noregret-0.0.0.dev6 → noregret-0.0.0.dev7}/noregret/regret_minimizers/sequence_form_polytopes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|