As part of developing our "algebra of games" idea, we want to move towards "lazy evaluation" of relationships among the constituent parts of games. See content migrated from discussion below for the rationale of why this makes the API more consistent.
For the moment we will change this in pygambit only (with C++ intended for 17.0 alongside more substantial implementation changes).
We will need to change (at least) the implementation of the following:
Node.outcome
Node.infoset
Node.player
Node.parent
It is not a coincidence that these are all node-related properties. We are intending that the node (history) is going to be the principal way of manipulating extensive games in 17.0, with objects referenced relative to a node (or set of nodes).
The implementation path for this in pygambit would be creating a different type of object which instead of keeping, for example, an infoset, will keep a node, and then access the node's information set on demand when needed.
Discussed in #863
Originally posted by tturocy April 30, 2026
This is something which is envisaged as part of the algebra-of-games API planned for 17.0.
Presently, relations like Node.outcome or Node.infoset are evaluated "immediately" and resolve to an object which is realised physically in memory (ultimately it's a shared pointer to an allocated structure). We have developed a sense that we want to move away from this, and to treat these as a form of selector.
There is another justification for this, which is that the existing API is inconsistent in this regard. Consider the sequence below:
In [1]: import pygambit as gbt
g = gbt.
In [2]: g = gbt.Game.new_tree(players=["1", "2"])
In [3]: first_gen = g.root.children
In [4]: len(first_gen)
Out[4]: 0
In [5]: g.append_move(g.root, "1", actions=["U", "D"])
In [6]: len(first_gen)
Out[6]: 2
As implemented, Node.children actually returns an object which is evaluated, in effect, lazily on iteration. So if the set of children of the node change, the output of iterating the collection changes.
However, predicates that resolve to individual objects rather than collections are evaluated immediately. For example,
In [1]: import pygambit as gbt
In [2]: g = gbt.Game.new_tree(players=["1", "2"])
In [3]: infoset = g.root.infoset
In [4]: infoset
In [5]: g.append_move(g.root, "1", actions=["U", "D"])
In [6]: infoset == g.root.infoset
Out[6]: False
This is (in my view) an argument in favour of revising the semantics even for 16.7 for these properties. I claim that most of the time, the intention when referring to objects via these relations is in the sense of a predicate. g.root.infoset means "the information set to which the root node of the game belongs", which may change as the game mutates; g.root.outcome would mean "the outcome associated with the root node (if any)", which likewise might change.
As part of developing our "algebra of games" idea, we want to move towards "lazy evaluation" of relationships among the constituent parts of games. See content migrated from discussion below for the rationale of why this makes the API more consistent.
For the moment we will change this in
pygambitonly (with C++ intended for 17.0 alongside more substantial implementation changes).We will need to change (at least) the implementation of the following:
Node.outcomeNode.infosetNode.playerNode.parentIt is not a coincidence that these are all node-related properties. We are intending that the node (history) is going to be the principal way of manipulating extensive games in 17.0, with objects referenced relative to a node (or set of nodes).
The implementation path for this in
pygambitwould be creating a different type of object which instead of keeping, for example, an infoset, will keep a node, and then access the node's information set on demand when needed.Discussed in #863
Originally posted by tturocy April 30, 2026
This is something which is envisaged as part of the algebra-of-games API planned for 17.0.
Presently, relations like
Node.outcomeorNode.infosetare evaluated "immediately" and resolve to an object which is realised physically in memory (ultimately it's a shared pointer to an allocated structure). We have developed a sense that we want to move away from this, and to treat these as a form of selector.There is another justification for this, which is that the existing API is inconsistent in this regard. Consider the sequence below:
As implemented,
Node.childrenactually returns an object which is evaluated, in effect, lazily on iteration. So if the set of children of the node change, the output of iterating the collection changes.However, predicates that resolve to individual objects rather than collections are evaluated immediately. For example,
This is (in my view) an argument in favour of revising the semantics even for 16.7 for these properties. I claim that most of the time, the intention when referring to objects via these relations is in the sense of a predicate.
g.root.infosetmeans "the information set to which the root node of the game belongs", which may change as the game mutates;g.root.outcomewould mean "the outcome associated with the root node (if any)", which likewise might change.