Skip to content

Commit 25846d4

Browse files
committed
Merge branch 'issue_483' into integrate_llm
2 parents a889431 + b5a9a88 commit 25846d4

File tree

5 files changed

+85
-104
lines changed

5 files changed

+85
-104
lines changed

src/games/game.cc

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ void GamePlayerRep::MakeStrategy()
123123
Array<int> c(NumInfosets());
124124

125125
for (int i = 1; i <= NumInfosets(); i++) {
126-
if (m_infosets[i]->flag == 1) {
127-
c[i] = m_infosets[i]->whichbranch;
126+
if (m_infosets[i - 1]->flag == 1) {
127+
c[i] = m_infosets[i - 1]->whichbranch;
128128
}
129129
else {
130130
c[i] = 0;
@@ -219,7 +219,7 @@ void GamePlayerRep::MakeReducedStrats(GameTreeNodeRep *n, GameTreeNodeRep *nn)
219219
}
220220
}
221221

222-
GameInfoset GamePlayerRep::GetInfoset(int p_index) const { return m_infosets[p_index]; }
222+
GameInfoset GamePlayerRep::GetInfoset(int p_index) const { return m_infosets[p_index - 1]; }
223223

224224
Array<GameInfoset> GamePlayerRep::GetInfosets() const
225225
{
@@ -400,46 +400,31 @@ template <class T>
400400
MixedStrategyProfile<T>::MixedStrategyProfile(const MixedBehaviorProfile<T> &p_profile)
401401
: m_rep(new TreeMixedStrategyProfileRep<T>(p_profile))
402402
{
403-
Game game = p_profile.GetGame();
404-
auto *efg = dynamic_cast<GameTreeRep *>(game.operator->());
405-
for (int pl = 1; pl <= m_rep->m_support.GetGame()->NumPlayers(); pl++) {
406-
GamePlayer player = m_rep->m_support.GetGame()->GetPlayer(pl);
407-
for (int st = 1; st <= player->NumStrategies(); st++) {
408-
T prob = (T)1;
409-
410-
for (int iset = 1; iset <= efg->GetPlayer(pl)->NumInfosets(); iset++) {
411-
if (efg->m_players[pl]->m_strategies[st]->m_behav[iset] > 0) {
412-
GameInfoset infoset = player->GetInfoset(iset);
413-
prob *=
414-
p_profile[infoset->GetAction(efg->m_players[pl]->m_strategies[st]->m_behav[iset])];
403+
auto *efg = dynamic_cast<GameTreeRep *>(p_profile.GetGame().operator->());
404+
for (const auto &player : efg->m_players) {
405+
for (const auto &strategy : player->m_strategies) {
406+
auto prob = static_cast<T>(1);
407+
for (const auto &infoset : player->m_infosets) {
408+
if (strategy->m_behav[infoset->GetNumber()] > 0) {
409+
prob *= p_profile[infoset->GetAction(strategy->m_behav[infoset->GetNumber()])];
415410
}
416411
}
417-
(*this)[m_rep->m_support.GetGame()->GetPlayer(pl)->GetStrategy(st)] = prob;
412+
(*m_rep)[strategy] = prob;
418413
}
419414
}
420415
}
421416

422-
template <class T>
423-
MixedStrategyProfile<T>::MixedStrategyProfile(const MixedStrategyProfile<T> &p_profile)
424-
: m_rep(p_profile.m_rep->Copy())
425-
{
426-
InvalidateCache();
427-
}
428-
429417
template <class T>
430418
MixedStrategyProfile<T> &
431419
MixedStrategyProfile<T>::operator=(const MixedStrategyProfile<T> &p_profile)
432420
{
433421
if (this != &p_profile) {
434422
InvalidateCache();
435-
delete m_rep;
436-
m_rep = p_profile.m_rep->Copy();
423+
m_rep.reset(p_profile.m_rep->Copy());
437424
}
438425
return *this;
439426
}
440427

441-
template <class T> MixedStrategyProfile<T>::~MixedStrategyProfile() { delete m_rep; }
442-
443428
//========================================================================
444429
// MixedStrategyProfile<T>: General data access
445430
//========================================================================
@@ -449,10 +434,8 @@ template <class T> Vector<T> MixedStrategyProfile<T>::operator[](const GamePlaye
449434
CheckVersion();
450435
auto strategies = m_rep->m_support.GetStrategies(p_player);
451436
Vector<T> probs(strategies.size());
452-
int st = 1;
453-
for (auto strategy : strategies) {
454-
probs[st] = (*this)[strategy];
455-
}
437+
std::transform(strategies.begin(), strategies.end(), probs.begin(),
438+
[this](const GameStrategy &s) { return (*m_rep)[s]; });
456439
return probs;
457440
}
458441

@@ -461,9 +444,10 @@ template <class T> MixedStrategyProfile<T> MixedStrategyProfile<T>::ToFullSuppor
461444
CheckVersion();
462445
MixedStrategyProfile<T> full(m_rep->m_support.GetGame()->NewMixedStrategyProfile(T(0)));
463446

464-
for (auto player : m_rep->m_support.GetGame()->GetPlayers()) {
465-
for (auto strategy : player->GetStrategies()) {
466-
full[strategy] = (m_rep->m_support.Contains(strategy)) ? (*this)[strategy] : T(0);
447+
for (const auto &player : m_rep->m_support.GetGame()->GetPlayers()) {
448+
for (const auto &strategy : player->GetStrategies()) {
449+
full[strategy] =
450+
(m_rep->m_support.Contains(strategy)) ? (*m_rep)[strategy] : static_cast<T>(0);
467451
}
468452
}
469453
return full;
@@ -472,17 +456,18 @@ template <class T> MixedStrategyProfile<T> MixedStrategyProfile<T>::ToFullSuppor
472456
//========================================================================
473457
// MixedStrategyProfile<T>: Computation of interesting quantities
474458
//========================================================================
459+
475460
template <class T> void MixedStrategyProfile<T>::ComputePayoffs() const
476461
{
477462
if (!map_profile_payoffs.empty()) {
478463
// caches (map_profile_payoffs and map_strategy_payoffs) are valid,
479464
// so don't compute anything, simply return
480465
return;
481466
}
482-
for (auto player : m_rep->m_support.GetPlayers()) {
467+
for (const auto &player : m_rep->m_support.GetPlayers()) {
483468
map_profile_payoffs[player] = GetPayoff(player);
484469
// values of the player's strategies
485-
for (auto strategy : m_rep->m_support.GetStrategies(player)) {
470+
for (const auto &strategy : m_rep->m_support.GetStrategies(player)) {
486471
map_strategy_payoffs[player][strategy] = GetPayoff(strategy);
487472
}
488473
}
@@ -493,13 +478,10 @@ template <class T> T MixedStrategyProfile<T>::GetLiapValue() const
493478
CheckVersion();
494479
ComputePayoffs();
495480

496-
T liapValue = T(0);
497-
for (auto player : m_rep->m_support.GetPlayers()) {
481+
auto liapValue = static_cast<T>(0);
482+
for (auto [player, payoff] : map_profile_payoffs) {
498483
for (auto v : map_strategy_payoffs[player]) {
499-
T regret = v.second - map_profile_payoffs[player];
500-
if (regret > T(0)) {
501-
liapValue += regret * regret; // penalty if not best response
502-
}
484+
liapValue += sqr(std::max(v.second - payoff, static_cast<T>(0)));
503485
}
504486
}
505487
return liapValue;

src/games/game.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ class GamePlayerRep : public GameObject {
289289
GameRep *m_game;
290290
int m_number;
291291
std::string m_label;
292-
Array<class GameTreeInfosetRep *> m_infosets;
292+
std::vector<class GameTreeInfosetRep *> m_infosets;
293293
Array<GameStrategyRep *> m_strategies;
294294

295295
GamePlayerRep(GameRep *p_game, int p_id) : m_game(p_game), m_number(p_id) {}

src/games/gametree.cc

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -50,53 +50,44 @@ template <class T> MixedStrategyProfileRep<T> *TreeMixedStrategyProfileRep<T>::C
5050
return new TreeMixedStrategyProfileRep(*this);
5151
}
5252

53-
template <class T> T TreeMixedStrategyProfileRep<T>::GetPayoff(int pl) const
53+
template <class T> void TreeMixedStrategyProfileRep<T>::MakeBehavior() const
5454
{
5555
if (mixed_behav_profile_sptr.get() == nullptr) {
5656
MixedStrategyProfile<T> tmp(Copy());
5757
mixed_behav_profile_sptr = std::make_shared<MixedBehaviorProfile<T>>(tmp);
5858
}
59-
return mixed_behav_profile_sptr->GetPayoff(pl);
6059
}
6160

6261
template <class T> void TreeMixedStrategyProfileRep<T>::InvalidateCache() const
6362
{
6463
mixed_behav_profile_sptr = nullptr;
6564
}
6665

66+
template <class T> T TreeMixedStrategyProfileRep<T>::GetPayoff(int pl) const
67+
{
68+
MakeBehavior();
69+
return mixed_behav_profile_sptr->GetPayoff(pl);
70+
}
71+
6772
template <class T>
6873
T TreeMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, const GameStrategy &strategy) const
6974
{
70-
MixedStrategyProfile<T> foo(Copy());
71-
for (auto s : this->m_support.GetStrategies(this->m_support.GetGame()->GetPlayer(pl))) {
72-
foo[s] = static_cast<T>(0);
73-
}
74-
foo[strategy] = static_cast<T>(1);
75-
return foo.GetPayoff(pl);
75+
TreeMixedStrategyProfileRep tmp(*this);
76+
tmp.SetStrategy(strategy);
77+
return tmp.GetPayoff(pl);
7678
}
7779

7880
template <class T>
7981
T TreeMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, const GameStrategy &strategy1,
8082
const GameStrategy &strategy2) const
8183
{
82-
GamePlayerRep *player1 = strategy1->GetPlayer();
83-
GamePlayerRep *player2 = strategy2->GetPlayer();
84-
if (player1 == player2) {
85-
return T(0);
84+
if (strategy1->GetPlayer() == strategy2->GetPlayer()) {
85+
return static_cast<T>(0);
8686
}
87-
88-
MixedStrategyProfile<T> foo(Copy());
89-
for (auto strategy : this->m_support.GetStrategies(player1)) {
90-
foo[strategy] = T(0);
91-
}
92-
foo[strategy1] = T(1);
93-
94-
for (auto strategy : this->m_support.GetStrategies(player2)) {
95-
foo[strategy] = T(0);
96-
}
97-
foo[strategy2] = T(1);
98-
99-
return foo.GetPayoff(pl);
87+
TreeMixedStrategyProfileRep tmp(*this);
88+
tmp.SetStrategy(strategy1);
89+
tmp.SetStrategy(strategy2);
90+
return tmp.GetPayoff(pl);
10091
}
10192

10293
template class TreeMixedStrategyProfileRep<double>;
@@ -731,9 +722,9 @@ bool GameTreeRep::IsPerfectRecall(GameInfoset &s1, GameInfoset &s2) const
731722
{
732723
for (auto player : m_players) {
733724
for (int i = 1; i <= player->NumInfosets(); i++) {
734-
GameTreeInfosetRep *iset1 = player->m_infosets[i];
725+
GameTreeInfosetRep *iset1 = player->m_infosets[i - 1];
735726
for (int j = 1; j <= player->NumInfosets(); j++) {
736-
GameTreeInfosetRep *iset2 = player->m_infosets[j];
727+
GameTreeInfosetRep *iset2 = player->m_infosets[j - 1];
737728

738729
bool precedes = false;
739730
int action = 0;
@@ -800,7 +791,7 @@ void GameTreeRep::SortInfosets()
800791
// Coded using a bubble sort for simplicity; large games might
801792
// find a quicksort worthwhile.
802793
for (int iset = 1; iset <= player->m_infosets.size(); iset++) {
803-
GameTreeInfosetRep *infoset = player->m_infosets[iset];
794+
GameTreeInfosetRep *infoset = player->m_infosets[iset - 1];
804795
for (int i = 1; i < infoset->m_members.size(); i++) {
805796
for (int j = 1; j < infoset->m_members.size() - i; j++) {
806797
if (infoset->m_members[j + 1]->m_number < infoset->m_members[j]->m_number) {
@@ -817,24 +808,24 @@ void GameTreeRep::SortInfosets()
817808
// find a quicksort worthwhile.
818809
for (int i = 1; i < player->m_infosets.size(); i++) {
819810
for (int j = 1; j < player->m_infosets.size() - i; j++) {
820-
int a = ((player->m_infosets[j + 1]->m_members.size())
821-
? player->m_infosets[j + 1]->m_members[1]->m_number
822-
: 0);
823-
int b = ((player->m_infosets[j]->m_members.size())
811+
int a = ((player->m_infosets[j]->m_members.size())
824812
? player->m_infosets[j]->m_members[1]->m_number
825813
: 0);
814+
int b = ((player->m_infosets[j - 1]->m_members.size())
815+
? player->m_infosets[j - 1]->m_members[1]->m_number
816+
: 0);
826817

827818
if (a < b || b == 0) {
828-
GameTreeInfosetRep *tmp = player->m_infosets[j];
829-
player->m_infosets[j] = player->m_infosets[j + 1];
830-
player->m_infosets[j + 1] = tmp;
819+
GameTreeInfosetRep *tmp = player->m_infosets[j - 1];
820+
player->m_infosets[j - 1] = player->m_infosets[j];
821+
player->m_infosets[j] = tmp;
831822
}
832823
}
833824
}
834825

835826
// Reassign information set IDs
836827
for (int iset = 1; iset <= player->m_infosets.size(); iset++) {
837-
player->m_infosets[iset]->m_number = iset;
828+
player->m_infosets[iset - 1]->m_number = iset;
838829
}
839830
}
840831
}

src/games/gametree.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,11 @@ template <class T> class TreeMixedStrategyProfileRep : public MixedStrategyProfi
313313
T GetPayoffDeriv(int pl, const GameStrategy &) const override;
314314
T GetPayoffDeriv(int pl, const GameStrategy &, const GameStrategy &) const override;
315315

316-
void InvalidateCache() const override;
317-
318-
protected:
316+
private:
319317
mutable std::shared_ptr<MixedBehaviorProfile<T>> mixed_behav_profile_sptr;
318+
319+
void MakeBehavior() const;
320+
void InvalidateCache() const override;
320321
};
321322

322323
} // namespace Gambit

src/games/stratmixed.h

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ template <class T> class MixedStrategyProfileRep {
5050
}
5151
/// Returns the probability the strategy is played
5252
T &operator[](const GameStrategy &p_strategy) { return m_probs[m_profileIndex.at(p_strategy)]; }
53+
/// Set the strategy of the corresponding player to a pure strategy
54+
void SetStrategy(const GameStrategy &p_strategy)
55+
{
56+
for (const auto &s : m_support.GetStrategies(p_strategy->GetPlayer())) {
57+
(*this)[s] = static_cast<T>(0);
58+
}
59+
(*this)[p_strategy] = static_cast<T>(1);
60+
}
5361

5462
virtual T GetPayoff(int pl) const = 0;
5563
virtual T GetPayoffDeriv(int pl, const GameStrategy &) const = 0;
@@ -65,7 +73,7 @@ template <class T> class MixedStrategyProfileRep {
6573
T GetRegret(const GamePlayer &) const;
6674
T GetMaxRegret() const;
6775

68-
virtual void InvalidateCache() const {};
76+
virtual void InvalidateCache() const {}
6977
};
7078

7179
/// \brief A probability distribution over strategies in a game
@@ -75,14 +83,9 @@ template <class T> class MixedStrategyProfileRep {
7583
/// probabilities.
7684
template <class T> class MixedStrategyProfile {
7785
private:
78-
MixedStrategyProfileRep<T> *m_rep;
79-
80-
public:
81-
/// @name Lifecycle
82-
//@{
83-
explicit MixedStrategyProfile(MixedStrategyProfileRep<T> *p_rep) : m_rep(p_rep) {}
84-
/// Convert a behavior strategy profile to a mixed strategy profile
85-
explicit MixedStrategyProfile(const MixedBehaviorProfile<T> &);
86+
std::unique_ptr<MixedStrategyProfileRep<T>> m_rep;
87+
mutable std::map<GamePlayer, std::map<GameStrategy, T>> map_strategy_payoffs;
88+
mutable std::map<GamePlayer, T> map_profile_payoffs;
8689

8790
/// Check underlying game has not changed; raise exception if it has
8891
void CheckVersion() const
@@ -91,14 +94,29 @@ template <class T> class MixedStrategyProfile {
9194
throw GameStructureChangedException();
9295
}
9396
}
97+
/// Used to read payoffs from cache or compute them and cache them if needed
98+
void ComputePayoffs() const;
99+
100+
/// Reset cache for payoffs and strategy values
101+
void InvalidateCache() const
102+
{
103+
map_strategy_payoffs.clear();
104+
map_profile_payoffs.clear();
105+
m_rep->InvalidateCache();
106+
}
94107

95108
public:
96109
/// @name Lifecycle
97110
//@{
111+
explicit MixedStrategyProfile(MixedStrategyProfileRep<T> *p_rep) : m_rep(p_rep) {}
112+
/// Convert a behavior strategy profile to a mixed strategy profile
113+
explicit MixedStrategyProfile(const MixedBehaviorProfile<T> &);
98114
/// Make a copy of the mixed strategy profile
99-
MixedStrategyProfile(const MixedStrategyProfile<T> &);
115+
MixedStrategyProfile(const MixedStrategyProfile<T> &p_profile) : m_rep(p_profile.m_rep->Copy())
116+
{
117+
}
100118
/// Destructor
101-
virtual ~MixedStrategyProfile();
119+
~MixedStrategyProfile() = default;
102120

103121
MixedStrategyProfile<T> &operator=(const MixedStrategyProfile<T> &);
104122
MixedStrategyProfile<T> &operator=(const Vector<T> &v)
@@ -209,17 +227,6 @@ template <class T> class MixedStrategyProfile {
209227

210228
/// @name Computation of interesting quantities
211229
//@{
212-
/// Used to read payoffs from cache or compute them and cache them if needed
213-
void ComputePayoffs() const;
214-
mutable std::map<GamePlayer, std::map<GameStrategy, T>> map_strategy_payoffs;
215-
mutable std::map<GamePlayer, T> map_profile_payoffs;
216-
/// Reset cache for payoffs and strategy values
217-
virtual void InvalidateCache() const
218-
{
219-
map_strategy_payoffs.clear();
220-
map_profile_payoffs.clear();
221-
m_rep->InvalidateCache();
222-
}
223230

224231
/// Computes the payoff of the profile to player 'pl'
225232
T GetPayoff(int pl) const

0 commit comments

Comments
 (0)