77Create a QuantEcon NormalFormGame from a gam file storing
88a 3-player Minimum Effort Game
99
10- >>> filepath = "./tests/gam_files/minimum_effort_game.gam"
11- >>> nfg = qe_nfg_from_gam_file(filepath)
10+ >>> import os
11+ >>> import quantecon.game_theory as gt
12+ >>> filepath = os.path.dirname(gt.__file__)
13+ >>> filepath += "/tests/game_files/minimum_effort_game.gam"
14+ >>> nfg = gt.from_gam(filepath)
1215>>> print(nfg)
13163-player NormalFormGame with payoff profile array:
1417[[[[ 1., 1., 1.], [ 1., 1., -9.], [ 1., 1., -19.]],
2427 [[-19., -19., 1.], [ -8., -8., 2.], [ 3., 3., 3.]]]]
2528
2629"""
30+ import numpy as np
31+ from .normal_form_game import Player , NormalFormGame
2732
28- from .normal_form_game import NormalFormGame
29- from itertools import product
3033
34+ def str2num (s ):
35+ if '.' in s :
36+ return float (s )
37+ return int (s )
3138
32- def qe_nfg_from_gam_file (filename : str ) -> NormalFormGame :
39+
40+ class GAMReader :
41+ """
42+ Reader object that converts a game in GameTracer gam format into
43+ a NormalFormGame.
44+
45+ """
46+ @classmethod
47+ def from_file (cls , file_path ):
48+ """
49+ Read from a gam format file.
50+
51+ Parameters
52+ ----------
53+ file_path : str
54+ Path to gam file.
55+
56+ Returns
57+ -------
58+ NormalFormGame
59+
60+ Examples
61+ --------
62+ Save a gam format string in a temporary file:
63+
64+ >>> import tempfile
65+ >>> fname = tempfile.mkstemp()[1]
66+ >>> with open(fname, mode='w') as f:
67+ ... f.write(\" \" \" \\
68+ ... 2
69+ ... 3 2
70+ ...
71+ ... 3 2 0 3 5 6 3 2 3 2 6 1\" \" \" )
72+
73+ Read the file:
74+
75+ >>> g = GAMReader.from_file(fname)
76+ >>> print(g)
77+ 2-player NormalFormGame with payoff profile array:
78+ [[[3, 3], [3, 2]],
79+ [[2, 2], [5, 6]],
80+ [[0, 3], [6, 1]]]
81+
82+ """
83+ with open (file_path , 'r' ) as f :
84+ string = f .read ()
85+ return cls ._parse (string )
86+
87+ @classmethod
88+ def from_url (cls , url ):
89+ """
90+ Read from a URL.
91+
92+ """
93+ import urllib .request
94+ with urllib .request .urlopen (url ) as response :
95+ string = response .read ().decode ()
96+ return cls ._parse (string )
97+
98+ @classmethod
99+ def from_string (cls , string ):
100+ """
101+ Read from a gam format string.
102+
103+ Parameters
104+ ----------
105+ string : str
106+ String in gam format.
107+
108+ Returns
109+ -------
110+ NormalFormGame
111+
112+ Examples
113+ --------
114+ >>> string = \" \" \" \\
115+ ... 2
116+ ... 3 2
117+ ...
118+ ... 3 2 0 3 5 6 3 2 3 2 6 1\" \" \"
119+ >>> g = GAMReader.from_string(string)
120+ >>> print(g)
121+ 2-player NormalFormGame with payoff profile array:
122+ [[[3, 3], [3, 2]],
123+ [[2, 2], [5, 6]],
124+ [[0, 3], [6, 1]]]
125+
126+ """
127+ return cls ._parse (string )
128+
129+ @staticmethod
130+ def _parse (string ):
131+ tokens = string .split ()
132+
133+ N = int (tokens .pop (0 ))
134+ nums_actions = tuple (int (tokens .pop (0 )) for _ in range (N ))
135+ payoffs = np .array ([str2num (s ) for s in tokens ])
136+
137+ na = np .prod (nums_actions )
138+ payoffs2d = payoffs .reshape (N , na )
139+ players = [
140+ Player (
141+ payoffs2d [i , :].reshape (nums_actions , order = 'F' ).transpose (
142+ list (range (i , N )) + list (range (i ))
143+ )
144+ ) for i in range (N )
145+ ]
146+
147+ return NormalFormGame (players )
148+
149+
150+ class GAMWriter :
151+ """
152+ Writer object that converts a NormalFormgame into a game in
153+ GameTracer gam format.
154+
155+ """
156+ @classmethod
157+ def to_file (cls , g , file_path ):
158+ """
159+ Save the GameTracer gam format string representation of the
160+ NormalFormGame `g` to a file.
161+
162+ Parameters
163+ ----------
164+ g : NormalFormGame
165+
166+ file_path : str
167+ Path to the file to write to.
168+
169+ """
170+ with open (file_path , 'w' ) as f :
171+ f .write (cls ._dump (g ) + '\n ' )
172+
173+ @classmethod
174+ def to_string (cls , g ):
175+ """
176+ Return a GameTracer gam format string representing the
177+ NormalFormGame `g`.
178+
179+ Parameters
180+ ----------
181+ g : NormalFormGame
182+
183+ Returns
184+ -------
185+ str
186+ String representation in gam format.
187+
188+ """
189+ return cls ._dump (g )
190+
191+ @staticmethod
192+ def _dump (g ):
193+ s = str (g .N ) + '\n '
194+ s += ' ' .join (map (str , g .nums_actions )) + '\n \n '
195+
196+ for i , player in enumerate (g .players ):
197+ payoffs = np .array2string (
198+ player .payoff_array .transpose (
199+ list (range (g .N - i , g .N )) + list (range (g .N - i ))
200+ ).ravel (order = 'F' ))[1 :- 1 ]
201+ s += ' ' .join (payoffs .split ()) + ' '
202+
203+ return s .rstrip ()
204+
205+
206+ def from_gam (filename : str ) -> NormalFormGame :
33207 """
34208 Makes a QuantEcon Normal Form Game from a gam file.
35209
@@ -51,32 +225,22 @@ def qe_nfg_from_gam_file(filename: str) -> NormalFormGame:
51225 http://dags.stanford.edu/Games/gametracer.html
52226
53227 """
54- with open (filename , 'r' ) as file :
55- lines = file .readlines ()
56- combined = [
57- token
58- for line in lines
59- for token in line .split ()
60- ]
228+ return GAMReader .from_file (filename )
61229
62- i = iter (combined )
63- players = int (next (i ))
64- actions = [int (next (i )) for _ in range (players )]
65230
66- nfg = NormalFormGame (actions )
231+ def to_gam (g , file_path = None ):
232+ """
233+ Write a NormalFormGame to a file in gam format.
67234
68- entries = [
69- {
70- tuple (reversed (action_combination )): float (next (i ))
71- for action_combination in product (
72- * [range (a ) for a in actions ])
73- }
74- for _ in range (players )
75- ]
235+ Parameters
236+ ----------
237+ g : NormalFormGame
76238
77- for action_combination in product (* [range (a ) for a in actions ]):
78- nfg [action_combination ] = tuple (
79- entries [p ][action_combination ] for p in range (players )
80- )
239+ file_path : str, optional(default=None)
240+ Path to the file to write to. If None, the result is returned as
241+ a string.
81242
82- return nfg
243+ """
244+ if file_path is None :
245+ return GAMWriter .to_string (g )
246+ return GAMWriter .to_file (g , file_path )
0 commit comments