<s> r"""<STR_LIT>""" <EOL> import re <EOL> import numbers <EOL> import numpy as np <EOL> from numba import jit <EOL> from . . util import check_random_state <EOL> class Player ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , payoff_array ) : <EOL> self . payoff_array = np . asarray ( payoff_array ) <EOL> if self . payoff_array . ndim == <NUM_LIT:0> : <EOL> raise ValueError ( '<STR_LIT>' ) <EOL> self . num_opponents = self . payoff_array . ndim - <NUM_LIT:1> <EOL> self . num_actions = self . payoff_array . shape [ <NUM_LIT:0> ] <EOL> self . dtype = self . payoff_array . dtype <EOL> self . tol = <NUM_LIT> <EOL> def __repr__ ( self ) : <EOL> s = repr ( self . payoff_array ) . replace ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> l = s . splitlines ( ) <EOL> for i in range ( <NUM_LIT:1> , len ( l ) ) : <EOL> if l [ i ] : <EOL> l [ i ] = '<STR_LIT:U+0020>' + l [ i ] <EOL> return '<STR_LIT:\n>' . join ( l ) <EOL> def __str__ ( self ) : <EOL> N = self . num_opponents + <NUM_LIT:1> <EOL> s = '<STR_LIT>' . format ( N = N ) <EOL> s += '<STR_LIT>' <EOL> s += np . array2string ( self . payoff_array , separator = '<STR_LIT:U+002CU+0020>' ) <EOL> return s <EOL> def payoff_vector ( self , opponents_actions ) : <EOL> """<STR_LIT>""" <EOL> def reduce_last_player ( payoff_array , action ) : <EOL> """<STR_LIT>""" <EOL> if isinstance ( action , numbers . Integral ) : <EOL> return payoff_array . take ( action , axis = - <NUM_LIT:1> ) <EOL> else : <EOL> return payoff_array . dot ( action ) <EOL> if self . num_opponents == <NUM_LIT:1> : <EOL> payoff_vector = reduce_last_player ( self . payoff_array , opponents_actions ) <EOL> elif self . num_opponents >= <NUM_LIT:2> : <EOL> payoff_vector = self . payoff_array <EOL> for i in reversed ( range ( self . num_opponents ) ) : <EOL> payoff_vector = reduce_last_player ( payoff_vector , opponents_actions [ i ] ) <EOL> else : <EOL> payoff_vector = self . payoff_array <EOL> return payoff_vector <EOL> def is_best_response ( self , own_action , opponents_actions ) : <EOL> """<STR_LIT>""" <EOL> payoff_vector = self . payoff_vector ( opponents_actions ) <EOL> payoff_max = payoff_vector . max ( ) <EOL> if isinstance ( own_action , numbers . Integral ) : <EOL> return payoff_vector [ own_action ] >= payoff_max - self . tol <EOL> else : <EOL> return np . dot ( own_action , payoff_vector ) >= payoff_max - self . tol <EOL> def best_response ( self , opponents_actions , tie_breaking = '<STR_LIT>' , <EOL> payoff_perturbation = None , random_state = None ) : <EOL> """<STR_LIT>""" <EOL> payoff_vector = self . payoff_vector ( opponents_actions ) <EOL> if payoff_perturbation is not None : <EOL> try : <EOL> payoff_vector += payoff_perturbation <EOL> except TypeError : <EOL> payoff_vector = payoff_vector + payoff_perturbation <EOL> if tie_breaking == '<STR_LIT>' : <EOL> best_response = np . argmax ( payoff_vector ) <EOL> return best_response <EOL> else : <EOL> best_responses = np . where ( payoff_vector >= payoff_vector . max ( ) - self . tol ) [ <NUM_LIT:0> ] <EOL> if tie_breaking == '<STR_LIT>' : <EOL> return self . random_choice ( best_responses , <EOL> random_state = random_state ) <EOL> elif tie_breaking is False : <EOL> return best_responses <EOL> else : <EOL> msg = "<STR_LIT>" + "<STR_LIT>" <EOL> raise ValueError ( msg ) <EOL> def random_choice ( self , actions = None , random_state = None ) : <EOL> """<STR_LIT>""" <EOL> random_state = check_random_state ( random_state ) <EOL> if actions is not None : <EOL> n = len ( actions ) <EOL> else : <EOL> n = self . num_actions <EOL> if n == <NUM_LIT:1> : <EOL> idx = <NUM_LIT:0> <EOL> else : <EOL> idx = random_state . randint ( n ) <EOL> if actions is not None : <EOL> return actions [ idx ] <EOL> else : <EOL> return idx <EOL> class NormalFormGame ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , data , dtype = None ) : <EOL> if hasattr ( data , '<STR_LIT>' ) and isinstance ( data [ <NUM_LIT:0> ] , Player ) : <EOL> N = len ( data ) <EOL> shape_0 = data [ <NUM_LIT:0> ] . payoff_array . shape <EOL> dtype_0 = data [ <NUM_LIT:0> ] . payoff_array . dtype <EOL> for i in range ( <NUM_LIT:1> , N ) : <EOL> shape = data [ i ] . payoff_array . shape <EOL> if not ( <EOL> len ( shape ) == N and <EOL> shape == shape_0 [ i : ] + shape_0 [ : i ] <EOL> ) : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> ) <EOL> dtype = data [ i ] . payoff_array . dtype <EOL> if dtype != dtype_0 : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> ) <EOL> self . players = tuple ( data ) <EOL> self . dtype = dtype_0 <EOL> else : <EOL> data = np . asarray ( data ) <EOL> if data . ndim == <NUM_LIT:0> : <EOL> N = <NUM_LIT:1> <EOL> self . players = ( Player ( np . zeros ( data ) ) , ) <EOL> self . dtype = data . dtype <EOL> elif data . ndim == <NUM_LIT:1> : <EOL> N = data . size <EOL> self . players = tuple ( <EOL> Player ( np . zeros ( tuple ( data [ i : ] ) + tuple ( data [ : i ] ) , <EOL> dtype = dtype ) ) <EOL> for i in range ( N ) <EOL> ) <EOL> self . dtype = self . players [ <NUM_LIT:0> ] . payoff_array . dtype <EOL> elif data . ndim == <NUM_LIT:2> and data . shape [ <NUM_LIT:1> ] >= <NUM_LIT:2> : <EOL> if data . shape [ <NUM_LIT:0> ] != data . shape [ <NUM_LIT:1> ] : <EOL> raise ValueError ( <EOL> '<STR_LIT>' + <EOL> '<STR_LIT>' <EOL> ) <EOL> N = <NUM_LIT:2> <EOL> self . players = tuple ( Player ( data ) for i in range ( N ) ) <EOL> self . dtype = data . dtype <EOL> else : <EOL> N = data . ndim - <NUM_LIT:1> <EOL> if data . shape [ - <NUM_LIT:1> ] != N : <EOL> raise ValueError ( <EOL> '<STR_LIT>' + <EOL> '<STR_LIT>' <EOL> ) <EOL> self . players = tuple ( <EOL> Player ( <EOL> data . take ( i , axis = - <NUM_LIT:1> ) . transpose ( list ( range ( i , N ) ) + <EOL> list ( range ( i ) ) ) <EOL> ) for i in range ( N ) <EOL> ) <EOL> self . dtype = data . dtype <EOL> self . N = N <EOL> self . nums_actions = tuple ( <EOL> player . num_actions for player in self . players <EOL> ) <EOL> @ property <EOL> def payoff_profile_array ( self ) : <EOL> N = self . N <EOL> dtype = self . dtype <EOL> payoff_profile_array = np . empty ( self . players [ <NUM_LIT:0> ] . payoff_array . shape + ( N , ) , dtype = dtype ) <EOL> for i , player in enumerate ( self . players ) : <EOL> payoff_profile_array [ ... , i ] = player . payoff_array . transpose ( list ( range ( N - i , N ) ) + <EOL> list ( range ( N - i ) ) ) <EOL> return payoff_profile_array <EOL> def __repr__ ( self ) : <EOL> s = '<STR_LIT>' <EOL> return s . format ( nums_actions = _nums_actions2string ( self . nums_actions ) , <EOL> N = self . N , <EOL> dtype = self . dtype ) <EOL> def __str__ ( self ) : <EOL> s = '<STR_LIT>' <EOL> s += _payoff_profile_array2string ( self . payoff_profile_array ) <EOL> return s . format ( N = self . N ) <EOL> def __getitem__ ( self , action_profile ) : <EOL> if self . N == <NUM_LIT:1> : <EOL> if not isinstance ( action_profile , numbers . Integral ) : <EOL> raise TypeError ( '<STR_LIT>' ) <EOL> return self . players [ <NUM_LIT:0> ] . payoff_array [ action_profile ] <EOL> try : <EOL> if len ( action_profile ) != self . N : <EOL> raise IndexError ( '<STR_LIT>' . format ( self . N ) ) <EOL> except TypeError : <EOL> raise TypeError ( '<STR_LIT>' ) <EOL> payoff_profile = np . empty ( self . N , dtype = self . dtype ) <EOL> for i , player in enumerate ( self . players ) : <EOL> payoff_profile [ i ] = player . payoff_array [ <EOL> tuple ( action_profile [ i : ] ) + tuple ( action_profile [ : i ] ) <EOL> ] <EOL> return payoff_profile <EOL> def __setitem__ ( self , action_profile , payoff_profile ) : <EOL> if self . N == <NUM_LIT:1> : <EOL> if not isinstance ( action_profile , numbers . Integral ) : <EOL> raise TypeError ( '<STR_LIT>' ) <EOL> self . players [ <NUM_LIT:0> ] . payoff_array [ action_profile ] = payoff_profile <EOL> return None <EOL> try : <EOL> if len ( action_profile ) != self . N : <EOL> raise IndexError ( '<STR_LIT>' . format ( self . N ) ) <EOL> except TypeError : <EOL> raise TypeError ( '<STR_LIT>' ) <EOL> try : <EOL> if len ( payoff_profile ) != self . N : <EOL> raise ValueError ( <EOL> '<STR_LIT>' . format ( self . N ) <EOL> ) <EOL> except TypeError : <EOL> raise TypeError ( '<STR_LIT>' ) <EOL> for i , player in enumerate ( self . players ) : <EOL> player . payoff_array [ <EOL> tuple ( action_profile [ i : ] ) + tuple ( action_profile [ : i ] ) <EOL> ] = payoff_profile [ i ] <EOL> def is_nash ( self , action_profile ) : <EOL> """<STR_LIT>""" <EOL> if self . N == <NUM_LIT:2> : <EOL> for i , player in enumerate ( self . players ) : <EOL> own_action , opponent_action = action_profile [ i ] , action_profile [ <NUM_LIT:1> - i ] <EOL> if not player . is_best_response ( own_action , opponent_action ) : <EOL> return False <EOL> elif self . N >= <NUM_LIT:3> : <EOL> for i , player in enumerate ( self . players ) : <EOL> own_action = action_profile [ i ] <EOL> opponents_actions = tuple ( action_profile [ i + <NUM_LIT:1> : ] ) + tuple ( action_profile [ : i ] ) <EOL> if not player . is_best_response ( own_action , opponents_actions ) : <EOL> return False <EOL> else : <EOL> if not self . players [ <NUM_LIT:0> ] . is_best_response ( action_profile [ <NUM_LIT:0> ] , None ) : <EOL> return False <EOL> return True <EOL> def _nums_actions2string ( nums_actions ) : <EOL> if len ( nums_actions ) == <NUM_LIT:1> : <EOL> s = '<STR_LIT>' . format ( nums_actions [ <NUM_LIT:0> ] ) <EOL> else : <EOL> s = '<STR_LIT:x>' . join ( map ( str , nums_actions ) ) <EOL> return s <EOL> def _payoff_profile_array2string ( payoff_profile_array , class_name = None ) : <EOL> s = np . array2string ( payoff_profile_array , separator = '<STR_LIT:U+002CU+0020>' ) <EOL> s = re . sub ( r'<STR_LIT>' , lambda x : x . group ( <NUM_LIT:0> ) [ <NUM_LIT:0> : - <NUM_LIT:1> ] , s ) <EOL> if class_name is not None : <EOL> prefix = class_name + '<STR_LIT:(>' <EOL> next_line_prefix = '<STR_LIT:U+0020>' * len ( prefix ) <EOL> suffix = '<STR_LIT:)>' <EOL> l = s . splitlines ( ) <EOL> l [ <NUM_LIT:0> ] = prefix + l [ <NUM_LIT:0> ] <EOL> for i in range ( <NUM_LIT:1> , len ( l ) ) : <EOL> if l [ i ] : <EOL> l [ i ] = next_line_prefix + l [ i ] <EOL> l [ - <NUM_LIT:1> ] += suffix <EOL> s = '<STR_LIT:\n>' . join ( l ) <EOL> return s <EOL> def pure2mixed ( num_actions , action ) : <EOL> """<STR_LIT>""" <EOL> mixed_action = np . zeros ( num_actions ) <EOL> mixed_action [ action ] = <NUM_LIT:1> <EOL> return mixed_action <EOL> @ jit ( nopython = True ) <EOL> def best_response_2p ( payoff_matrix , opponent_mixed_action ) : <EOL> """<STR_LIT>""" <EOL> n , m = payoff_matrix . shape <EOL> best_response = <NUM_LIT:0> <EOL> payoff_0 = <NUM_LIT:0> <EOL> for b in range ( m ) : <EOL> payoff_0 += payoff_matrix [ <NUM_LIT:0> , b ] * opponent_mixed_action [ b ] <EOL> payoff_max = payoff_0 <EOL> for a in range ( <NUM_LIT:1> , n ) : <EOL> payoff = <NUM_LIT:0> <EOL> for b in range ( m ) : <EOL> payoff += payoff_matrix [ a , b ] * opponent_mixed_action [ b ] <EOL> if payoff > payoff_max : <EOL> payoff_max = payoff <EOL> best_response = a <EOL> return best_response </s>
