Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions src/games/nash.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,16 @@
namespace Gambit::Nash {

template <class T>
using StrategyCallbackType =
std::function<void(const MixedStrategyProfile<T> &, const std::string &)>;
using StrategyCallbackType = std::function<void(const MixedStrategyProfile<T> &)>;

/// @brief A fallback callback function for mixed strategy profiles that does nothing
template <class T> void NullStrategyCallback(const MixedStrategyProfile<T> &, const std::string &)
{
}
template <class T> void NullStrategyCallback(const MixedStrategyProfile<T> &) {}

template <class T>
using BehaviorCallbackType =
std::function<void(const MixedBehaviorProfile<T> &, const std::string &)>;
using BehaviorCallbackType = std::function<void(const MixedBehaviorProfile<T> &)>;

/// @brief A fallback callback function for mixed behavior profiles that does nothing
template <class T> void NullBehaviorCallback(const MixedBehaviorProfile<T> &, const std::string &)
{
}
template <class T> void NullBehaviorCallback(const MixedBehaviorProfile<T> &) {}

template <class T>
std::list<MixedBehaviorProfile<T>>
Expand Down
2 changes: 1 addition & 1 deletion src/solvers/enummixed/enummixed.cc
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ EnumMixedStrategySolveDetailed(const Game &p_game, StrategyCallbackType<T> p_onE
}
eqm = eqm.Normalize();
solution->m_extremeEquilibria.push_back(eqm);
p_onEquilibrium(eqm, "NE");
p_onEquilibrium(eqm);

// note: The keys give the mixed strategy associated with each node.
// The keys should also keep track of the basis
Expand Down
8 changes: 4 additions & 4 deletions src/solvers/enumpoly/efgpoly.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ namespace Gambit::Nash {

std::list<MixedBehaviorProfile<double>>
EnumPolyBehaviorSolve(const Game &p_game, int p_stopAfter, double p_maxregret,
EnumPolyMixedBehaviorObserverFunctionType p_onEquilibrium,
EnumPolyBehaviorSupportObserverFunctionType p_onSupport)
BehaviorCallbackType<double> p_onEquilibrium,
EnumPolyEventCallbackType<BehaviorSupportProfile> p_onEvent)
{
const double scale = p_game->GetMaxPayoff() - p_game->GetMinPayoff();
if (scale != 0.0) {
Expand All @@ -236,7 +236,7 @@ EnumPolyBehaviorSolve(const Game &p_game, int p_stopAfter, double p_maxregret,
auto possible_supports = PossibleNashBehaviorSupports(p_game);

for (auto support : possible_supports->m_supports) {
p_onSupport("candidate", support);
p_onEvent(EnumPolyCandidateSupportEvent<BehaviorSupportProfile>{support});
bool isSingular = false;
for (const auto &solution :
SolveSupport(support, isSingular, std::max(p_stopAfter - static_cast<int>(ret.size()), 0),
Expand All @@ -245,7 +245,7 @@ EnumPolyBehaviorSolve(const Game &p_game, int p_stopAfter, double p_maxregret,
ret.push_back(solution);
}
if (isSingular) {
p_onSupport("singular", support);
p_onEvent(EnumPolySingularSupportEvent<BehaviorSupportProfile>{support});
}
if (p_stopAfter > 0 && static_cast<int>(ret.size()) >= p_stopAfter) {
break;
Expand Down
53 changes: 24 additions & 29 deletions src/solvers/enumpoly/enumpoly.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,46 +24,41 @@
#ifndef GAMBIT_SOLVERS_ENUMPOLY_ENUMPOLY_H
#define GAMBIT_SOLVERS_ENUMPOLY_ENUMPOLY_H

#include <variant>

#include "games/nash.h"
#include "solvers/nashsupport/nashsupport.h"

namespace Gambit::Nash {

using EnumPolyMixedStrategyObserverFunctionType =
std::function<void(const MixedStrategyProfile<double> &)>;

inline void EnumPolyNullMixedStrategyObserver(const MixedStrategyProfile<double> &) {}

using EnumPolyStrategySupportObserverFunctionType =
std::function<void(const std::string &, const StrategySupportProfile &)>;

inline void EnumPolyNullStrategySupportObserver(const std::string &,
const StrategySupportProfile &)
{
}
template <class Support> struct EnumPolyCandidateSupportEvent {
const Support &support;
};

std::list<MixedStrategyProfile<double>> EnumPolyStrategySolve(
const Game &p_game, int p_stopAfter, double p_maxregret,
EnumPolyMixedStrategyObserverFunctionType p_onEquilibrium = EnumPolyNullMixedStrategyObserver,
EnumPolyStrategySupportObserverFunctionType p_onSupport = EnumPolyNullStrategySupportObserver);
template <class Support> struct EnumPolySingularSupportEvent {
const Support &support;
};

using EnumPolyMixedBehaviorObserverFunctionType =
std::function<void(const MixedBehaviorProfile<double> &)>;
template <class Support>
using EnumPolyEvent =
std::variant<EnumPolyCandidateSupportEvent<Support>, EnumPolySingularSupportEvent<Support>>;

inline void EnumPolyNullMixedBehaviorObserver(const MixedBehaviorProfile<double> &) {}
template <class Support>
using EnumPolyEventCallbackType = std::function<void(const EnumPolyEvent<Support> &)>;

using EnumPolyBehaviorSupportObserverFunctionType =
std::function<void(const std::string &, const BehaviorSupportProfile &)>;
template <class Support> void NullEnumPolyEventCallback(const EnumPolyEvent<Support> &) {}

inline void EnumPolyNullBehaviorSupportObserver(const std::string &,
const BehaviorSupportProfile &)
{
}
std::list<MixedStrategyProfile<double>>
EnumPolyStrategySolve(const Game &p_game, int p_stopAfter, double p_maxregret,
StrategyCallbackType<double> p_onEquilibrium = NullStrategyCallback<double>,
EnumPolyEventCallbackType<StrategySupportProfile> p_onEvent =
NullEnumPolyEventCallback<StrategySupportProfile>);

std::list<MixedBehaviorProfile<double>> EnumPolyBehaviorSolve(
const Game &, int p_stopAfter, double p_maxregret,
EnumPolyMixedBehaviorObserverFunctionType p_onEquilibrium = EnumPolyNullMixedBehaviorObserver,
EnumPolyBehaviorSupportObserverFunctionType p_onSupport = EnumPolyNullBehaviorSupportObserver);
std::list<MixedBehaviorProfile<double>>
EnumPolyBehaviorSolve(const Game &, int p_stopAfter, double p_maxregret,
BehaviorCallbackType<double> p_onEquilibrium = NullBehaviorCallback<double>,
EnumPolyEventCallbackType<BehaviorSupportProfile> p_onEvent =
NullEnumPolyEventCallback<BehaviorSupportProfile>);

} // namespace Gambit::Nash

Expand Down
8 changes: 4 additions & 4 deletions src/solvers/enumpoly/nfgpoly.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ EnumPolyStrategySupportSolve(const StrategySupportProfile &support, bool &is_sin

std::list<MixedStrategyProfile<double>>
EnumPolyStrategySolve(const Game &p_game, int p_stopAfter, double p_maxregret,
EnumPolyMixedStrategyObserverFunctionType p_onEquilibrium,
EnumPolyStrategySupportObserverFunctionType p_onSupport)
StrategyCallbackType<double> p_onEquilibrium,
EnumPolyEventCallbackType<StrategySupportProfile> p_onEvent)
{
const double scale = p_game->GetMaxPayoff() - p_game->GetMinPayoff();
if (scale != 0.0) {
Expand All @@ -152,7 +152,7 @@ EnumPolyStrategySolve(const Game &p_game, int p_stopAfter, double p_maxregret,
auto possible_supports = PossibleNashStrategySupports(p_game);

for (auto support : possible_supports->m_supports) {
p_onSupport("candidate", support);
p_onEvent(EnumPolyCandidateSupportEvent<StrategySupportProfile>{support});
bool is_singular;
for (auto solution : EnumPolyStrategySupportSolve(
support, is_singular, std::max(p_stopAfter - static_cast<int>(ret.size()), 0))) {
Expand All @@ -164,7 +164,7 @@ EnumPolyStrategySolve(const Game &p_game, int p_stopAfter, double p_maxregret,
}

if (is_singular) {
p_onSupport("singular", support);
p_onEvent(EnumPolySingularSupportEvent<StrategySupportProfile>{support});
}
if (p_stopAfter > 0 && static_cast<int>(ret.size()) >= p_stopAfter) {
break;
Expand Down
4 changes: 2 additions & 2 deletions src/solvers/enumpure/enumpure.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ inline std::list<MixedStrategyProfile<Rational>> EnumPureStrategySolve(
for (const auto &profile : StrategyContingencies(p_game)) {
if (IsNash(profile)) {
solutions.push_back(profile->ToMixedStrategyProfile());
p_onEquilibrium(solutions.back(), "NE");
p_onEquilibrium(solutions.back());
}
}
return solutions;
Expand Down Expand Up @@ -95,7 +95,7 @@ EnumPureAgentSolve(const Game &p_game,
for (auto citer : BehaviorContingencies(BehaviorSupportProfile(p_game))) {
if (IsAgentNash(citer)) {
solutions.push_back(citer.ToMixedBehaviorProfile());
p_onEquilibrium(solutions.back(), "NE");
p_onEquilibrium(solutions.back());
}
}
return solutions;
Expand Down
33 changes: 22 additions & 11 deletions src/solvers/gnm/gnm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace {
std::list<MixedStrategyProfile<double>>
Solve(const Game &p_game, const std::shared_ptr<gnmgame> &p_rep, const cvector &p_pert,
double p_lambdaEnd, int p_steps, int p_localNewtonInterval, int p_localNewtonMaxits,
std::function<void(const MixedStrategyProfile<double> &, const std::string &)> &p_callback)
Nash::StrategyCallbackType<double> p_onEquilibrium, Nash::GNMEventCallbackType p_onEvent)
{
const double FUZZ = 1e-12;
const bool WOBBLE = false;
Expand All @@ -49,12 +49,23 @@ Solve(const Game &p_game, const std::shared_ptr<gnmgame> &p_rep, const cvector &
throw UndefinedException("Perturbation vector must have at least one nonzero component.");
}
std::list<MixedStrategyProfile<double>> eqa;
p_callback(ToProfile(p_game, p_pert), "pert");
const auto perturbation = ToProfile(p_game, p_pert);
p_onEvent(Nash::GNMPerturbationEvent{perturbation});
cvector norm_pert = p_pert / p_pert.norm();
std::list<cvector> answers;
std::string return_message;
auto callback = [p_game, p_callback](const std::string &label, const cvector &sigma) {
p_callback(ToProfile(p_game, sigma), label);
auto callback = [p_game, p_onEquilibrium, p_onEvent](const std::string &label,
const cvector &sigma) {
const auto profile = ToProfile(p_game, sigma);
if (label == "NE") {
p_onEquilibrium(profile);
}
else if (label == "start") {
p_onEvent(Nash::GNMStartEvent{profile});
}
else {
p_onEvent(Nash::GNMStepEvent{profile, std::stod(label)});
}
};
GNM(*p_rep, norm_pert, answers, p_steps, FUZZ, p_localNewtonInterval, p_localNewtonMaxits,
p_lambdaEnd, WOBBLE, THRESHOLD, callback, return_message);
Expand All @@ -68,10 +79,10 @@ Solve(const Game &p_game, const std::shared_ptr<gnmgame> &p_rep, const cvector &

namespace Gambit::Nash {

std::list<MixedStrategyProfile<double>> GNMStrategySolve(const Game &p_game, double p_lambdaEnd,
int p_steps, int p_localNewtonInterval,
int p_localNewtonMaxits,
StrategyCallbackType<double> p_callback)
std::list<MixedStrategyProfile<double>>
GNMStrategySolve(const Game &p_game, double p_lambdaEnd, int p_steps, int p_localNewtonInterval,
int p_localNewtonMaxits, StrategyCallbackType<double> p_onEquilibrium,
GNMEventCallbackType p_onEvent)
{
if (!p_game->IsPerfectRecall()) {
throw UndefinedException(
Expand All @@ -88,21 +99,21 @@ std::list<MixedStrategyProfile<double>> GNMStrategySolve(const Game &p_game, dou
pert[player->GetStrategies().front()] = 1.0;
}
return Solve(p_game, A, ToPerturbation(pert), p_lambdaEnd, p_steps, p_localNewtonInterval,
p_localNewtonMaxits, p_callback);
p_localNewtonMaxits, p_onEquilibrium, p_onEvent);
}

std::list<MixedStrategyProfile<double>>
GNMStrategySolve(const MixedStrategyProfile<double> &p_pert, double p_lambdaEnd, int p_steps,
int p_localNewtonInterval, int p_localNewtonMaxits,
StrategyCallbackType<double> p_callback)
StrategyCallbackType<double> p_onEquilibrium, GNMEventCallbackType p_onEvent)
{
if (!p_pert.GetGame()->IsPerfectRecall()) {
throw UndefinedException(
"Computing equilibria of games with imperfect recall is not supported.");
}
const std::shared_ptr<gnmgame> A = BuildGame(p_pert.GetGame(), true);
return Solve(p_pert.GetGame(), A, ToPerturbation(p_pert), p_lambdaEnd, p_steps,
p_localNewtonInterval, p_localNewtonMaxits, p_callback);
p_localNewtonInterval, p_localNewtonMaxits, p_onEquilibrium, p_onEvent);
}

} // end namespace Gambit::Nash
26 changes: 24 additions & 2 deletions src/solvers/gnm/gnm.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#ifndef GAMBIT_NASH_GNM_H
#define GAMBIT_NASH_GNM_H

#include <variant>

#include "games/nash.h"
#include "solvers/gtracer/gtracer.h"

Expand All @@ -33,17 +35,37 @@ const int GNM_LOCAL_NEWTON_INTERVAL_DEFAULT = 3;
const int GNM_LOCAL_NEWTON_MAXITS_DEFAULT = 10;
const int GNM_STEPS_DEFAULT = 100;

struct GNMPerturbationEvent {
const MixedStrategyProfile<double> &profile;
};

struct GNMStartEvent {
const MixedStrategyProfile<double> &profile;
};

struct GNMStepEvent {
const MixedStrategyProfile<double> &profile;
double lambda;
};

using GNMEvent = std::variant<GNMPerturbationEvent, GNMStartEvent, GNMStepEvent>;
using GNMEventCallbackType = std::function<void(const GNMEvent &)>;

inline void NullGNMEventCallback(const GNMEvent &) {}

std::list<MixedStrategyProfile<double>>
GNMStrategySolve(const Game &p_game, double p_lambdaEnd, int p_steps, int p_localNewtonInterval,
int p_localNewtonMaxits,
StrategyCallbackType<double> p_callback = NullStrategyCallback<double>);
StrategyCallbackType<double> p_onEquilibrium = NullStrategyCallback<double>,
GNMEventCallbackType p_onEvent = NullGNMEventCallback);

/// @brief Compute the mixed strategy equilibria accessible via the initial ray determined
/// by \p p_profile using the Global Newton method
std::list<MixedStrategyProfile<double>>
GNMStrategySolve(const MixedStrategyProfile<double> &p_profile, double p_lambdaEnd, int p_steps,
int p_localNewtonInterval, int p_localNewtonMaxits,
StrategyCallbackType<double> p_callback = NullStrategyCallback<double>);
StrategyCallbackType<double> p_onEquilibrium = NullStrategyCallback<double>,
GNMEventCallbackType p_onEvent = NullGNMEventCallback);

} // end namespace Gambit::Nash

Expand Down
10 changes: 5 additions & 5 deletions src/solvers/ipa/ipa.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ using namespace Gambit::gametracer;

namespace Gambit::Nash {

std::list<MixedStrategyProfile<double>> IPAStrategySolve(const Game &p_game,
StrategyCallbackType<double> p_callback)
std::list<MixedStrategyProfile<double>>
IPAStrategySolve(const Game &p_game, StrategyCallbackType<double> p_onEquilibrium)
{
MixedStrategyProfile<double> pert = p_game->NewMixedStrategyProfile(0.0);
for (const auto &player : p_game->GetPlayers()) {
Expand All @@ -41,12 +41,12 @@ std::list<MixedStrategyProfile<double>> IPAStrategySolve(const Game &p_game,
for (auto player : p_game->GetPlayers()) {
pert[player->GetStrategies().front()] = 1.0;
}
return IPAStrategySolve(pert, p_callback);
return IPAStrategySolve(pert, p_onEquilibrium);
}

std::list<MixedStrategyProfile<double>>
IPAStrategySolve(const MixedStrategyProfile<double> &p_pert,
StrategyCallbackType<double> p_callback)
StrategyCallbackType<double> p_onEquilibrium)
{
if (!p_pert.GetGame()->IsPerfectRecall()) {
throw UndefinedException(
Expand All @@ -67,7 +67,7 @@ IPAStrategySolve(const MixedStrategyProfile<double> &p_pert,

std::list<MixedStrategyProfile<double>> solutions;
solutions.push_back(ToProfile(p_pert.GetGame(), ans));
p_callback(solutions.back(), "NE");
p_onEquilibrium(solutions.back());
return solutions;
}

Expand Down
4 changes: 2 additions & 2 deletions src/solvers/ipa/ipa.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ namespace Gambit::Nash {

std::list<MixedStrategyProfile<double>>
IPAStrategySolve(const Game &p_game,
StrategyCallbackType<double> p_callback = NullStrategyCallback<double>);
StrategyCallbackType<double> p_onEquilibrium = NullStrategyCallback<double>);

std::list<MixedStrategyProfile<double>>
IPAStrategySolve(const MixedStrategyProfile<double> &p_pert,
StrategyCallbackType<double> p_callback = NullStrategyCallback<double>);
StrategyCallbackType<double> p_onEquilibrium = NullStrategyCallback<double>);

} // namespace Gambit::Nash

Expand Down
2 changes: 1 addition & 1 deletion src/solvers/lcp/efglcp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ std::list<MixedBehaviorProfile<T>> NashLcpBehaviorSolver<T>::Solve(const Game &p
GetProfile(tab, profile, sol, p_game->GetRoot(), 1, 1, solution);
profile.UndefinedToCentroid();
solution.m_equilibria.push_back(profile);
this->m_onEquilibrium(profile, "NE");
this->m_onEquilibrium(profile);
return solution.m_equilibria;
}

Expand Down
2 changes: 1 addition & 1 deletion src/solvers/lcp/nfglcp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ NashLcpStrategySolver<T>::OnBFS(const Game &p_game, linalg::LHTableau<T> &p_tabl
}
}

m_onEquilibrium(profile, "NE");
m_onEquilibrium(profile);
p_solution.m_equilibria.push_back(profile);

if (m_stopAfter > 0 && p_solution.EquilibriumCount() >= m_stopAfter) {
Expand Down
Loading
Loading