Skip to content

Commit 2aedf8d

Browse files
authored
Develop generic nested container range, use for strategies (#683)
Extends the nested range developed for information sets to a generic template, and uses it also to iterate the strategies of a game.
1 parent 2514b63 commit 2aedf8d

File tree

18 files changed

+247
-279
lines changed

18 files changed

+247
-279
lines changed

src/core/array.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ template <class T> class Array {
9494
void erase(iterator pos) { m_data.erase(pos); }
9595
void push_back(const T &value) { m_data.push_back(value); }
9696
void pop_back() { m_data.pop_back(); }
97+
void reserve(size_t len) { m_data.reserve(len); }
9798
};
9899

99100
/// Convenience function to erase the element at `p_index`

src/core/function.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ using namespace Gambit;
4343
// vector perpendicular to the plane, then subtracting to compute the
4444
// component parallel to the plane.)
4545
//
46-
void FunctionOnSimplices::Project(Vector<double> &x, const Array<int> &lengths) const
46+
void FunctionOnSimplices::Project(Vector<double> &x, const Array<size_t> &lengths) const
4747
{
4848
int index = 1;
4949
for (size_t part = 1; part <= lengths.size(); part++) {

src/core/function.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class FunctionOnSimplices : public Function {
4242

4343
protected:
4444
// Project the gradient 'x' onto the plane of the product of simplices.
45-
void Project(Vector<double> &x, const Array<int> &lengths) const;
45+
void Project(Vector<double> &x, const Array<size_t> &lengths) const;
4646
};
4747

4848
class FunctionMinimizerError : public std::runtime_error {

src/games/game.h

Lines changed: 36 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -818,39 +818,6 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
818818
throw UndefinedException();
819819
}
820820

821-
/// @name Dimensions of the game
822-
//@{
823-
/// The number of strategies for each player
824-
virtual Array<int> NumStrategies() const = 0;
825-
/// Gets the i'th strategy in the game, numbered globally
826-
virtual GameStrategy GetStrategy(int p_index) const = 0;
827-
/// Creates a new strategy for the player
828-
virtual GameStrategy NewStrategy(const GamePlayer &p_player, const std::string &p_label)
829-
{
830-
throw UndefinedException();
831-
}
832-
/// Remove the strategy from the game
833-
virtual void DeleteStrategy(const GameStrategy &p_strategy) { throw UndefinedException(); }
834-
/// Returns the number of strategy contingencies in the game
835-
int NumStrategyContingencies() const
836-
{
837-
BuildComputedValues();
838-
return std::transform_reduce(
839-
m_players.begin(), m_players.end(), 0, std::multiplies<>(),
840-
[](const std::shared_ptr<GamePlayerRep> &p) { return p->m_strategies.size(); });
841-
}
842-
/// Returns the total number of actions in the game
843-
virtual int BehavProfileLength() const = 0;
844-
/// Returns the total number of strategies in the game
845-
int MixedProfileLength() const
846-
{
847-
BuildComputedValues();
848-
return std::transform_reduce(
849-
m_players.begin(), m_players.end(), 0, std::plus<>(),
850-
[](const std::shared_ptr<GamePlayerRep> &p) { return p->m_strategies.size(); });
851-
}
852-
//@}
853-
854821
virtual PureStrategyProfile NewPureStrategyProfile() const = 0;
855822
virtual MixedStrategyProfile<double> NewMixedStrategyProfile(double) const = 0;
856823
virtual MixedStrategyProfile<Rational> NewMixedStrategyProfile(const Rational &) const = 0;
@@ -899,14 +866,48 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
899866
virtual GamePlayer NewPlayer() = 0;
900867
//@}
901868

869+
/// @name Dimensions of the game
870+
//@{
871+
using Strategies =
872+
NestedElementCollection<Game, &GameRep::GetPlayers, &GamePlayerRep::GetStrategies>;
873+
/// Returns the set of strategies in the game
874+
Strategies GetStrategies() const
875+
{
876+
BuildComputedValues();
877+
return Strategies(std::const_pointer_cast<GameRep>(this->shared_from_this()));
878+
}
879+
/// Gets the i'th strategy in the game, numbered globally starting from 1
880+
GameStrategy GetStrategy(const std::size_t p_index) const
881+
{
882+
const auto strategies = GetStrategies();
883+
if (p_index < 1 || p_index > strategies.size()) {
884+
throw std::out_of_range("Strategy index out of range");
885+
}
886+
return *std::next(strategies.begin(), p_index - 1);
887+
}
888+
/// Creates a new strategy for the player
889+
virtual GameStrategy NewStrategy(const GamePlayer &p_player, const std::string &p_label)
890+
{
891+
throw UndefinedException();
892+
}
893+
/// Remove the strategy from the game
894+
virtual void DeleteStrategy(const GameStrategy &p_strategy) { throw UndefinedException(); }
895+
/// Returns the total number of actions in the game
896+
virtual int BehavProfileLength() const = 0;
897+
//@}
898+
902899
/// @name Information sets
903900
//@{
904-
class Infosets;
901+
using Infosets =
902+
NestedElementCollection<Game, &GameRep::GetPlayers, &GamePlayerRep::GetInfosets>;
905903

906904
/// Returns the iset'th information set in the game (numbered globally)
907905
virtual GameInfoset GetInfoset(int iset) const { throw UndefinedException(); }
908906
/// Returns the set of information sets in the game
909-
virtual Infosets GetInfosets() const;
907+
virtual Infosets GetInfosets() const
908+
{
909+
return Infosets(std::const_pointer_cast<GameRep>(this->shared_from_this()));
910+
}
910911
/// Sort the information sets for each player in a canonical order
911912
virtual void SortInfosets() {}
912913
/// Returns the set of actions taken by the infoset's owner before reaching this infoset
@@ -958,83 +959,6 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
958959
virtual void BuildComputedValues() const {}
959960
};
960961

961-
class GameRep::Infosets {
962-
Players m_players;
963-
964-
public:
965-
explicit Infosets(const Players &outer) : m_players(outer) {}
966-
967-
class iterator {
968-
using OuterIter = Players::iterator;
969-
using InnerIter = GamePlayerRep::Infosets::iterator;
970-
971-
OuterIter m_playerIterator, m_playerEnd;
972-
InnerIter m_infosetIterator, m_infosetEnd;
973-
974-
void next()
975-
{
976-
while (m_playerIterator != m_playerEnd && m_infosetIterator == m_infosetEnd) {
977-
++m_playerIterator;
978-
if (m_playerIterator != m_playerEnd) {
979-
auto infosets = (*m_playerIterator)->GetInfosets();
980-
m_infosetIterator = infosets.begin();
981-
m_infosetEnd = infosets.end();
982-
}
983-
}
984-
}
985-
986-
public:
987-
using iterator_category = std::forward_iterator_tag;
988-
using value_type = GameInfoset;
989-
using reference = GameInfoset;
990-
using pointer = GameInfoset;
991-
using difference_type = std::ptrdiff_t;
992-
993-
iterator() = default;
994-
995-
iterator(const OuterIter &p_playerIterator, const OuterIter &p_playerEnd)
996-
: m_playerIterator(p_playerIterator), m_playerEnd(p_playerEnd)
997-
{
998-
if (m_playerIterator != m_playerEnd) {
999-
const auto infosets = (*m_playerIterator)->GetInfosets();
1000-
m_infosetIterator = infosets.begin();
1001-
m_infosetEnd = infosets.end();
1002-
}
1003-
next();
1004-
}
1005-
1006-
reference operator*() const { return *m_infosetIterator; }
1007-
pointer operator->() const { return *m_infosetIterator; }
1008-
1009-
iterator &operator++()
1010-
{
1011-
++m_infosetIterator;
1012-
next();
1013-
return *this;
1014-
}
1015-
1016-
iterator operator++(int)
1017-
{
1018-
iterator tmp = *this;
1019-
++(*this);
1020-
return tmp;
1021-
}
1022-
1023-
friend bool operator==(const iterator &a, const iterator &b)
1024-
{
1025-
return a.m_playerIterator == b.m_playerIterator &&
1026-
(a.m_playerIterator == a.m_playerEnd || a.m_infosetIterator == b.m_infosetIterator);
1027-
}
1028-
1029-
friend bool operator!=(const iterator &a, const iterator &b) { return !(a == b); }
1030-
};
1031-
1032-
iterator begin() const { return {m_players.begin(), m_players.end()}; }
1033-
iterator end() const { return {m_players.end(), m_players.end()}; }
1034-
};
1035-
1036-
inline GameRep::Infosets GameRep::GetInfosets() const { return Infosets(GetPlayers()); }
1037-
1038962
//=======================================================================
1039963
// Inline members of game representation classes
1040964
//=======================================================================

src/games/gameagg.cc

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -196,32 +196,6 @@ Game GameAGGRep::Copy() const
196196
return ReadAggFile(is);
197197
}
198198

199-
//------------------------------------------------------------------------
200-
// GameAGGRep: Dimensions of the game
201-
//------------------------------------------------------------------------
202-
203-
Array<int> GameAGGRep::NumStrategies() const
204-
{
205-
Array<int> ns;
206-
for (const auto &player : m_players) {
207-
ns.push_back(player->GetStrategies().size());
208-
}
209-
return ns;
210-
}
211-
212-
GameStrategy GameAGGRep::GetStrategy(int p_index) const
213-
{
214-
for (const auto &player : m_players) {
215-
if (static_cast<int>(player->GetStrategies().size()) >= p_index) {
216-
return player->GetStrategy(p_index);
217-
}
218-
else {
219-
p_index -= player->GetStrategies().size();
220-
}
221-
}
222-
throw std::out_of_range("Strategy index out of range");
223-
}
224-
225199
//------------------------------------------------------------------------
226200
// GameAGGRep: Factory functions
227201
//------------------------------------------------------------------------

src/games/gameagg.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ class GameAGGRep : public GameRep {
4646
std::shared_ptr<agg::AGG> GetUnderlyingAGG() const { return aggPtr; }
4747
/// @name Dimensions of the game
4848
//@{
49-
/// The number of strategies for each player
50-
Array<int> NumStrategies() const override;
51-
/// Gets the i'th strategy in the game, numbered globally
52-
GameStrategy GetStrategy(int p_index) const override;
5349
/// Returns the total number of actions in the game
5450
int BehavProfileLength() const override { throw UndefinedException(); }
5551
//@}

src/games/gamebagg.cc

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,16 @@ template <class T> class BAGGMixedStrategyProfileRep : public MixedStrategyProfi
9999
template <class T> T BAGGMixedStrategyProfileRep<T>::GetPayoff(int pl) const
100100
{
101101
auto &g = dynamic_cast<GameBAGGRep &>(*(this->m_support.GetGame()));
102-
std::vector<double> s(g.MixedProfileLength());
103-
Array<int> ns = g.NumStrategies();
102+
std::vector<double> s(g.GetStrategies().size());
103+
const auto ns = g.GetStrategies().shape();
104104
int bplayer = -1, btype = -1;
105105
for (int i = 0, offs = 0; i < g.baggPtr->getNumPlayers(); ++i) {
106106
for (int tp = 0; tp < g.baggPtr->getNumTypes(i); ++tp) {
107107
if (pl == g.baggPtr->typeOffset[i] + tp + 1) {
108108
bplayer = i;
109109
btype = tp;
110110
}
111-
for (int j = 0; j < ns[g.baggPtr->typeOffset[i] + tp + 1]; ++j, ++offs) {
111+
for (int j = 0; j < ns[g.baggPtr->typeOffset[i] + tp]; ++j, ++offs) {
112112
const GameStrategy strategy = this->m_support.GetGame()
113113
->GetPlayer(g.baggPtr->typeOffset[i] + tp + 1)
114114
->GetStrategy(j + 1);
@@ -124,7 +124,7 @@ template <class T>
124124
T BAGGMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, const GameStrategy &ps) const
125125
{
126126
auto &g = dynamic_cast<GameBAGGRep &>(*(this->m_support.GetGame()));
127-
std::vector<double> s(g.MixedProfileLength());
127+
std::vector<double> s(g.GetStrategies().size());
128128
int bplayer = -1, btype = -1;
129129
for (int i = 0; i < g.baggPtr->getNumPlayers(); ++i) {
130130
for (int tp = 0; tp < g.baggPtr->getNumTypes(i); ++tp) {
@@ -163,7 +163,7 @@ T BAGGMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, const GameStrategy &ps1
163163
}
164164

165165
auto &g = dynamic_cast<GameBAGGRep &>(*(this->m_support.GetGame()));
166-
std::vector<double> s(g.MixedProfileLength());
166+
std::vector<double> s(g.GetStrategies().size());
167167
int bplayer = -1, btype = -1;
168168
for (int i = 0; i < g.baggPtr->getNumPlayers(); ++i) {
169169
for (int tp = 0; tp < g.baggPtr->getNumTypes(i); ++tp) {
@@ -236,15 +236,6 @@ Game GameBAGGRep::Copy() const
236236
// GameBAGGRep: Dimensions of the game
237237
//------------------------------------------------------------------------
238238

239-
Array<int> GameBAGGRep::NumStrategies() const
240-
{
241-
Array<int> ns;
242-
for (const auto &player : m_players) {
243-
ns.push_back(player->m_strategies.size());
244-
}
245-
return ns;
246-
}
247-
248239
PureStrategyProfile GameBAGGRep::NewPureStrategyProfile() const
249240
{
250241
return PureStrategyProfile(std::make_shared<BAGGPureStrategyProfileRep>(

src/games/gamebagg.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ class GameBAGGRep : public GameRep {
5353

5454
/// @name Dimensions of the game
5555
//@{
56-
/// The number of strategies for each player
57-
Array<int> NumStrategies() const override;
58-
/// Gets the i'th strategy in the game, numbered globally
59-
GameStrategy GetStrategy(int p_index) const override { throw UndefinedException(); }
6056
/// Returns the total number of actions in the game
6157
int BehavProfileLength() const override { throw UndefinedException(); }
6258
//@}

src/games/gameexpl.cc

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,6 @@ Rational GameExplicitRep::GetMaxPayoff() const
5454
});
5555
}
5656

57-
//------------------------------------------------------------------------
58-
// GameExplicitRep: Dimensions of the game
59-
//------------------------------------------------------------------------
60-
61-
Array<int> GameExplicitRep::NumStrategies() const
62-
{
63-
BuildComputedValues();
64-
Array<int> dim;
65-
for (const auto &player : m_players) {
66-
dim.push_back(player->m_strategies.size());
67-
}
68-
return dim;
69-
}
70-
71-
GameStrategy GameExplicitRep::GetStrategy(int p_index) const
72-
{
73-
BuildComputedValues();
74-
int i = 1;
75-
for (const auto &player : m_players) {
76-
for (const auto &strategy : player->m_strategies) {
77-
if (p_index == i++) {
78-
return strategy;
79-
}
80-
}
81-
}
82-
throw std::out_of_range("Strategy index out of range");
83-
}
84-
8557
//------------------------------------------------------------------------
8658
// GameExplicitRep: Outcomes
8759
//------------------------------------------------------------------------

src/games/gameexpl.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@ class GameExplicitRep : public GameRep {
3939
Rational GetMaxPayoff() const override;
4040
//@}
4141

42-
/// @name Dimensions of the game
43-
//@{
44-
/// The number of strategies for each player
45-
Array<int> NumStrategies() const override;
46-
/// Gets the i'th strategy in the game, numbered globally
47-
GameStrategy GetStrategy(int p_index) const override;
48-
//@}
49-
5042
/// @name Outcomes
5143
//@{
5244
/// Creates a new outcome in the game

0 commit comments

Comments
 (0)