Skip to content

Commit

Permalink
Implement empirical payoff estimation method for AQRE.
Browse files Browse the repository at this point in the history
  • Loading branch information
tturocy committed Apr 16, 2024
1 parent f24845c commit 0603918
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
1 change: 1 addition & 0 deletions doc/pygambit.api.rst
Expand Up @@ -300,5 +300,6 @@ Computation of quantal response equilibria
fit_strategy_fixedpoint
LogitQREMixedStrategyFitResult

fit_behavior_empirical
fit_behavior_fixedpoint
LogitQREMixedBehaviorFitResult
52 changes: 52 additions & 0 deletions src/pygambit/qre.py
Expand Up @@ -510,6 +510,8 @@ def fit_behavior_fixedpoint(
See Also
--------
fit_strategy_fixedpoint : Estimate QRE using the strategic representation
fit_behavior_empirical : Estimate QRE by approximation of the correspondence
using independent decision problems.
References
----------
Expand All @@ -521,3 +523,53 @@ def fit_behavior_fixedpoint(
return LogitQREMixedBehaviorFitResult(
data, "fixedpoint", res.lam, res.profile, res.log_like
)


def fit_behavior_empirical(
data: libgbt.MixedBehaviorProfileDouble
) -> LogitQREMixedBehaviorFitResult:
"""Use maximum likelihood estimation to estimate a quantal
response equilibrium using the empirical payoff method.
The empirical payoff method operates by ignoring the fixed-point
considerations of the QRE and approximates instead by a collection
of independent decision problems. [1]_
Returns
-------
LogitQREMixedBehaviorFitResult
The result of the estimation represented as a
``LogitQREMixedBehaviorFitResult`` object.
See Also
--------
fit_behavior_fixedpoint : Estimate QRE precisely by computing the correspondence
References
----------
.. [1] Bland, J. R. and Turocy, T. L., 2023. Quantal response equilibrium
as a structural model for estimation: The missing manual.
SSRN working paper 4425515.
"""
def do_logit(lam: float):
logit_probs = [[math.exp(lam*a) for a in infoset]
for player in values for infoset in player]
sums = [sum(v) for v in logit_probs]
logit_probs = [[v/s for v in vv]
for (vv, s) in zip(logit_probs, sums)]
logit_probs = [v for infoset in logit_probs for v in infoset]
return [max(v, 1.0e-293) for v in logit_probs]

def log_like(lam: float) -> float:
logit_probs = do_logit(lam)
return sum([f*math.log(p) for (f, p) in zip(list(flattened_data), logit_probs)])

flattened_data = [data[a] for p in data.game.players for s in p.infosets for a in s.actions]
normalized = data.normalize()
values = [[[normalized.action_value(a) for a in s.actions]
for s in p.infosets]
for p in data.game.players]
res = scipy.optimize.minimize(lambda x: -log_like(x[0]), (0.1,),
bounds=((0.0, None),))
return LogitQREMixedBehaviorFitResult(
data, "empirical", res.x[0], do_logit(res.x[0]), -res.fun
)
2 changes: 1 addition & 1 deletion src/solvers/logit/efglogit.h
Expand Up @@ -101,7 +101,7 @@ LogitBehaviorEstimate(const MixedBehaviorProfile<double> &p_frequencies, double
alg.SetMaxDecel(p_maxAccel);
alg.SetStepsize(p_firstStep);
std::ostringstream ostream;
return alg.Estimate(start, p_frequencies, ostream, 1000000.0, 1.0);
return alg.Estimate(start, p_frequencies, ostream, 2.0, 1.0);
}

inline List<MixedBehaviorProfile<double>> LogitBehaviorSolve(const Game &p_game, double p_epsilon,
Expand Down

0 comments on commit 0603918

Please sign in to comment.