I'm new to python so this might be a stupid question, however I couldn't find an answer to this anywhere.
I'm trying to find the optimal reaction for a player given the action of another player. The situation is your typical Bertrand price competition for those familiar economics. The code is as follows:
import numpy as np
from scipy.optimize import minimize
class Player:
def __init__(self):
self.action = np.random.choice(np.linspace(0, 1, 11))
def payoff(self, other):
if self.action < other.action:
return (1 - self.action) * self.action
elif self.action == other.action:
return 0.5 * (1 - self.action) * self.action
else:
return 0
def best_reply(self, other):
br = minimize(-self.payoff, 0.5, other)
return br['x']
A = Player()
B = Player()
print(A.best_reply(B))
When I run the above code I get an error of:
TypeError: bad operand type for unary -: 'method'
Can someone explain to me why this is? I was able to circumvent the problem by multiplying the payoffs by -1 and removing the '-' from the best_reply function. However, when I then run the code I get:
TypeError: payoff() takes 2 positional arguments but 3 were given
How come? The only arguments I've given are self (A) and the other player (B). If someone would be able to help me out by explaining what exactly I'm doing wrong and what the correct way of running such code is, I would be extremely grateful. Thank you in advance!
Edit: Added imports to the code
Here's how I would do it. Separate the function to be optimized from the class method and have a private static method for the payoff calculation that both methods can utilize.
import numpy as np
from scipy.optimize import minimize
class Player:
def __init__(self):
self.action = np.random.choice(np.linspace(0, 1, 11))
@staticmethod
def _calc_payoff(a, b):
if a < b:
return (1 - a) * a
elif a == b:
return 0.5 * (1 - a) * a
else:
return 0
def payoff(self, other):
return self._calc_payoff(self.action, other.action)
def best_reply(self, other):
f = lambda x: 1 - self._calc_payoff(x, other.action)
br = minimize(f, 0.5)
return br.x.item()
A = Player()
B = Player()
print(A.best_reply(B))
Is 0.5
the correct result?