#NEWLINE# def phi_sa( self , s , terminal , a , phi_s = None , snippet = False ) : #NEWLINE# #INDENT# '\n        Returns the feature vector corresponding to a state-action pair.\n        We use the copy paste technique (Lagoudakis & Parr 2003).\n        Essentially, we append the phi(s) vector to itself *|A|* times, where\n        *|A|* is the size of the action space.\n        We zero the feature values of all of these blocks except the one\n        corresponding to the actionID *a*.\n\n        When ``snippet == False`` we construct and return the full, sparse phi_sa.\n        When ``snippet == True``, we return the tuple (phi_s, index1, index2)\n        where index1 and index2 are the indices defining the ends of the phi_s\n        block which WOULD be nonzero if we were to construct the full phi_sa.\n\n        :param s: The queried state in the state-action pair.\n        :param terminal: Whether or not *s* is a terminal state\n        :param a: The queried action in the state-action pair.\n        :param phi_s: (optional) The feature vector evaluated at state s.\n            If the feature vector phi(s) has already been cached,\n            pass it here as input so that it need not be computed again.\n        :param snippet: if ``True``, do not return a single phi_sa vector,\n            but instead a tuple of the components needed to create it.\n            See return value below.\n\n        :return: If ``snippet==False``, return the enormous phi_sa vector\n            constructed by the copy-paste method.\n            If ``snippet==True``, do not construct phi_sa, only return\n            a tuple (phi_s, index1, index2) as described above.\n\n        ' #NEWLINE# if ( phi_s is None ) : #NEWLINE# #INDENT# phi_s = self . phi ( s , terminal ) #NEWLINE# #UNINDENT# if ( snippet is True ) : #NEWLINE# #INDENT# return ( phi_s , ( a * self . features_num ) , ( ( a + 1 ) * phi_sa . features_num ) ) #NEWLINE# #UNINDENT# phi_sa = np . zeros ( ( self . features_num * self . actions_num ) , dtype = phi_s . dtype ) #NEWLINE# if ( self . features_num == 0 ) : #NEWLINE# #INDENT# return phi_sa #NEWLINE# #UNINDENT# if ( len ( self . _arange_cache ) != self . features_num ) : #NEWLINE# #INDENT# self . _arange_cache = np . arange ( ( a * self . features_num ) , ( ( a + 1 ) * self . features_num ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# self . _arange_cache += ( ( a * self . features_num ) - self . _arange_cache [ 0 ] ) #NEWLINE# #UNINDENT# phi_sa [ self . _arange_cache ] = phi_s #NEWLINE# return phi_sa