Skip to content

Commit 6db11d8

Browse files
committed
RFC: Refactor GAMWriter._dump
- Use `io.StringIO()` - Fine tune `np.array2string` - Add tests for `to_gam`
1 parent a168fa4 commit 6db11d8

2 files changed

Lines changed: 46 additions & 10 deletions

File tree

quantecon/game_theory/game_converters.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
[[-19., -19., 1.], [ -8., -8., 2.], [ 3., 3., 3.]]]]
2828
2929
"""
30+
import io
31+
import sys
3032
import numbers
3133
import numpy as np
3234
from .normal_form_game import Player, NormalFormGame
@@ -326,17 +328,27 @@ def to_string(cls, g):
326328

327329
@staticmethod
328330
def _dump(g):
329-
s = str(g.N) + '\n'
330-
s += ' '.join(map(str, g.nums_actions)) + '\n\n'
331+
p = GAMPayoffVector.from_nfg(g)
331332

332-
for i, player in enumerate(g.players):
333-
payoffs = np.array2string(
334-
player.payoff_array.transpose(
335-
(*range(g.N-i, g.N), *range(g.N-i))
336-
).ravel(order='F'))[1:-1]
337-
s += ' '.join(payoffs.split()) + ' '
333+
buf = io.StringIO()
334+
335+
buf.write(str(p.N))
336+
buf.write('\n')
337+
buf.write(' '.join(map(str, p.nums_actions)))
338+
buf.write('\n\n')
339+
340+
payoffs_str = np.array2string(
341+
p.payoffs,
342+
separator=' ',
343+
threshold=sys.maxsize, # no truncation '...'
344+
# suppress_small helps avoid scientific notation for small |x|;
345+
# large |x| values may still print with e+...
346+
suppress_small=True
347+
)[1:-1] # strip brackets
348+
349+
buf.write(' '.join(payoffs_str.split()))
338350

339-
return s.rstrip()
351+
return buf.getvalue().rstrip()
340352

341353

342354
def from_gam(filename: str) -> NormalFormGame:

quantecon/game_theory/tests/test_game_converters.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def test_invalid_inputs():
104104
assert_raises(ValueError, GAMPayoffVector, (2, 2), np.zeros(7))
105105

106106

107-
# TestGAMWriter #
107+
# GAMWriter/to_gam #
108108

109109
class TestGAMWriter:
110110
def setup_method(self):
@@ -157,3 +157,27 @@ def test_to_gam(self):
157157
assert_string_equal(s_actual, self.s_desired + '\n')
158158

159159
os.remove(temp_path)
160+
161+
162+
def test_gam_writer_many_actions():
163+
n0, n1 = 40, 60
164+
p0 = Player(np.arange(n0 * n1).reshape(n0, n1))
165+
p1 = Player((np.arange(n1 * n0) + 10_000).reshape(n1, n0))
166+
g = NormalFormGame((p0, p1))
167+
168+
s = to_gam(g)
169+
170+
# NumPy summary marker should never appear
171+
assert_('...' not in s)
172+
173+
# Token count matches N * prod(nums_actions)
174+
tokens = s.split()
175+
N = int(tokens[0])
176+
nums_actions = tuple(int(x) for x in tokens[1:1+N])
177+
payoff_tokens = tokens[1+N:]
178+
179+
assert_(N == 2)
180+
assert_(nums_actions == (n0, n1))
181+
182+
expected = N * np.prod(nums_actions)
183+
assert_(len(payoff_tokens) == expected)

0 commit comments

Comments
 (0)