Skip to content

Commit 66c4037

Browse files
committed
RFC: Build PolymatrixGame.polymatrix as numba.typed.Dict
Also Numba-fy PolymatrixGame.range_of_payoffs()
1 parent 83d3c6c commit 66c4037

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

quantecon/game_theory/polymatrix_game.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
# from typing import TypeAlias, Self
4040
from numpy.typing import NDArray
4141

42+
from numba import jit, types
43+
from numba.typed import Dict as NumbaDict
44+
4245
from .normal_form_game import NormalFormGame, Player, _nums_actions2string
4346

4447

@@ -151,7 +154,7 @@ class PolymatrixGame:
151154
nums_actions : tuple(int)
152155
The number of actions available to each player.
153156
154-
polymatrix : dict[tuple(int), ndarray(float, ndim=2)]
157+
polymatrix : numba.typed.Dict[tuple(int), ndarray(float, ndim=2)]
155158
Maps each pair of player numbers to a matrix.
156159
157160
"""
@@ -209,7 +212,10 @@ def __init__(
209212
for p2 in range(self.N)
210213
if p1 != p2
211214
]
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+
)
213219
for (p1, p2) in matchups:
214220
rows = self.nums_actions[p1]
215221
cols = self.nums_actions[p2]
@@ -250,13 +256,19 @@ def from_nf(
250256
Self
251257
The Polymatrix Game.
252258
"""
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+
)
260272
for p1 in range(nf.N):
261273
for a1 in range(nf.nums_actions[p1]):
262274
payoffs = hh_payoff_player(
@@ -314,6 +326,20 @@ def range_of_payoffs(self) -> tuple[float, float]:
314326
tuple[float, float]
315327
Tuple of minimum and maximum.
316328
"""
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

Comments
 (0)