Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
724e889
Rebased onto lastest master
StephenPasteris Nov 3, 2025
c327bd2
Moved indexproduct.h back to enumpoly
StephenPasteris Nov 11, 2025
2b80cec
Made one-liners in wrapper methods
StephenPasteris Nov 11, 2025
451ba0c
Changed GameSequenceRep from struct to class
StephenPasteris Nov 11, 2025
54f33c7
Defined GetReachableInfosets()
StephenPasteris Nov 12, 2025
a78b64f
reset m_reachable to nullptr during addition or removal of actions
StephenPasteris Nov 12, 2025
f5dbc77
fixed issue with FindReachableInfosets
StephenPasteris Nov 12, 2025
c3172d3
changed *m_reachable from set to map
StephenPasteris Nov 12, 2025
be771f5
Made Infosets class
StephenPasteris Nov 12, 2025
2354b97
Removed InfosetsWrapper
StephenPasteris Nov 12, 2025
d71a2a6
Added PlayerSequences to BehaviorSupportProfile
StephenPasteris Nov 12, 2025
16821e9
Added Sequences to BehaviorSupportProfile
StephenPasteris Nov 13, 2025
ee0441b
Added Contingencies to BehaviorSupportProfile
StephenPasteris Nov 13, 2025
574664e
Removed wrapper classes
StephenPasteris Nov 13, 2025
a1b343e
Moved ToMixedBehaviorProfile into BehaviorSupportProfile
StephenPasteris Nov 13, 2025
448762f
Removed nested classes from GameSequenceForm
StephenPasteris Nov 13, 2025
65a4519
Renamed m_reachable m_reachableInfosets
StephenPasteris Nov 14, 2025
c28a6aa
Made m_reachableInfosets consistent with m_infosetReachable
StephenPasteris Nov 14, 2025
6a1b586
Used brace initialisation
StephenPasteris Nov 14, 2025
2ec1dcf
Moved PlayerSequences into behavspt.h
StephenPasteris Nov 18, 2025
1ab5af5
changed attribute in Sequences to BehaviorSupportProfile
StephenPasteris Nov 18, 2025
fca0af5
changed attribute in Contingencies to BehaviorSupportProfile
StephenPasteris Nov 18, 2025
97603ac
renamed Contingencies and GetContingencies to SequenceContingencies a…
StephenPasteris Nov 18, 2025
bbcc097
Moved Sequences into behavspt.h
StephenPasteris Nov 18, 2025
560917b
Moved SequenceContingencies into behavspt.h
StephenPasteris Nov 18, 2025
4aceb2e
Removed behavsptseqform.h
StephenPasteris Nov 18, 2025
821ce92
Minor cleanups
tturocy Nov 18, 2025
8f0cbcd
Promote GameSequence to be a GameObject
tturocy Nov 18, 2025
bc656aa
Address clang-tidy error.
tturocy Nov 18, 2025
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
195 changes: 179 additions & 16 deletions src/games/behavspt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ size_t BehaviorSupportProfile::BehaviorProfileLength() const

void BehaviorSupportProfile::AddAction(const GameAction &p_action)
{
m_reachableInfosets = nullptr;
auto &support = m_actions.at(p_action->GetInfoset());
auto pos = std::find_if(support.begin(), support.end(), [p_action](const GameAction &a) {
return a->GetNumber() >= p_action->GetNumber();
Expand All @@ -81,6 +82,7 @@ void BehaviorSupportProfile::AddAction(const GameAction &p_action)

bool BehaviorSupportProfile::RemoveAction(const GameAction &p_action)
{
m_reachableInfosets = nullptr;
auto &support = m_actions.at(p_action->GetInfoset());
auto pos = std::find(support.begin(), support.end(), p_action);
if (pos != support.end()) {
Expand Down Expand Up @@ -272,14 +274,12 @@ std::shared_ptr<GameSequenceForm> BehaviorSupportProfile::GetSequenceForm() cons
return m_sequenceForm;
}

SequencesWrapper BehaviorSupportProfile::GetSequences() const
{
return SequencesWrapper(GetSequenceForm()->GetSequences());
}
BehaviorSupportProfile::Sequences BehaviorSupportProfile::GetSequences() const { return {this}; }

PlayerSequencesWrapper BehaviorSupportProfile::GetSequences(GamePlayer &p_player) const
BehaviorSupportProfile::PlayerSequences
BehaviorSupportProfile::GetSequences(GamePlayer &p_player) const
{
return PlayerSequencesWrapper(GetSequenceForm()->GetSequences(p_player));
return {this, p_player};
}

int BehaviorSupportProfile::GetConstraintEntry(const GameInfoset &p_infoset,
Expand All @@ -288,27 +288,190 @@ int BehaviorSupportProfile::GetConstraintEntry(const GameInfoset &p_infoset,
return GetSequenceForm()->GetConstraintEntry(p_infoset, p_action);
}

const Rational &BehaviorSupportProfile::GetPayoff(
const std::map<GamePlayer, std::shared_ptr<GameSequenceRep>> &p_profile,
const GamePlayer &p_player) const
const Rational &
BehaviorSupportProfile::GetPayoff(const std::map<GamePlayer, GameSequence> &p_profile,
const GamePlayer &p_player) const
{
return GetSequenceForm()->GetPayoff(p_profile, p_player);
}

MixedBehaviorProfile<double> BehaviorSupportProfile::ToMixedBehaviorProfile(
const std::map<std::shared_ptr<GameSequenceRep>, double> &p_profile) const
BehaviorSupportProfile::SequenceContingencies
BehaviorSupportProfile::GetSequenceContingencies() const
{
return {this};
}

MixedBehaviorProfile<double>
BehaviorSupportProfile::ToMixedBehaviorProfile(const std::map<GameSequence, double> &x) const
{
return GetSequenceForm()->ToMixedBehaviorProfile(p_profile);
MixedBehaviorProfile<double> b(*this);
for (auto sequence : GetSequences()) {
if (sequence->action == nullptr) {
continue;
}
const double parent_prob = x.at(sequence->parent.lock());
if (parent_prob > 0) {
b[sequence->action] = x.at(sequence) / parent_prob;
}
else {
b[sequence->action] = 0;
}
}
return b;
}

InfosetsWrapper BehaviorSupportProfile::GetInfosets() const
size_t BehaviorSupportProfile::Sequences::size() const
{
return InfosetsWrapper(GetSequenceForm()->GetInfosets());
return std::accumulate(m_support->GetSequenceForm()->m_sequences.cbegin(),
m_support->GetSequenceForm()->m_sequences.cend(), 0,
[](int acc, const std::pair<GamePlayer, std::vector<GameSequence>> &seq) {
return acc + seq.second.size();
});
}

ContingenciesWrapper BehaviorSupportProfile::GetContingencies() const
BehaviorSupportProfile::Sequences::iterator BehaviorSupportProfile::Sequences::begin() const
{
return ContingenciesWrapper(GetSequenceForm()->GetContingencies());
return {m_support->GetSequenceForm(), false};
}
BehaviorSupportProfile::Sequences::iterator BehaviorSupportProfile::Sequences::end() const
{
return {m_support->GetSequenceForm(), true};
}

BehaviorSupportProfile::Sequences::iterator::iterator(
const std::shared_ptr<GameSequenceForm> p_sfg, bool p_end)
: m_sfg(p_sfg)
{
if (p_end) {
m_currentPlayer = m_sfg->m_sequences.cend();
}
else {
m_currentPlayer = m_sfg->m_sequences.cbegin();
m_currentSequence = m_currentPlayer->second.cbegin();
}
}

BehaviorSupportProfile::Sequences::iterator &
BehaviorSupportProfile::Sequences::iterator::operator++()
{
if (m_currentPlayer == m_sfg->m_sequences.cend()) {
return *this;
}
m_currentSequence++;
if (m_currentSequence != m_currentPlayer->second.cend()) {
return *this;
}
m_currentPlayer++;
if (m_currentPlayer != m_sfg->m_sequences.cend()) {
m_currentSequence = m_currentPlayer->second.cbegin();
}
return *this;
}

bool BehaviorSupportProfile::Sequences::iterator::operator==(const iterator &it) const
{
if (m_sfg != it.m_sfg || m_currentPlayer != it.m_currentPlayer) {
return false;
}
if (m_currentPlayer == m_sfg->m_sequences.end()) {
return true;
}
return (m_currentSequence == it.m_currentSequence);
}

std::vector<GameSequence>::const_iterator BehaviorSupportProfile::PlayerSequences::begin() const
{
return m_support->GetSequenceForm()->m_sequences.at(m_player).begin();
}

std::vector<GameSequence>::const_iterator BehaviorSupportProfile::PlayerSequences::end() const
{
return m_support->GetSequenceForm()->m_sequences.at(m_player).end();
}

size_t BehaviorSupportProfile::PlayerSequences::size() const
{
return m_support->GetSequenceForm()->m_sequences.at(m_player).size();
}

BehaviorSupportProfile::SequenceContingencies::iterator::iterator(
const std::shared_ptr<GameSequenceForm> p_sfg, bool p_end)
: m_sfg(p_sfg), m_end(p_end)
{
for (auto [player, sequences] : m_sfg->m_sequences) {
m_indices[player] = 0;
}
}

std::map<GamePlayer, GameSequence>
BehaviorSupportProfile::SequenceContingencies::iterator::operator*() const
{
std::map<GamePlayer, GameSequence> ret;
for (auto [player, index] : m_indices) {
ret[player] = m_sfg->m_sequences.at(player)[index];
}
return ret;
}

std::map<GamePlayer, GameSequence>
BehaviorSupportProfile::SequenceContingencies::iterator::operator->() const
{
std::map<GamePlayer, GameSequence> ret;
for (auto [player, index] : m_indices) {
ret[player] = m_sfg->m_sequences.at(player)[index];
}
return ret;
}

BehaviorSupportProfile::SequenceContingencies::iterator &
BehaviorSupportProfile::SequenceContingencies::iterator::operator++()
{
for (auto [player, index] : m_indices) {
if (index < m_sfg->m_sequences.at(player).size() - 1) {
m_indices[player]++;
return *this;
}
m_indices[player] = 0;
}
m_end = true;
return *this;
}

//========================================================================
// BehaviorSupportProfile: Reachable Information Sets
//========================================================================

void BehaviorSupportProfile::FindReachableInfosets(GameNode p_node) const
{
if (!p_node->IsTerminal()) {
auto infoset = p_node->GetInfoset();
(*m_reachableInfosets)[infoset] = true;
if (p_node->GetPlayer()->IsChance()) {
for (auto action : infoset->GetActions()) {
FindReachableInfosets(p_node->GetChild(action));
}
}
else {
for (auto action : GetActions(infoset)) {
FindReachableInfosets(p_node->GetChild(action));
}
}
}
}

std::shared_ptr<std::map<GameInfoset, bool>> BehaviorSupportProfile::GetReachableInfosets() const
{
if (!m_reachableInfosets) {
m_reachableInfosets = std::make_shared<std::map<GameInfoset, bool>>();
for (size_t pl = 0; pl <= GetGame()->NumPlayers(); pl++) {
const GamePlayer player = (pl == 0) ? GetGame()->GetChance() : GetGame()->GetPlayer(pl);
for (const auto &infoset : player->GetInfosets()) {
(*m_reachableInfosets)[infoset] = false;
}
}
FindReachableInfosets(GetGame()->GetRoot());
}
return m_reachableInfosets;
}

} // end namespace Gambit
121 changes: 109 additions & 12 deletions src/games/behavspt.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
namespace Gambit {

class GameSequenceForm;
class GameSequenceRep;
class SequencesWrapper;
class PlayerSequencesWrapper;
class InfosetsWrapper;
Expand All @@ -44,9 +43,10 @@ class ContingenciesWrapper;
/// computational approaches that enumerate possible equilibrium
/// supports.
class BehaviorSupportProfile {
protected:
Game m_efg;
std::map<GameInfoset, std::vector<GameAction>> m_actions;
mutable std::shared_ptr<GameSequenceForm> m_sequenceForm;
mutable std::shared_ptr<std::map<GameInfoset, bool>> m_reachableInfosets;

std::map<GameInfoset, bool> m_infosetReachable;
std::map<GameNode, bool> m_nonterminalReachable;
Expand All @@ -57,7 +57,6 @@ class BehaviorSupportProfile {

public:
class Support {
private:
const BehaviorSupportProfile *m_profile;
GameInfoset m_infoset;

Expand Down Expand Up @@ -147,19 +146,117 @@ class BehaviorSupportProfile {
BehaviorSupportProfile Undominated(bool p_strict) const;
//@}

mutable std::shared_ptr<GameSequenceForm> m_sequenceForm;
class Infosets {
const BehaviorSupportProfile *m_support;

public:
Infosets(const BehaviorSupportProfile *p_support) : m_support(p_support) {}

size_t size() const
{
auto reachable_infosets = m_support->GetReachableInfosets();
size_t count = 0;
for (auto [infoset, is_reachable] : *reachable_infosets) {
if (is_reachable && !infoset->GetPlayer()->IsChance()) {
++count;
}
}
return count;
}
};

class Sequences {
const BehaviorSupportProfile *m_support;

public:
class iterator {
const std::shared_ptr<GameSequenceForm> m_sfg;
std::map<GamePlayer, std::vector<GameSequence>>::const_iterator m_currentPlayer;
std::vector<GameSequence>::const_iterator m_currentSequence;

public:
iterator(const std::shared_ptr<GameSequenceForm> p_sfg, bool p_end);

GameSequence operator*() const { return *m_currentSequence; }
GameSequence operator->() const { return *m_currentSequence; }

iterator &operator++();

bool operator==(const iterator &it) const;
bool operator!=(const iterator &it) const { return !(*this == it); }
};

Sequences(const BehaviorSupportProfile *p_support) : m_support(p_support) {}

size_t size() const;

iterator begin() const;
iterator end() const;
};

class PlayerSequences {
const BehaviorSupportProfile *m_support;
GamePlayer m_player;

public:
PlayerSequences(const BehaviorSupportProfile *p_support, const GamePlayer &p_player)
: m_support(p_support), m_player(p_player)
{
}

size_t size() const;
std::vector<GameSequence>::const_iterator begin() const;
std::vector<GameSequence>::const_iterator end() const;
};

class SequenceContingencies {
const BehaviorSupportProfile *m_support;

public:
SequenceContingencies(const BehaviorSupportProfile *p_support) : m_support(p_support) {}

class iterator {
private:
const std::shared_ptr<GameSequenceForm> m_sfg;
bool m_end{false};
std::map<GamePlayer, size_t> m_indices;

public:
using iterator_category = std::input_iterator_tag;

iterator(const std::shared_ptr<GameSequenceForm> p_sfg, bool p_end = false);

std::map<GamePlayer, GameSequence> operator*() const;

std::map<GamePlayer, GameSequence> operator->() const;

iterator &operator++();

bool operator==(const iterator &it) const
{
return (m_end == it.m_end && m_sfg == it.m_sfg && m_indices == it.m_indices);
}
bool operator!=(const iterator &it) const { return !(*this == it); }
};

iterator begin() { return {m_support->GetSequenceForm()}; }
iterator end() { return {m_support->GetSequenceForm(), true}; }
};

std::shared_ptr<GameSequenceForm> GetSequenceForm() const;
SequencesWrapper GetSequences() const;
PlayerSequencesWrapper GetSequences(GamePlayer &p_player) const;
Sequences GetSequences() const;
PlayerSequences GetSequences(GamePlayer &p_player) const;
int GetConstraintEntry(const GameInfoset &p_infoset, const GameAction &p_action) const;
const Rational &
GetPayoff(const std::map<GamePlayer, std::shared_ptr<GameSequenceRep>> &p_profile,
const GamePlayer &p_player) const;
const Rational &GetPayoff(const std::map<GamePlayer, GameSequence> &p_profile,
const GamePlayer &p_player) const;
GameRep::Players GetPlayers() const { return GetGame()->GetPlayers(); }
MixedBehaviorProfile<double>
ToMixedBehaviorProfile(const std::map<std::shared_ptr<GameSequenceRep>, double> &) const;
InfosetsWrapper GetInfosets() const;
ContingenciesWrapper GetContingencies() const;
ToMixedBehaviorProfile(const std::map<GameSequence, double> &) const;
Infosets GetInfosets() const { return {this}; };
SequenceContingencies GetSequenceContingencies() const;

void FindReachableInfosets(GameNode p_node) const;
std::shared_ptr<std::map<GameInfoset, bool>> GetReachableInfosets() const;
};

} // end namespace Gambit
Expand Down
Loading
Loading