|
39 | 39 | # from typing import TypeAlias, Self |
40 | 40 | from numpy.typing import NDArray |
41 | 41 |
|
| 42 | +from numba import jit, types |
| 43 | +from numba.typed import Dict as NumbaDict |
| 44 | + |
42 | 45 | from .normal_form_game import NormalFormGame, Player, _nums_actions2string |
43 | 46 |
|
44 | 47 |
|
@@ -151,7 +154,7 @@ class PolymatrixGame: |
151 | 154 | nums_actions : tuple(int) |
152 | 155 | The number of actions available to each player. |
153 | 156 |
|
154 | | - polymatrix : dict[tuple(int), ndarray(float, ndim=2)] |
| 157 | + polymatrix : numba.typed.Dict[tuple(int), ndarray(float, ndim=2)] |
155 | 158 | Maps each pair of player numbers to a matrix. |
156 | 159 |
|
157 | 160 | """ |
@@ -209,7 +212,10 @@ def __init__( |
209 | 212 | for p2 in range(self.N) |
210 | 213 | if p1 != p2 |
211 | 214 | ] |
212 | | - self.polymatrix: dict[tuple[int, int], NDArray] = {} |
| 215 | + self.polymatrix: Mapping[tuple[int, int], NDArray] = NumbaDict.empty( |
| 216 | + key_type=types.UniTuple(types.int_, 2), |
| 217 | + value_type=types.float64[:, :], |
| 218 | + ) |
213 | 219 | for (p1, p2) in matchups: |
214 | 220 | rows = self.nums_actions[p1] |
215 | 221 | cols = self.nums_actions[p2] |
@@ -250,13 +256,19 @@ def from_nf( |
250 | 256 | Self |
251 | 257 | The Polymatrix Game. |
252 | 258 | """ |
253 | | - polymatrix_builder = { |
254 | | - (p1, p2): np.full( |
255 | | - (nf.nums_actions[p1], nf.nums_actions[p2]), -np.inf) |
256 | | - for p1 in range(nf.N) |
257 | | - for p2 in range(nf.N) |
258 | | - if p1 != p2 |
259 | | - } |
| 259 | + polymatrix_builder = NumbaDict.empty( |
| 260 | + key_type=types.UniTuple(types.int_, 2), |
| 261 | + value_type=types.float64[:, :], |
| 262 | + ) |
| 263 | + for p1 in range(nf.N): |
| 264 | + for p2 in range(nf.N): |
| 265 | + if p1 == p2: |
| 266 | + continue |
| 267 | + rows = nf.nums_actions[p1] |
| 268 | + cols = nf.nums_actions[p2] |
| 269 | + polymatrix_builder[(p1, p2)] = np.full( |
| 270 | + (rows, cols), -np.inf, dtype=np.float64 |
| 271 | + ) |
260 | 272 | for p1 in range(nf.N): |
261 | 273 | for a1 in range(nf.nums_actions[p1]): |
262 | 274 | payoffs = hh_payoff_player( |
@@ -314,6 +326,20 @@ def range_of_payoffs(self) -> tuple[float, float]: |
314 | 326 | tuple[float, float] |
315 | 327 | Tuple of minimum and maximum. |
316 | 328 | """ |
317 | | - min_p = min([np.min(M) for M in self.polymatrix.values()]) |
318 | | - max_p = max([np.max(M) for M in self.polymatrix.values()]) |
319 | | - return (min_p, max_p) |
| 329 | + return _min_max(self.polymatrix) |
| 330 | + |
| 331 | + |
| 332 | +@jit(nopython=True, cache=True) |
| 333 | +def _min_max(polymatrix): |
| 334 | + min_ = max_ = next(iter(polymatrix.values()))[0, 0] |
| 335 | + for a in polymatrix.values(): |
| 336 | + m, n = a.shape |
| 337 | + for i in range(m): |
| 338 | + for j in range(n): |
| 339 | + x = a[i, j] |
| 340 | + if x < min_: |
| 341 | + min_ = x |
| 342 | + elif x > max_: |
| 343 | + max_ = x |
| 344 | + |
| 345 | + return min_, max_ |
0 commit comments