Skip to content

Commit ca9256b

Browse files
committed
Remove GameNodeRep::GetChild(int) and implement children as a std::vector
Closes #514
1 parent a4b4936 commit ca9256b

File tree

7 files changed

+40
-31
lines changed

7 files changed

+40
-31
lines changed

src/games/behavmixed.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ void MixedBehaviorProfile<T>::RealizationProbs(const MixedStrategyProfile<T> &mp
115115
prob = T(node->m_infoset->GetActionProb(node->m_infoset->GetAction(i)));
116116
}
117117

118-
GameNodeRep *child = node->m_children[i];
118+
GameNodeRep *child = node->m_children[i - 1];
119119

120120
map_bvals[child] = prob * map_bvals[node];
121121
map_nvals[child] += map_bvals[child];
@@ -428,8 +428,8 @@ T MixedBehaviorProfile<T>::DiffActionValue(const GameAction &p_action,
428428

429429
deriv += DiffRealizProb(member, p_oppAction) *
430430
(map_nodeValues[child][player] - map_actionValues[p_action]);
431-
deriv += map_realizProbs[member] *
432-
DiffNodeValue(member->GetChild(p_action->GetNumber()), player, p_oppAction);
431+
deriv +=
432+
map_realizProbs[member] * DiffNodeValue(member->GetChild(p_action), player, p_oppAction);
433433
}
434434

435435
return deriv / GetInfosetProb(p_action->GetInfoset());

src/games/game.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ void GamePlayerRep::MakeReducedStrats(GameNodeRep *n, GameNodeRep *nn)
124124
// we haven't visited this infoset before
125125
n->m_infoset->flag = 1;
126126
for (size_t i = 1; i <= n->NumChildren(); i++) {
127-
GameNodeRep *m = n->m_children[i];
127+
GameNodeRep *m = n->m_children[i - 1];
128128
n->whichbranch = m;
129129
n->m_infoset->whichbranch = i;
130130
MakeReducedStrats(m, nn);
@@ -133,19 +133,19 @@ void GamePlayerRep::MakeReducedStrats(GameNodeRep *n, GameNodeRep *nn)
133133
}
134134
else {
135135
// we have visited this infoset, take same action
136-
MakeReducedStrats(n->m_children[n->m_infoset->whichbranch], nn);
136+
MakeReducedStrats(n->m_children[n->m_infoset->whichbranch - 1], nn);
137137
}
138138
}
139139
else {
140140
n->ptr = nullptr;
141141
if (nn != nullptr) {
142142
n->ptr = nn->m_parent;
143143
}
144-
n->whichbranch = n->m_children[1];
144+
n->whichbranch = n->m_children.front();
145145
if (n->m_infoset) {
146146
n->m_infoset->whichbranch = 0;
147147
}
148-
MakeReducedStrats(n->m_children[1], n->m_children[1]);
148+
MakeReducedStrats(n->m_children.front(), n->m_children.front());
149149
}
150150
}
151151
else if (nn) {

src/games/game.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ class GameNodeRep : public GameObject {
367367
GameInfosetRep *m_infoset{nullptr};
368368
GameNodeRep *m_parent;
369369
GameOutcomeRep *m_outcome{nullptr};
370-
Array<GameNodeRep *> m_children;
370+
std::vector<GameNodeRep *> m_children;
371371
GameNodeRep *whichbranch{nullptr}, *ptr{nullptr};
372372

373373
GameNodeRep(GameRep *e, GameNodeRep *p);
@@ -383,13 +383,12 @@ class GameNodeRep : public GameObject {
383383

384384
int GetNumber() const { return m_number; }
385385
size_t NumChildren() const { return m_children.size(); }
386-
GameNode GetChild(int i) const { return m_children[i]; }
387386
GameNode GetChild(const GameAction &p_action)
388387
{
389388
if (p_action->GetInfoset() != m_infoset) {
390389
throw MismatchException();
391390
}
392-
return m_children[p_action->GetNumber()];
391+
return m_children.at(p_action->GetNumber() - 1);
393392
}
394393
Array<GameNode> GetChildren() const;
395394

src/games/gametree.cc

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,10 @@ void GameTreeRep::DeleteAction(GameAction p_action)
137137
infoset->RenumberActions();
138138

139139
for (auto member : infoset->m_members) {
140-
DeleteTree(member->m_children[where]);
140+
DeleteTree(member->m_children[where - 1]);
141141
m_numNodes--;
142-
member->m_children[where]->Invalidate();
143-
erase_atindex(member->m_children, where);
142+
member->m_children[where - 1]->Invalidate();
143+
member->m_children.erase(std::next(member->m_children.begin(), where - 1));
144144
}
145145
ClearComputedValues();
146146
Canonicalize();
@@ -461,10 +461,10 @@ void GameTreeRep::DeleteTree(GameNode p_node)
461461
}
462462
IncrementVersion();
463463
while (!node->m_children.empty()) {
464-
DeleteTree(node->m_children.front());
464+
DeleteTree(node->m_children.back());
465465
m_numNodes--;
466-
node->m_children.front()->Invalidate();
467-
erase_atindex(node->m_children, 1);
466+
node->m_children.back()->Invalidate();
467+
node->m_children.pop_back();
468468
}
469469
if (node->m_infoset) {
470470
RemoveMember(node->m_infoset, node);
@@ -738,9 +738,10 @@ Rational SubtreeSum(const GameNode &p_node)
738738
Rational sum(0);
739739

740740
if (p_node->NumChildren() > 0) {
741-
sum = SubtreeSum(p_node->GetChild(1));
742-
for (size_t i = 2; i <= p_node->NumChildren(); i++) {
743-
if (SubtreeSum(p_node->GetChild(i)) != sum) {
741+
auto children = p_node->GetChildren();
742+
sum = SubtreeSum(children.front());
743+
for (auto child = std::next(children.begin()); child != children.end(); child++) {
744+
if (SubtreeSum(*child) != sum) {
744745
throw NotZeroSumException();
745746
}
746747
}
@@ -776,17 +777,17 @@ bool GameTreeRep::IsPerfectRecall(GameInfoset &s1, GameInfoset &s2) const
776777
auto *iset2 = player->m_infosets[j - 1];
777778

778779
bool precedes = false;
779-
size_t action = 0;
780+
GameAction action = nullptr;
780781

781782
for (size_t m = 1; m <= iset2->NumMembers(); m++) {
782783
size_t n;
783784
for (n = 1; n <= iset1->NumMembers(); n++) {
784785
if (iset2->GetMember(m)->IsSuccessorOf(iset1->GetMember(n)) &&
785786
iset1->GetMember(n) != iset2->GetMember(m)) {
786787
precedes = true;
787-
for (size_t act = 1; act <= iset1->NumActions(); act++) {
788+
for (const auto &act : iset1->GetActions()) {
788789
if (iset2->GetMember(m)->IsSuccessorOf(iset1->GetMember(n)->GetChild(act))) {
789-
if (action != 0 && action != act) {
790+
if (action != nullptr && action != act) {
790791
s1 = iset1;
791792
s2 = iset2;
792793
return false;

src/gui/efglayout.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -574,16 +574,15 @@ int gbtTreeLayout::LayoutSubtree(const GameNode &p_node, const BehaviorSupportPr
574574
}
575575
else {
576576
if (p_node->NumChildren() > 0) {
577-
for (size_t i = 1; i <= p_node->NumChildren(); i++) {
578-
yn = LayoutSubtree(p_node->GetChild(i), p_support, p_maxy, p_miny, p_ycoord);
577+
for (const auto &action : p_node->GetInfoset()->GetActions()) {
578+
yn = LayoutSubtree(p_node->GetChild(action), p_support, p_maxy, p_miny, p_ycoord);
579579
if (y1 == -1) {
580580
y1 = yn;
581581
}
582582

583-
if (!p_node->GetPlayer()->IsChance() &&
584-
!p_support.Contains(p_node->GetInfoset()->GetAction(i))) {
583+
if (!p_node->GetPlayer()->IsChance() && !p_support.Contains(action)) {
585584
(*std::find_if(m_nodeList.begin(), m_nodeList.end(), [&](const gbtNodeEntry *e) {
586-
return e->GetNode() == p_node->GetChild(i);
585+
return e->GetNode() == p_node->GetChild(action);
587586
}))->SetInSupport(false);
588587
}
589588
}

src/pygambit/gambit.pxd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ cdef extern from "games/game.h":
7676
c_GameActionRep *deref "operator->"() except +RuntimeError
7777

7878
cdef cppclass c_GameInfoset "GameObjectPtr<GameInfosetRep>":
79+
bool operator ==(c_GameInfoset) except +
7980
bool operator !=(c_GameInfoset) except +
8081
c_GameInfosetRep *deref "operator->"() except +RuntimeError
8182

@@ -157,7 +158,7 @@ cdef extern from "games/game.h":
157158
c_GamePlayer GetPlayer() except +
158159
c_GameNode GetParent() except +
159160
int NumChildren() except +
160-
c_GameNode GetChild(int) except +IndexError
161+
c_GameNode GetChild(c_GameAction) except +IndexError
161162
c_GameOutcome GetOutcome() except +
162163
c_GameNode GetPriorSibling() except +
163164
c_GameNode GetNextSibling() except +

src/pygambit/node.pxi

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,13 @@ class NodeChildren:
4242
return f"NodeChildren(parent={Node.wrap(self.parent)})"
4343

4444
def __iter__(self) -> typing.Iterator[Node]:
45-
for i in range(self.parent.deref().NumChildren()):
46-
yield Node.wrap(self.parent.deref().GetChild(i + 1))
45+
if self.parent.deref().GetInfoset() != cython.cast(c_GameInfoset, NULL):
46+
for i in range(self.parent.deref().GetInfoset().deref().NumActions()):
47+
yield Node.wrap(
48+
self.parent.deref().GetChild(
49+
self.parent.deref().GetInfoset().deref().GetAction(i + 1)
50+
)
51+
)
4752

4853
def __getitem__(self, index: typing.Union[int, str]) -> Node:
4954
if isinstance(index, str):
@@ -56,7 +61,11 @@ class NodeChildren:
5661
raise ValueError(f"Node has multiple children with label '{index}'")
5762
return matches[0]
5863
if isinstance(index, int):
59-
return Node.wrap(self.parent.deref().GetChild(index + 1))
64+
if self.parent.deref().GetInfoset() == cython.cast(c_GameInfoset, NULL):
65+
raise IndexError("Index out of range")
66+
return Node.wrap(self.parent.deref().GetChild(
67+
self.parent.deref().GetInfoset().deref().GetAction(index + 1)
68+
))
6069
raise TypeError(f"Child index must be int or str, not {index.__class__.__name__}")
6170

6271

0 commit comments

Comments
 (0)