Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
been removed as planned. (#357)

### Added
- Implement `GetPlays()` (C++) and `get_plays` (Python) to compute the set of terminal nodes consistent
with a node, information set, or action (#517)
- Implement `GameRep::GetPlays` (C++) and `Node.plays`, `Infoset.plays`, and `Action.plays` (Python)
to compute the set of terminal nodes consistent with a node, information set, or action (#517)
- Implement `GameRep::GetPower` (C++) and `Action.power` (Python) to compute the power of an action,
that is, the set of plays (terminal nodes) consistent with passing throughn the action
and the plays that do not pass through the information set where this action is available.


## [16.3.1] - unreleased
Expand Down
1 change: 1 addition & 0 deletions doc/pygambit.api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ Information about the game
Action.precedes
Action.prob
Action.plays
Action.power
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be Action.veto


.. autosummary::

Expand Down
3 changes: 3 additions & 0 deletions src/games/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,9 @@ class GameRep : public BaseGameRep {
/// Returns the set of terminal nodes which are descendants of members of an action
virtual std::vector<GameNode> GetPlays(GameAction action) const { throw UndefinedException(); }

/// Returns the power of an action
virtual std::vector<GameNode> GetPower(GameAction action) const { throw UndefinedException(); }

/// Returns true if the game is perfect recall. If not,
/// a pair of violating information sets is returned in the parameters.
virtual bool IsPerfectRecall(GameInfoset &, GameInfoset &) const = 0;
Expand Down
18 changes: 18 additions & 0 deletions src/games/gametree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,24 @@ std::vector<GameNode> GameTreeRep::GetPlays(GameAction action) const
return plays;
}

std::vector<GameNode> GameTreeRep::GetPower(GameAction action) const
{
std::vector<GameNode> power;

const std::vector<GameNode> plays = GetPlays(GetRoot());
const std::vector<GameNode> aplays = GetPlays(action);
const std::vector<GameNode> iplays = GetPlays(action->GetInfoset());

for (const auto &node : plays) {
if ((std::find(iplays.cbegin(), iplays.cend(), node) == iplays.cend()) ||
(std::find(aplays.cbegin(), aplays.cend(), node) != aplays.cend())) {
power.push_back(node);
}
}

return power;
}

void GameTreeRep::DeleteOutcome(const GameOutcome &p_outcome)
{
IncrementVersion();
Expand Down
2 changes: 2 additions & 0 deletions src/games/gametree.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ class GameTreeRep : public GameExplicitRep {
std::vector<GameNode> GetPlays(GameInfoset infoset) const override;
std::vector<GameNode> GetPlays(GameAction action) const override;

std::vector<GameNode> GetPower(GameAction action) const override;

Game CopySubgame(GameNode) const override;
//@}

Expand Down
11 changes: 10 additions & 1 deletion src/pygambit/action.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,18 @@ class Action:

@property
def plays(self) -> typing.List[Node]:
"""Returns a list of all terminal `Node` objects consistent with it.
"""Returns a list of all terminal `Node` objects consistent with the action.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simpler is just to say 'terminal nodes' rather than 'terminal Node objects'

"""
return [
Node.wrap(n) for n in
self.action.deref().GetInfoset().deref().GetGame().deref().GetPlays(self.action)
]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring has not been updated.

It would be useful to write a brief explanation of what the 'veto' of an action is here - a few lines so the documentation is self-contained

@property
def power(self) -> typing.List[Node]:
"""Returns power of the action.
"""
return [
Node.wrap(n) for n in
self.action.deref().GetInfoset().deref().GetGame().deref().GetPower(self.action)
]
1 change: 1 addition & 0 deletions src/pygambit/gambit.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ cdef extern from "games/game.h":
stdvector[c_GameNode] GetPlays(c_GameNode) except +
stdvector[c_GameNode] GetPlays(c_GameInfoset) except +
stdvector[c_GameNode] GetPlays(c_GameAction) except +
stdvector[c_GameNode] GetPower(c_GameAction) except +
bool IsPerfectRecall() except +

c_GameInfoset AppendMove(c_GameNode, c_GamePlayer, int) except +ValueError
Expand Down
18 changes: 18 additions & 0 deletions tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,21 @@ def test_action_plays():
} # paths=[0, 1, 0], [0, 1]

assert set(test_action.plays) == expected_set_of_plays


def test_action_power():
"""Verify `action.power` returns the action's power
(terminal `Node` objects that can be reached from this action
or that cannot be reached from the information set associated with this action).
"""
game = games.read_from_file("e01.efg")
list_nodes = list(game.nodes)
list_infosets = list(game.infosets)

test_action = list_infosets[2].actions[0] # members' paths=[0, 1, 0], [0, 1]

expected_set_of_plays = {
list_nodes[2], list_nodes[4], list_nodes[7]
} # paths=[0, 0], [0, 1, 0], [0, 1]

assert set(test_action.power) == expected_set_of_plays