noregret 0.0.0.dev9__tar.gz → 0.0.0.dev10__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.
Files changed (44) hide show
  1. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/PKG-INFO +1 -1
  2. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/__init__.py +6 -2
  3. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/__init__.py +2 -0
  4. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/black_box.py +76 -0
  5. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/regret_minimizers/stochastic.py +2 -3
  6. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/tests/test_games.py +42 -0
  7. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/tests/test_regret_minimization.py +6 -3
  8. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/utilities.py +0 -14
  9. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret.egg-info/PKG-INFO +1 -1
  10. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/setup.py +1 -1
  11. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/LICENSE +0 -0
  12. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/README.rst +0 -0
  13. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/assurance-game.json +0 -0
  14. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/battle-of-the-sexes.json +0 -0
  15. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/chicken.json +0 -0
  16. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/gift-exchange-game.json +0 -0
  17. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/matching-pennies.json +0 -0
  18. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/prisoners-dilemma.json +0 -0
  19. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/pure-coordination.json +0 -0
  20. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/rock-paper-scissors-plus.json +0 -0
  21. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/rock-paper-scissors.json +0 -0
  22. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/rock-paper-superscissors.json +0 -0
  23. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/examples/stag-hunt.json +0 -0
  24. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/extensive_form.py +0 -0
  25. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/games.py +0 -0
  26. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/multilinear.py +0 -0
  27. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/games/normal_form.py +0 -0
  28. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/kernels.py +0 -0
  29. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/regret_minimizers/__init__.py +0 -0
  30. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/regret_minimizers/probability_simplices.py +0 -0
  31. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/regret_minimizers/regret_minimizers.py +0 -0
  32. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/regret_minimizers/sequence_form_polytopes.py +0 -0
  33. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/sequence_form_polytopes.py +0 -0
  34. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/solvers/__init__.py +0 -0
  35. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/solvers/linear_programming.py +0 -0
  36. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/solvers/regret_minimization.py +0 -0
  37. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/tests/__init__.py +0 -0
  38. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/tests/test_linear_programming.py +0 -0
  39. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret/tests/test_sequence_form_polytopes.py +0 -0
  40. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret.egg-info/SOURCES.txt +0 -0
  41. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret.egg-info/dependency_links.txt +0 -0
  42. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret.egg-info/requires.txt +0 -0
  43. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/noregret.egg-info/top_level.txt +0 -0
  44. {noregret-0.0.0.dev9 → noregret-0.0.0.dev10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: noregret
3
- Version: 0.0.0.dev9
3
+ Version: 0.0.0.dev10
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
@@ -17,6 +17,7 @@ from noregret.games import (
17
17
  RockPaperScissors,
18
18
  RockPaperScissorsPlus,
19
19
  RockPaperSuperscissors,
20
+ Simulation,
20
21
  StagHunt,
21
22
  StrategyProfile,
22
23
  to_extensive_form_game,
@@ -67,7 +68,7 @@ from noregret.solvers import (
67
68
  stochastic_regret_minimization,
68
69
  symmetric_regret_minimization,
69
70
  )
70
- from noregret.utilities import import_object, sample, tuple_or_none
71
+ from noregret.utilities import import_object, tuple_or_none
71
72
 
72
73
  BM = BlumMansour
73
74
  """Alias for :class:`noregret.BlumMansour`."""
@@ -121,6 +122,8 @@ RM = RegretMatching
121
122
  """Alias for :class:`noregret.RegretMatching`."""
122
123
  rm = regret_minimization
123
124
  """Alias for :func:`noregret.regret_minimization`."""
125
+ Sim = Simulation
126
+ """Alias for :class:`noregret.Simulation`."""
124
127
  stochastic_rm = stochastic_regret_minimization
125
128
  """Alias for :func:`noregret.stochastic_regret_minimization`."""
126
129
  symmetric_rm = symmetric_regret_minimization
@@ -194,10 +197,11 @@ __all__ = (
194
197
  'RockPaperScissors',
195
198
  'RockPaperScissorsPlus',
196
199
  'RockPaperSuperscissors',
197
- 'sample',
198
200
  'SequenceFormPolytope',
199
201
  'SequenceFormPolytopeRegretMinimizer',
200
202
  'Serializable',
203
+ 'Sim',
204
+ 'Simulation',
201
205
  'StagHunt',
202
206
  'stochastic_regret_minimization',
203
207
  'StochasticRegretMinimizer',
@@ -2,6 +2,7 @@
2
2
  from noregret.games.black_box import (
3
3
  BlackBoxGame,
4
4
  open_spiel_game,
5
+ Simulation,
5
6
  StrategyProfile,
6
7
  UniformStrategyProfile,
7
8
  )
@@ -53,6 +54,7 @@ __all__ = (
53
54
  'RockPaperScissors',
54
55
  'RockPaperScissorsPlus',
55
56
  'RockPaperSuperscissors',
57
+ 'Simulation',
56
58
  'StagHunt',
57
59
  'StrategyProfile',
58
60
  'to_extensive_form_game',
@@ -2,6 +2,7 @@
2
2
  from abc import ABC, abstractmethod
3
3
  from dataclasses import dataclass, field
4
4
  from functools import partial
5
+ from typing import Any
5
6
 
6
7
  from ordered_set import OrderedSet
7
8
  from pyspiel import exploitability, GameType, load_game
@@ -9,6 +10,39 @@ from pyspiel import exploitability, GameType, load_game
9
10
  from noregret.kernels import Kernel
10
11
 
11
12
 
13
+ @dataclass
14
+ class Simulation:
15
+ """Class for simulations."""
16
+ kernel: Kernel
17
+ """Kernel."""
18
+ players: list[int]
19
+ """Players."""
20
+ decision_points: list[str | None]
21
+ """Decision points."""
22
+ actions: list[str]
23
+ """Actions."""
24
+ utilities: Any
25
+ """Utilities."""
26
+
27
+ def sequences(self, player=None):
28
+ """Return sequences given an optional player.
29
+
30
+ :param player: Optional player.
31
+ :return: Sequences.
32
+ """
33
+ for i, j, a in zip(self.players, self.decision_points, self.actions):
34
+ if i is not None and (player is None or i == player):
35
+ yield j, a
36
+
37
+ def utility(self, player):
38
+ """Return the utility given a player.
39
+
40
+ :param player: Player.
41
+ :return: Utility.
42
+ """
43
+ return self.utilities[player]
44
+
45
+
12
46
  @dataclass
13
47
  class BlackBoxGame(ABC):
14
48
  """Abstract base class for black box games."""
@@ -140,11 +174,53 @@ class BlackBoxGame(ABC):
140
174
  return np.array(ps, dtype)
141
175
 
142
176
  def exploitability(self, strategy_profile):
177
+ """Return exploitability given a strategy profile.
178
+
179
+ :param strategy_profile: Strategy profile.
180
+ :return: Exploitability.
181
+ """
143
182
  if not self.is_two_player or not self.is_zero_sum:
144
183
  raise ValueError('not 2p0s')
145
184
 
146
185
  raise NotImplementedError
147
186
 
187
+ def simulate(self, strategy_profile):
188
+ """Run a simulation given a strategy profile.
189
+
190
+ :param strategy_profile: Strategy profile.
191
+ :return: Simulation.
192
+ """
193
+ np = self.kernel.numpy
194
+ is_ = []
195
+ js = []
196
+ as_ = []
197
+ h = self.root_node
198
+
199
+ while A := self.actions(h):
200
+ i = self.player(h)
201
+
202
+ if i is None:
203
+ j = None
204
+ ps = self.chance_probabilities(h)
205
+ else:
206
+ j = self.information_set(h)
207
+ ps = strategy_profile(h)
208
+
209
+ a = np.random.choice(A, p=ps).item()
210
+ h = self.apply(h, a)
211
+
212
+ is_.append(i)
213
+ js.append(j)
214
+ as_.append(a)
215
+
216
+ is_ = tuple(is_)
217
+ js = tuple(js)
218
+ as_ = tuple(as_)
219
+ us = self.utilities(h)
220
+ simulation = Simulation(self.kernel, is_, js, as_, us)
221
+
222
+ return simulation
223
+
148
224
 
149
225
  @dataclass
150
226
  class _OpenSpielBlackBoxGame(BlackBoxGame):
@@ -10,7 +10,6 @@ from noregret.regret_minimizers.probability_simplices import (
10
10
  ProbabilitySimplexRegretMinimizer,
11
11
  RegretMatching,
12
12
  )
13
- from noregret.utilities import sample
14
13
 
15
14
 
16
15
  @dataclass
@@ -105,7 +104,7 @@ class StochasticRegretMinimizer(ABC):
105
104
  us[j] = np.array(u_primes, dtype)
106
105
  u += us[j] @ ps
107
106
  else:
108
- a = sample(A, ps)
107
+ a = np.random.choice(A, p=ps).item()
109
108
  h_prime = self.game.apply(h, a)
110
109
  u += self._external_sampling(i, us, h_prime)
111
110
 
@@ -135,7 +134,7 @@ class StochasticRegretMinimizer(ABC):
135
134
  else:
136
135
  ps = self._action_probabilities(h)
137
136
 
138
- k = sample(range(len(A)), ps)
137
+ k = np.random.choice(len(A), p=ps)
139
138
  a = A[k]
140
139
  h_prime = self.game.apply(h, a)
141
140
  p_prime = ps[k] * p
@@ -6,6 +6,7 @@ import noregret as nr
6
6
 
7
7
  class GameTestCaseMixin(ABC):
8
8
  KER = None
9
+ GAMES = None
9
10
 
10
11
  @abstractmethod
11
12
  def uniform_strategy_profile(self, game):
@@ -145,12 +146,43 @@ class ExtensiveFormGameTestCase(GameTestCaseMixin, TestCase):
145
146
  self.assertEqual(sfp.parent_sequences, sfp2.parent_sequences)
146
147
 
147
148
 
149
+ class SimulationTestCase(TestCase):
150
+ KER = nr.FPKer()
151
+
152
+ def test_sequences(self):
153
+ np = self.KER.numpy
154
+ dtype = self.KER.data_type
155
+ sim = nr.Sim(
156
+ self.KER,
157
+ (0, None, 0, 1),
158
+ ('', None, 'ab', 'b'),
159
+ ('a', 'b', 'c', 'd'),
160
+ np.array([1, -1], dtype),
161
+ )
162
+
163
+ self.assertEqual(
164
+ tuple(sim.sequences()),
165
+ (('', 'a'), ('ab', 'c'), ('b', 'd')),
166
+ )
167
+ self.assertEqual(tuple(sim.sequences(0)), (('', 'a'), ('ab', 'c')))
168
+ self.assertEqual(tuple(sim.sequences(1)), (('b', 'd'),))
169
+
170
+ def test_utility(self):
171
+ np = self.KER.numpy
172
+ dtype = self.KER.data_type
173
+ sim = nr.Sim(self.KER, (), (), (), np.array([1, -1], dtype))
174
+
175
+ self.assertEqual(sim.utility(0), 1)
176
+ self.assertEqual(sim.utility(1), -1)
177
+
178
+
148
179
  class BlackBoxGameTestCase(TestCase):
149
180
  KER = nr.FPKer()
150
181
  GAMES = (
151
182
  nr.open_spiel_game(KER, 'kuhn_poker'),
152
183
  nr.open_spiel_game(KER, 'leduc_poker'),
153
184
  )
185
+ SEED = 42
154
186
 
155
187
  def test_actions_and_children(self):
156
188
  for game in self.GAMES:
@@ -210,6 +242,16 @@ class BlackBoxGameTestCase(TestCase):
210
242
 
211
243
  self.assertAlmostEqual(epsilon, epsilon2)
212
244
 
245
+ def test_simulation(self):
246
+ np = self.KER.numpy
247
+
248
+ for game in self.GAMES:
249
+ np.random.seed(self.SEED)
250
+
251
+ sigma = nr.UniformStrategyProfile(self.KER, game)
252
+
253
+ game.simulate(sigma)
254
+
213
255
 
214
256
  if __name__ == '__main__':
215
257
  main() # pragma: no cover
@@ -1,6 +1,5 @@
1
1
  from functools import partial
2
2
  from math import inf
3
- from random import seed
4
3
  from unittest import main, TestCase
5
4
 
6
5
  import noregret as nr
@@ -218,9 +217,11 @@ class StochasticRegretMinimizationTestCase(TestCase):
218
217
  SEED = 42
219
218
 
220
219
  def test_external_sampling(self):
220
+ np = self.KER.numpy
221
+
221
222
  assert self.GAME.is_two_player and self.GAME.is_zero_sum
222
223
 
223
- seed(self.SEED)
224
+ np.random.seed(self.SEED)
224
225
 
225
226
  R = nr.MCCFR(self.KER, self.GAME)
226
227
  sigma = nr.stochastic_rm(
@@ -235,9 +236,11 @@ class StochasticRegretMinimizationTestCase(TestCase):
235
236
  self.assertLess(epsilon, self.TARGET_EXPLOITABILITY)
236
237
 
237
238
  def test_outcome_sampling(self):
239
+ np = self.KER.numpy
240
+
238
241
  assert self.GAME.is_two_player and self.GAME.is_zero_sum
239
242
 
240
- seed(self.SEED)
243
+ np.random.seed(self.SEED)
241
244
 
242
245
  R = nr.MCCFR(
243
246
  self.KER,
@@ -1,6 +1,5 @@
1
1
  """Module for utilities."""
2
2
  from importlib import import_module
3
- from random import choices
4
3
 
5
4
 
6
5
  def import_object(object_path):
@@ -35,16 +34,3 @@ def tuple_or_none(values):
35
34
  :return: Tuple or ``None``.
36
35
  """
37
36
  return None if values is None else tuple(values)
38
-
39
-
40
- def sample(values, probabilities):
41
- """Sample a random value as per the probabilities.
42
-
43
- >>> sample(range(5), [0, 0, 1, 0, 0])
44
- 2
45
-
46
- :param values: Values to be sampled from.
47
- :param probabilities: The probabilities of sampling each value.
48
- :return: The sampled value.
49
- """
50
- return choices(values, probabilities)[0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: noregret
3
- Version: 0.0.0.dev9
3
+ Version: 0.0.0.dev10
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
@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
4
4
 
5
5
  setup(
6
6
  name='noregret',
7
- version='0.0.0.dev9',
7
+ version='0.0.0.dev10',
8
8
  description='No-regret learning dynamics',
9
9
  long_description=open('README.rst').read(),
10
10
  long_description_content_type='text/x-rst',
File without changes
File without changes
File without changes