@@ -145,7 +145,6 @@ void GameTreeRep::DeleteAction(GameAction p_action)
145145 member->m_children .erase (it);
146146 }
147147 ClearComputedValues ();
148- Canonicalize ();
149148}
150149
151150GameInfoset GameActionRep::GetInfoset () const { return m_infoset->shared_from_this (); }
@@ -193,7 +192,6 @@ void GameTreeRep::SetPlayer(GameInfoset p_infoset, GamePlayer p_player)
193192 p_player->m_infosets .push_back (p_infoset);
194193
195194 ClearComputedValues ();
196- Canonicalize ();
197195}
198196
199197bool GameInfosetRep::Precedes (GameNode p_node) const
@@ -237,7 +235,6 @@ GameAction GameTreeRep::InsertAction(GameInfoset p_infoset, GameAction p_action
237235 m_numNodes += p_infoset->m_members .size ();
238236 // m_numNonterminalNodes stays unchanged when an action is appended to an information set
239237 ClearComputedValues ();
240- Canonicalize ();
241238 return action;
242239}
243240
@@ -251,10 +248,7 @@ void GameTreeRep::RemoveMember(GameInfosetRep *p_infoset, GameNodeRep *p_node)
251248 p_infoset->Invalidate ();
252249 p_infoset->m_player ->m_infosets .erase (std::find (
253250 player->m_infosets .begin (), player->m_infosets .end (), p_infoset->shared_from_this ()));
254- int iset = 1 ;
255- for (auto &infoset : player->m_infosets ) {
256- infoset->m_number = iset++;
257- }
251+ RenumberInfosets (player);
258252 }
259253}
260254
@@ -284,7 +278,6 @@ void GameTreeRep::Reveal(GameInfoset p_atInfoset, GamePlayer p_player)
284278 }
285279
286280 ClearComputedValues ();
287- Canonicalize ();
288281}
289282
290283// ========================================================================
@@ -422,7 +415,6 @@ void GameTreeRep::DeleteParent(GameNode p_node)
422415
423416 oldParent->Invalidate ();
424417 ClearComputedValues ();
425- Canonicalize ();
426418}
427419
428420void GameTreeRep::DeleteTree (GameNode p_node)
@@ -449,7 +441,6 @@ void GameTreeRep::DeleteTree(GameNode p_node)
449441 node->m_label = " " ;
450442
451443 ClearComputedValues ();
452- Canonicalize ();
453444}
454445
455446void GameTreeRep::CopySubtree (GameNodeRep *dest, GameNodeRep *src, GameNodeRep *stop)
@@ -491,7 +482,6 @@ void GameTreeRep::CopyTree(GameNode p_dest, GameNode p_src)
491482 CopySubtree (dest_child->get (), src_child->get (), dest);
492483 }
493484 ClearComputedValues ();
494- Canonicalize ();
495485 }
496486}
497487
@@ -515,7 +505,6 @@ void GameTreeRep::MoveTree(GameNode p_dest, GameNode p_src)
515505 dest->m_outcome = nullptr ;
516506
517507 ClearComputedValues ();
518- Canonicalize ();
519508}
520509
521510Game GameTreeRep::CopySubgame (GameNode p_root) const
@@ -547,7 +536,6 @@ void GameTreeRep::SetInfoset(GameNode p_node, GameInfoset p_infoset)
547536 node->m_infoset = p_infoset.get ();
548537
549538 ClearComputedValues ();
550- Canonicalize ();
551539}
552540
553541GameInfoset GameTreeRep::LeaveInfoset (GameNode p_node)
@@ -578,7 +566,6 @@ GameInfoset GameTreeRep::LeaveInfoset(GameNode p_node)
578566 (*new_act)->SetLabel ((*old_act)->GetLabel ());
579567 }
580568 ClearComputedValues ();
581- Canonicalize ();
582569 return node->m_infoset ->shared_from_this ();
583570}
584571
@@ -619,7 +606,6 @@ GameInfoset GameTreeRep::AppendMove(GameNode p_node, GameInfoset p_infoset)
619606 });
620607 m_numNonterminalNodes++;
621608 ClearComputedValues ();
622- Canonicalize ();
623609 return node->m_infoset ->shared_from_this ();
624610}
625611
@@ -671,7 +657,6 @@ GameInfoset GameTreeRep::InsertMove(GameNode p_node, GameInfoset p_infoset)
671657 m_numNodes += newNode->m_infoset ->m_actions .size ();
672658 m_numNonterminalNodes++;
673659 ClearComputedValues ();
674- Canonicalize ();
675660 return p_infoset;
676661}
677662
@@ -769,64 +754,39 @@ bool GameTreeRep::IsPerfectRecall() const
769754// GameTreeRep: Managing the representation
770755// ------------------------------------------------------------------------
771756
772- void GameTreeRep::NumberNodes (GameNodeRep *n, int &index )
757+ void GameTreeRep::SortInfosets (GamePlayerRep *p_player )
773758{
774- n->m_number = index++;
775- for (auto &child : n->m_children ) {
776- NumberNodes (child.get (), index);
759+ // Sort nodes within information sets according to ID.
760+ for (auto &infoset : p_player->m_infosets ) {
761+ std::sort (infoset->m_members .begin (), infoset->m_members .end (),
762+ [](const std::shared_ptr<GameNodeRep> &a, const std::shared_ptr<GameNodeRep> &b) {
763+ return a->m_number < b->m_number ;
764+ });
777765 }
766+ // Sort information sets by the smallest ID among their members
767+ std::sort (
768+ p_player->m_infosets .begin (), p_player->m_infosets .end (),
769+ [](const std::shared_ptr<GameInfosetRep> &a, const std::shared_ptr<GameInfosetRep> &b) {
770+ return a->m_members .front ()->m_number < b->m_members .front ()->m_number ;
771+ });
772+ RenumberInfosets (p_player);
773+ }
774+ void GameTreeRep::RenumberInfosets (GamePlayerRep *p_player)
775+ {
776+ std::for_each (
777+ p_player->m_infosets .begin (), p_player->m_infosets .end (),
778+ [iset = 1 ](const std::shared_ptr<GameInfosetRep> &s) mutable { s->m_number = iset++; });
778779}
779780
780- void GameTreeRep::Canonicalize ()
781+ void GameTreeRep::SortInfosets ()
781782{
782- if (!m_doCanon) {
783- return ;
784- }
785783 int nodeindex = 1 ;
786- NumberNodes (m_root.get (), nodeindex);
787-
788- for (size_t pl = 0 ; pl <= m_players.size (); pl++) {
789- auto player = (pl) ? m_players[pl - 1 ].get () : m_chance.get ();
790-
791- // Sort nodes within information sets according to ID.
792- // Coded using a bubble sort for simplicity; large games might
793- // find a quicksort worthwhile.
794- for (auto &infoset : player->m_infosets ) {
795- for (size_t i = 1 ; i < infoset->m_members .size (); i++) {
796- for (size_t j = 1 ; j < infoset->m_members .size () - i; j++) {
797- if (infoset->m_members [j]->m_number < infoset->m_members [j - 1 ]->m_number ) {
798- auto tmp = infoset->m_members [j - 1 ];
799- infoset->m_members [j - 1 ] = infoset->m_members [j];
800- infoset->m_members [j] = tmp;
801- }
802- }
803- }
804- }
805-
806- // Sort information sets by the smallest ID among their members
807- // Coded using a bubble sort for simplicity; large games might
808- // find a quicksort worthwhile.
809- for (size_t i = 1 ; i < player->m_infosets .size (); i++) {
810- for (size_t j = 1 ; j < player->m_infosets .size () - i; j++) {
811- const int a = ((player->m_infosets [j]->m_members .size ())
812- ? player->m_infosets [j]->m_members [0 ]->m_number
813- : 0 );
814- const int b = ((player->m_infosets [j - 1 ]->m_members .size ())
815- ? player->m_infosets [j - 1 ]->m_members [0 ]->m_number
816- : 0 );
817-
818- if (a < b || b == 0 ) {
819- auto tmp = player->m_infosets [j - 1 ];
820- player->m_infosets [j - 1 ] = player->m_infosets [j];
821- player->m_infosets [j] = tmp;
822- }
823- }
824- }
825-
826- // Reassign information set IDs
827- std::for_each (
828- player->m_infosets .begin (), player->m_infosets .end (),
829- [iset = 1 ](const std::shared_ptr<GameInfosetRep> &s) mutable { s->m_number = iset++; });
784+ for (const auto &node : GetNodes ()) {
785+ node->m_number = nodeindex++;
786+ }
787+ SortInfosets (m_chance.get ());
788+ for (auto player : m_players) {
789+ SortInfosets (player.get ());
830790 }
831791}
832792
@@ -848,7 +808,7 @@ void GameTreeRep::BuildComputedValues() const
848808 if (m_computedValues) {
849809 return ;
850810 }
851- const_cast <GameTreeRep *>(this )->Canonicalize ();
811+ const_cast <GameTreeRep *>(this )->SortInfosets ();
852812 for (const auto &player : m_players) {
853813 std::map<GameInfosetRep *, int > behav;
854814 std::map<GameNodeRep *, GameNodeRep *> ptr, whichbranch;
0 commit comments