diff --git a/Makefile.am b/Makefile.am index 2a19386a9..4325353ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -285,6 +285,9 @@ agg_SOURCES = \ game_SOURCES = \ src/gambit.h \ + src/games/gameseq.cc \ + src/games/gameseq.h \ + src/games/ndarray.h \ src/games/number.h \ src/games/gameobject.h \ src/games/game.cc \ @@ -398,9 +401,6 @@ gambit_nashsupport_SOURCES = \ gambit_enumpoly_SOURCES = \ ${core_SOURCES} ${game_SOURCES} ${gambit_nashsupport_SOURCES} \ - src/solvers/enumpoly/ndarray.h \ - src/solvers/enumpoly/gameseq.cc \ - src/solvers/enumpoly/gameseq.h \ src/solvers/enumpoly/indexproduct.h \ src/solvers/enumpoly/rectangle.h \ src/solvers/enumpoly/poly.cc \ diff --git a/src/games/behavspt.cc b/src/games/behavspt.cc index 71eec0931..6b9004acc 100644 --- a/src/games/behavspt.cc +++ b/src/games/behavspt.cc @@ -21,6 +21,7 @@ // #include "gambit.h" +#include "gameseq.h" namespace Gambit { @@ -259,4 +260,55 @@ std::list BehaviorSupportProfile::GetMembers(const GameInfoset &p_info return answer; } +//======================================================================== +// BehaviorSupportProfile: Sequence form +//======================================================================== + +std::shared_ptr BehaviorSupportProfile::GetSequenceForm() const +{ + if (!m_sequenceForm) { + m_sequenceForm = std::make_shared(*this); + } + return m_sequenceForm; +} + +SequencesWrapper BehaviorSupportProfile::GetSequences() const +{ + return SequencesWrapper(GetSequenceForm()->GetSequences()); +} + +PlayerSequencesWrapper BehaviorSupportProfile::GetSequences(GamePlayer &p_player) const +{ + return PlayerSequencesWrapper(GetSequenceForm()->GetSequences(p_player)); +} + +int BehaviorSupportProfile::GetConstraintEntry(const GameInfoset &p_infoset, + const GameAction &p_action) const +{ + return GetSequenceForm()->GetConstraintEntry(p_infoset, p_action); +} + +const Rational &BehaviorSupportProfile::GetPayoff( + const std::map> &p_profile, + const GamePlayer &p_player) const +{ + return GetSequenceForm()->GetPayoff(p_profile, p_player); +} + +MixedBehaviorProfile BehaviorSupportProfile::ToMixedBehaviorProfile( + const std::map, double> &p_profile) const +{ + return GetSequenceForm()->ToMixedBehaviorProfile(p_profile); +} + +InfosetsWrapper BehaviorSupportProfile::GetInfosets() const +{ + return InfosetsWrapper(GetSequenceForm()->GetInfosets()); +} + +ContingenciesWrapper BehaviorSupportProfile::GetContingencies() const +{ + return ContingenciesWrapper(GetSequenceForm()->GetContingencies()); +} + } // end namespace Gambit diff --git a/src/games/behavspt.h b/src/games/behavspt.h index bf15cccb5..099234ba0 100644 --- a/src/games/behavspt.h +++ b/src/games/behavspt.h @@ -29,6 +29,13 @@ namespace Gambit { +class GameSequenceForm; +class GameSequenceRep; +class SequencesWrapper; +class PlayerSequencesWrapper; +class InfosetsWrapper; +class ContingenciesWrapper; + /// This class represents a subset of the actions in an extensive game. /// It is enforced that each player has at least one action at each /// information set; thus, the actions in a support can be viewed as @@ -139,6 +146,20 @@ class BehaviorSupportProfile { /// Returns a copy of the support with dominated actions eliminated BehaviorSupportProfile Undominated(bool p_strict) const; //@} + + mutable std::shared_ptr m_sequenceForm; + std::shared_ptr GetSequenceForm() const; + SequencesWrapper GetSequences() const; + PlayerSequencesWrapper GetSequences(GamePlayer &p_player) const; + int GetConstraintEntry(const GameInfoset &p_infoset, const GameAction &p_action) const; + const Rational & + GetPayoff(const std::map> &p_profile, + const GamePlayer &p_player) const; + GameRep::Players GetPlayers() const { return GetGame()->GetPlayers(); } + MixedBehaviorProfile + ToMixedBehaviorProfile(const std::map, double> &) const; + InfosetsWrapper GetInfosets() const; + ContingenciesWrapper GetContingencies() const; }; } // end namespace Gambit diff --git a/src/solvers/enumpoly/gameseq.cc b/src/games/gameseq.cc similarity index 100% rename from src/solvers/enumpoly/gameseq.cc rename to src/games/gameseq.cc diff --git a/src/solvers/enumpoly/gameseq.h b/src/games/gameseq.h similarity index 86% rename from src/solvers/enumpoly/gameseq.h rename to src/games/gameseq.h index 54f43c0eb..d5718599f 100644 --- a/src/solvers/enumpoly/gameseq.h +++ b/src/games/gameseq.h @@ -28,7 +28,7 @@ namespace Gambit { -struct GameSequenceRep { +class GameSequenceRep { public: GamePlayer player; GameAction action; @@ -293,6 +293,61 @@ class GameSequenceForm { ToMixedBehaviorProfile(const std::map &) const; }; +class SequencesWrapper { +public: + explicit SequencesWrapper(const GameSequenceForm::Sequences &sequences) : m_sequences(sequences) + { + } + + auto begin() const { return m_sequences.begin(); } + auto end() const { return m_sequences.end(); } + + std::size_t size() const { return m_sequences.size(); } + +private: + GameSequenceForm::Sequences m_sequences; +}; + +class PlayerSequencesWrapper { +public: + explicit PlayerSequencesWrapper(const GameSequenceForm::PlayerSequences &sequences) + : m_sequences(sequences) + { + } + + auto begin() const { return m_sequences.begin(); } + auto end() const { return m_sequences.end(); } + + std::size_t size() const { return m_sequences.size(); } + +private: + GameSequenceForm::PlayerSequences m_sequences; +}; + +class InfosetsWrapper { +public: + explicit InfosetsWrapper(const GameSequenceForm::Infosets &infosets) : m_infosets(infosets) {} + + std::size_t size() const { return m_infosets.size(); } + +private: + GameSequenceForm::Infosets m_infosets; +}; + +class ContingenciesWrapper { +public: + explicit ContingenciesWrapper(const GameSequenceForm::Contingencies &contingencies) + : m_contingencies(contingencies) + { + } + + auto begin() { return m_contingencies.begin(); } + auto end() { return m_contingencies.end(); } + +private: + GameSequenceForm::Contingencies m_contingencies; +}; + } // end namespace Gambit #endif // GAMESEQ_H diff --git a/src/solvers/enumpoly/ndarray.h b/src/games/ndarray.h similarity index 100% rename from src/solvers/enumpoly/ndarray.h rename to src/games/ndarray.h diff --git a/src/solvers/enumpoly/efgpoly.cc b/src/solvers/enumpoly/efgpoly.cc index 8ca2ac2fd..a6775ca82 100644 --- a/src/solvers/enumpoly/efgpoly.cc +++ b/src/solvers/enumpoly/efgpoly.cc @@ -22,7 +22,7 @@ #include "enumpoly.h" #include "solvers/nashsupport/nashsupport.h" -#include "gameseq.h" +#include "games/gameseq.h" #include "polysystem.h" #include "polysolver.h" #include "behavextend.h" @@ -48,7 +48,7 @@ namespace { class ProblemData { public: - GameSequenceForm sfg; + BehaviorSupportProfile m_support; std::shared_ptr space; std::map var; std::map> variables; @@ -62,17 +62,17 @@ Polynomial BuildSequenceVariable(ProblemData &p_data, const GameSequence if (!p_sequence->action) { return {p_data.space, 1}; } - if (p_sequence->action != p_data.sfg.GetSupport().GetActions(p_sequence->GetInfoset()).back()) { + if (p_sequence->action != p_data.m_support.GetActions(p_sequence->GetInfoset()).back()) { return {p_data.space, var.at(p_sequence), 1}; } Polynomial equation(p_data.space); - for (auto seq : p_data.sfg.GetSequences(p_sequence->player)) { + for (auto seq : p_data.m_support.GetSequences(p_sequence->player)) { if (seq == p_sequence) { continue; } if (const int constraint_coef = - p_data.sfg.GetConstraintEntry(p_sequence->GetInfoset(), seq->action)) { + p_data.m_support.GetConstraintEntry(p_sequence->GetInfoset(), seq->action)) { equation += BuildSequenceVariable(p_data, seq, var) * double(constraint_coef); } } @@ -80,18 +80,18 @@ Polynomial BuildSequenceVariable(ProblemData &p_data, const GameSequence } ProblemData::ProblemData(const BehaviorSupportProfile &p_support) - : sfg(p_support), - space(std::make_shared(sfg.GetSequences().size() - sfg.GetInfosets().size() - - sfg.GetPlayers().size())) + : m_support(p_support), space(std::make_shared(m_support.GetSequences().size() - + m_support.GetInfosets().size() - + m_support.GetPlayers().size())) { - for (auto sequence : sfg.GetSequences()) { + for (auto sequence : m_support.GetSequences()) { if (sequence->action && (sequence->action != p_support.GetActions(sequence->GetInfoset()).back())) { var[sequence] = var.size() + 1; } } - for (auto sequence : sfg.GetSequences()) { + for (auto sequence : m_support.GetSequences()) { variables.emplace(sequence, BuildSequenceVariable(*this, sequence, var)); } } @@ -100,11 +100,11 @@ Polynomial GetPayoff(ProblemData &p_data, const GamePlayer &p_player) { Polynomial equation(p_data.space); - for (auto profile : p_data.sfg.GetContingencies()) { - auto pay = p_data.sfg.GetPayoff(profile, p_player); + for (auto profile : p_data.m_support.GetContingencies()) { + auto pay = p_data.m_support.GetPayoff(profile, p_player); if (pay != Rational(0)) { Polynomial term(p_data.space, double(pay)); - for (auto player : p_data.sfg.GetPlayers()) { + for (auto player : p_data.m_support.GetPlayers()) { term *= p_data.variables.at(profile[player]); } equation += term; @@ -115,9 +115,9 @@ Polynomial GetPayoff(ProblemData &p_data, const GamePlayer &p_player) void IndifferenceEquations(ProblemData &p_data, PolynomialSystem &p_equations) { - for (auto player : p_data.sfg.GetPlayers()) { + for (auto player : p_data.m_support.GetPlayers()) { const Polynomial payoff = GetPayoff(p_data, player); - for (auto sequence : p_data.sfg.GetSequences(player)) { + for (auto sequence : p_data.m_support.GetSequences(player)) { try { p_equations.push_back(payoff.PartialDerivative(p_data.var.at(sequence))); } @@ -131,11 +131,11 @@ void IndifferenceEquations(ProblemData &p_data, PolynomialSystem &p_equa void LastActionProbPositiveInequalities(ProblemData &p_data, PolynomialSystem &p_equations) { - for (auto sequence : p_data.sfg.GetSequences()) { + for (auto sequence : p_data.m_support.GetSequences()) { if (!sequence->action) { continue; } - const auto &actions = p_data.sfg.GetSupport().GetActions(sequence->action->GetInfoset()); + const auto &actions = p_data.m_support.GetActions(sequence->action->GetInfoset()); if (actions.size() > 1 && sequence->action == actions.back()) { p_equations.push_back(p_data.variables.at(sequence)); } @@ -145,7 +145,7 @@ void LastActionProbPositiveInequalities(ProblemData &p_data, PolynomialSystem ToSequenceProbs(const ProblemData &p_data, const Vector &v) { std::map x; - for (auto sequence : p_data.sfg.GetSequences()) { + for (auto sequence : p_data.m_support.GetSequences()) { x[sequence] = p_data.variables.at(sequence).Evaluate(v); } return x; @@ -181,7 +181,7 @@ std::list> SolveSupport(const BehaviorSupportProfil std::list> solutions; for (auto root : roots) { const MixedBehaviorProfile sol( - data.sfg.ToMixedBehaviorProfile(ToSequenceProbs(data, root))); + data.m_support.ToMixedBehaviorProfile(ToSequenceProbs(data, root))); if (ExtendsToNash(sol, BehaviorSupportProfile(sol.GetGame()), BehaviorSupportProfile(sol.GetGame()))) { solutions.push_back(sol);