Skip to content

Commit a9fbcf1

Browse files
committed
Modernisation of some MixedStrategyProfile-related operations.
1 parent 107eeaa commit a9fbcf1

File tree

4 files changed

+68
-85
lines changed

4 files changed

+68
-85
lines changed

src/games/game.cc

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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
//========================================================================
@@ -459,9 +444,10 @@ template <class T> MixedStrategyProfile<T> MixedStrategyProfile<T>::ToFullSuppor
459444
CheckVersion();
460445
MixedStrategyProfile<T> full(m_rep->m_support.GetGame()->NewMixedStrategyProfile(T(0)));
461446

462-
for (auto player : m_rep->m_support.GetGame()->GetPlayers()) {
463-
for (auto strategy : player->GetStrategies()) {
464-
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);
465451
}
466452
}
467453
return full;
@@ -470,17 +456,18 @@ template <class T> MixedStrategyProfile<T> MixedStrategyProfile<T>::ToFullSuppor
470456
//========================================================================
471457
// MixedStrategyProfile<T>: Computation of interesting quantities
472458
//========================================================================
459+
473460
template <class T> void MixedStrategyProfile<T>::ComputePayoffs() const
474461
{
475462
if (!map_profile_payoffs.empty()) {
476463
// caches (map_profile_payoffs and map_strategy_payoffs) are valid,
477464
// so don't compute anything, simply return
478465
return;
479466
}
480-
for (auto player : m_rep->m_support.GetPlayers()) {
467+
for (const auto &player : m_rep->m_support.GetPlayers()) {
481468
map_profile_payoffs[player] = GetPayoff(player);
482469
// values of the player's strategies
483-
for (auto strategy : m_rep->m_support.GetStrategies(player)) {
470+
for (const auto &strategy : m_rep->m_support.GetStrategies(player)) {
484471
map_strategy_payoffs[player][strategy] = GetPayoff(strategy);
485472
}
486473
}
@@ -491,13 +478,10 @@ template <class T> T MixedStrategyProfile<T>::GetLiapValue() const
491478
CheckVersion();
492479
ComputePayoffs();
493480

494-
T liapValue = T(0);
495-
for (auto player : m_rep->m_support.GetPlayers()) {
481+
auto liapValue = static_cast<T>(0);
482+
for (auto [player, payoff] : map_profile_payoffs) {
496483
for (auto v : map_strategy_payoffs[player]) {
497-
T regret = v.second - map_profile_payoffs[player];
498-
if (regret > T(0)) {
499-
liapValue += regret * regret; // penalty if not best response
500-
}
484+
liapValue += sqr(std::max(v.second - payoff, static_cast<T>(0)));
501485
}
502486
}
503487
return liapValue;

src/games/gametree.cc

Lines changed: 16 additions & 25 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);
86-
}
87-
88-
MixedStrategyProfile<T> foo(Copy());
89-
for (auto strategy : this->m_support.GetStrategies(player1)) {
90-
foo[strategy] = T(0);
84+
if (strategy1->GetPlayer() == strategy2->GetPlayer()) {
85+
return static_cast<T>(0);
9186
}
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>;

src/games/gametree.h

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

323-
void InvalidateCache() const override;
324-
325-
protected:
323+
private:
326324
mutable std::shared_ptr<MixedBehaviorProfile<T>> mixed_behav_profile_sptr;
325+
326+
void MakeBehavior() const;
327+
void InvalidateCache() const override;
327328
};
328329

329330
} // 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)