Skip to content

Commit

Permalink
Clean up implementation of enumeration of possible Nash supports
Browse files Browse the repository at this point in the history
This cleans up the implementations of the enumeration of possible Nash subsupports:

* The principal enumeration methods are extracted from enumpoly into their own directory.
* Unused or obsolete code has been removed, and some aspects of the implementation have been
  refactored for simplification.
* Enumeration for the strategic game has been experimentally exposed in pygambit.
  • Loading branch information
tturocy committed Jun 26, 2024
1 parent ed3722e commit 0e0b258
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 52 deletions.
2 changes: 1 addition & 1 deletion src/games/behavspt.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class BehaviorSupportProfile {
void AddAction(const GameAction &);
/// Removes the action from the support; returns true if successful.
bool RemoveAction(const GameAction &);
//@}
//@}

/// @name Reachability of nodes and information sets
//@{
Expand Down
4 changes: 1 addition & 3 deletions src/games/stratspt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,6 @@ bool StrategySupportProfile::Overwhelms(const GameStrategy &s, const GameStrateg
// class StrategySupportProfile::const_iterator
//===========================================================================


bool StrategySupportProfile::const_iterator::GoToNext()
{
if (strat != support.NumStrategies(pl)) {
Expand All @@ -417,8 +416,7 @@ bool StrategySupportProfile::const_iterator::GoToNext()
}
}

bool
StrategySupportProfile::const_iterator::IsSubsequentTo(const GameStrategy &s) const
bool StrategySupportProfile::const_iterator::IsSubsequentTo(const GameStrategy &s) const
{
if (pl > s->GetPlayer()->GetNumber()) {
return true;
Expand Down
21 changes: 14 additions & 7 deletions src/games/stratspt.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,19 @@ class StrategySupportProfile {
public:
/// @name Lifecycle
//@{
explicit const_iterator(const StrategySupportProfile &S, int p_pl = 1, int p_st = 1) :
support(S), pl(p_pl), strat(p_st) { }
explicit const_iterator(const StrategySupportProfile &S, int p_pl = 1, int p_st = 1)
: support(S), pl(p_pl), strat(p_st)
{
}
~const_iterator() = default;
//@}

/// @name Operator overloading
//@{
bool operator==(const const_iterator &other) const
{ return (support == other.support && pl == other.pl && strat == other.strat); }
{
return (support == other.support && pl == other.pl && strat == other.strat);
}
bool operator!=(const const_iterator &other) const { return !(*this == other); }
//@}

Expand All @@ -169,14 +173,17 @@ class StrategySupportProfile {
/// Advance to next strategy; return False when advancing past last strategy.
bool GoToNext();
/// Advance to next strategy
const_iterator &operator++() { GoToNext(); return *this; }
const_iterator &operator++()
{
GoToNext();
return *this;
}
//@}

/// @name Access to state information
//@{
GameStrategy operator*() const { return GetStrategy(); }
GameStrategy GetStrategy() const
{ return support.GetStrategy(pl, strat); }
GameStrategy GetStrategy() const { return support.GetStrategy(pl, strat); }
int StrategyIndex() const { return strat; }
GamePlayer GetPlayer() const { return support.GetGame()->GetPlayer(pl); }
int PlayerIndex() const { return pl; }
Expand All @@ -194,7 +201,7 @@ class StrategySupportProfile {
};

const_iterator begin() const { return const_iterator(*this); }
const_iterator end() const { return const_iterator(*this, m_nfg->NumPlayers() + 1); }
const_iterator end() const { return const_iterator(*this, m_nfg->NumPlayers() + 1); }
};

} // end namespace Gambit
Expand Down
5 changes: 2 additions & 3 deletions src/pygambit/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,11 @@ inline Rational to_rational(const char *p_value)
return lexical_cast<Rational>(std::string(p_value));
}

template <class T>
std::list<T *> make_list_of_pointer(const std::list<T> &p_list)
template <class T> std::list<T *> make_list_of_pointer(const std::list<T> &p_list)
{
std::list<T *> result;
for (auto element : p_list) {
result.push_back(new T(element));
}
return result;
}
}
2 changes: 1 addition & 1 deletion src/solvers/enumpoly/poly.imp
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ template <class T> T polynomial<T>::LeadingCoefficient() const
}
}

template <class T> __attribute__((unused)) Gambit::List<T> polynomial<T>::CoefficientList() const
template <class T> Gambit::List<T> polynomial<T>::CoefficientList() const
{
return coeflist;
}
Expand Down
22 changes: 8 additions & 14 deletions src/solvers/nashsupport/efgsupport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ using namespace Gambit;
class ActionCursor {
protected:
BehaviorSupportProfile m_support;
int pl, iset, act;
int pl{1}, iset{1}, act{1};

public:
// Lifecycle
Expand All @@ -46,9 +46,7 @@ class ActionCursor {
GameAction GetAction() const { return m_support.GetAction(pl, iset, act); }
};


ActionCursor::ActionCursor(const BehaviorSupportProfile &p_support)
: m_support(p_support), pl(1), iset(1), act(1)
ActionCursor::ActionCursor(const BehaviorSupportProfile &p_support) : m_support(p_support)
{
Game efg = p_support.GetGame();

Expand All @@ -65,7 +63,6 @@ ActionCursor::ActionCursor(const BehaviorSupportProfile &p_support)
}
}


bool ActionCursor::GoToNext()
{
if (act != m_support.NumActions(pl, iset)) {
Expand Down Expand Up @@ -104,11 +101,9 @@ bool HasActiveActionsAtActiveInfosetsAndNoOthers(const BehaviorSupportProfile &p
return true;
}


void
PossibleNashBehaviorSupports(const BehaviorSupportProfile &p_support,
const ActionCursor &p_cursor,
std::list<BehaviorSupportProfile> &p_list)
void PossibleNashBehaviorSupports(const BehaviorSupportProfile &p_support,
const ActionCursor &p_cursor,
std::list<BehaviorSupportProfile> &p_list)
{
ActionCursor copy(p_cursor);
if (!copy.GoToNext()) {
Expand All @@ -130,15 +125,15 @@ PossibleNashBehaviorSupports(const BehaviorSupportProfile &p_support,
PossibleNashBehaviorSupports(copySupport, copy, p_list);
}

}

} // namespace

//
// TODO: This is a naive implementation that does not take into account
// that removing actions from a support profile can (and often does) lead
// to information sets becoming unreachable.
//
std::shared_ptr<PossibleNashBehaviorSupportsResult> PossibleNashBehaviorSupports(const Game &p_game)
std::shared_ptr<PossibleNashBehaviorSupportsResult>
PossibleNashBehaviorSupports(const Game &p_game)
{
BehaviorSupportProfile support(p_game);
ActionCursor cursor(support);
Expand All @@ -147,4 +142,3 @@ std::shared_ptr<PossibleNashBehaviorSupportsResult> PossibleNashBehaviorSupports
PossibleNashBehaviorSupports(support, cursor, result->m_supports);
return result;
}

17 changes: 1 addition & 16 deletions src/solvers/nashsupport/nashsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class PossibleNashStrategySupportsResult {
// a totally-mixed Nash equilibrium.
std::shared_ptr<PossibleNashStrategySupportsResult> PossibleNashStrategySupports(const Game &);


class PossibleNashBehaviorSupportsResult {
public:
std::list<BehaviorSupportProfile> m_supports;
Expand All @@ -45,18 +44,4 @@ class PossibleNashBehaviorSupportsResult {
// a totally-mixed Nash equilibrium.
std::shared_ptr<PossibleNashBehaviorSupportsResult> PossibleNashBehaviorSupports(const Game &);

// Produce all subsupports that could
// host the path of a behavioral Nash equilibrium. These are subsupports
// that have no strategy, at an active infoset, that is weakly dominated by
// another active strategy, either in the conditional sense (for any active
// node in the infoset) or the unconditional sense. In addition we
// check for domination by strategys that are inactive, but whose activation
// would not activate any currently inactive infosets, so that the
// subsupport resulting from activation is consistent, in the sense
// of having active strategys at all active infosets, and not at other
// infosets.
List<StrategySupportProfile> PossibleNashSubsupports(const StrategySupportProfile &S);



#endif // GAMBIT_SOLVERS_NASHSUPPORT_NASHSUPPORT_H
#endif // GAMBIT_SOLVERS_NASHSUPPORT_NASHSUPPORT_H
11 changes: 4 additions & 7 deletions src/solvers/nashsupport/nfgsupport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ bool AcceptCandidate(const StrategySupportProfile &p_support,
for (int j = 1; j <= strat->GetPlayer()->NumStrategies(); j++) {
GameStrategy other_strat = strat->GetPlayer()->GetStrategy(j);
if (other_strat != strat) {
if (current.Contains(other_strat) &&
current.Dominates(other_strat, strat, false)) {
if (current.Contains(other_strat) && current.Dominates(other_strat, strat, false)) {
return false;
}
current.AddStrategy(other_strat);
Expand Down Expand Up @@ -101,10 +100,10 @@ void PossibleNashSupports(const StrategySupportProfile &p_support,
}
}

} // end anonymous namespace
} // end anonymous namespace


std::shared_ptr<PossibleNashStrategySupportsResult> PossibleNashStrategySupports(const Game &p_game)
std::shared_ptr<PossibleNashStrategySupportsResult>
PossibleNashStrategySupports(const Game &p_game)
{
auto result = std::make_shared<PossibleNashStrategySupportsResult>();
StrategySupportProfile support(p_game);
Expand All @@ -113,5 +112,3 @@ std::shared_ptr<PossibleNashStrategySupportsResult> PossibleNashStrategySupports
PossibleNashSupports(support, sact, cursor, result->m_supports);
return result;
}


0 comments on commit 0e0b258

Please sign in to comment.