From dcc665eaf2b02df1ef9fe2bbe87027fbc394b103 Mon Sep 17 00:00:00 2001 From: Ted Turocy Date: Fri, 1 Sep 2023 14:41:24 +0100 Subject: [PATCH] Migrate action and infoset to pure-python cython. --- src/pygambit/core/action.pxi | 40 +++++++++----------------- src/pygambit/core/infoset.pxi | 53 +++++++++++++++++------------------ src/pygambit/gambit.pyx | 1 + 3 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/pygambit/core/action.pxi b/src/pygambit/core/action.pxi index 85c0eb461..8542192b3 100644 --- a/src/pygambit/core/action.pxi +++ b/src/pygambit/core/action.pxi @@ -19,13 +19,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -import typing -from libcpp.string cimport string - -cdef class Action: +@cython.cclass +class Action: """A choice available at an information set.""" - cdef c_GameAction action + action = cython.declare(c_GameAction) def __repr__(self): return ( @@ -35,21 +33,15 @@ cdef class Action: f"in game '{self.infoset.game.title}'>" ) - def __richcmp__(self, other, whichop) -> bool: + def __eq__(self, other: typing.Any) -> bool: if isinstance(other, Action): - if whichop == 2: - return self.action.deref() == (other).action.deref() - elif whichop == 3: - return self.action.deref() != (other).action.deref() - else: - raise NotImplementedError - else: - if whichop == 2: - return False - elif whichop == 3: - return True - else: - raise NotImplementedError + return self.action.deref() == ( other).action.deref() + return False + + def __ne__(self, other: typing.Any) -> bool: + if isinstance(other, Action): + return self.action.deref() != ( other).action.deref() + return True def __hash__(self) -> long: return long(self.action.deref()) @@ -103,13 +95,9 @@ cdef class Action: def prob(self) -> typing.Union[decimal.Decimal, Rational]: """ Get or set the probability a chance action is played. - - Parameters - ---------- - value : Any - The probability the action is played. This can be any numeric type, or any object that - has a string representation which can be interpreted as an integer, - decimal, or rational number. + When setting the probability, the value can be any numeric type, or any object that + has a string representation which can be interpreted as an integer, + decimal, or rational number. Raises ------ diff --git a/src/pygambit/core/infoset.pxi b/src/pygambit/core/infoset.pxi index c78230aff..222ebdb1a 100644 --- a/src/pygambit/core/infoset.pxi +++ b/src/pygambit/core/infoset.pxi @@ -20,9 +20,14 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -cdef class Members(Collection): + +@cython.cclass +class Members(Collection): """The set of nodes which are members of an information set.""" - cdef c_GameInfoset infoset + infoset = cython.declare(c_GameInfoset) + + def __init__(self, infoset: Infoset): + self.infoset = infoset.infoset def __len__(self): return self.infoset.deref().NumMembers() @@ -36,9 +41,10 @@ cdef class Members(Collection): return n -cdef class Actions(Collection): +@cython.cclass +class Actions(Collection): """The set of actions which are available at an information set.""" - cdef c_GameInfoset infoset + infoset = cython.declare(c_GameInfoset) def add(self, action=None): """Add an action at the information set. If `action` is not null, the new action @@ -60,36 +66,32 @@ cdef class Actions(Collection): def __getitem__(self, act): if not isinstance(act, int): return Collection.__getitem__(self, act) - cdef Action a + a = cython.declare(Action) a = Action() a.action = self.infoset.deref().GetAction(act+1) return a -cdef class Infoset: + +@cython.cclass +class Infoset: """Represents an information set in a :py:class:`Game`.""" - cdef c_GameInfoset infoset + infoset = cython.declare(c_GameInfoset) def __repr__(self) -> str: return ( f"" ) - - def __richcmp__(Infoset self, other, whichop) -> bool: + + def __eq__(self, other: typing.Any) -> bool: if isinstance(other, Infoset): - if whichop == 2: - return self.infoset.deref() == (other).infoset.deref() - elif whichop == 3: - return self.infoset.deref() != (other).infoset.deref() - else: - raise NotImplementedError - else: - if whichop == 2: - return False - elif whichop == 3: - return True - else: - raise NotImplementedError + return self.infoset.deref() == ( other).infoset.deref() + return False + + def __ne__(self, other: typing.Any) -> bool: + if isinstance(other, Infoset): + return self.infoset.deref() != ( other).infoset.deref() + return True def __hash__(self) -> long: return long(self.infoset.deref()) @@ -155,7 +157,7 @@ cdef class Infoset: @property def actions(self) -> Actions: """Returns the set of actions at the information set.""" - cdef Actions a + a = cython.declare(Actions) a = Actions() a.infoset = self.infoset return a @@ -163,10 +165,7 @@ cdef class Infoset: @property def members(self) -> Members: """Returns the set of nodes which are members of the information set.""" - cdef Members m - m = Members() - m.infoset = self.infoset - return m + return Members(self) @property def player(self) -> Player: diff --git a/src/pygambit/gambit.pyx b/src/pygambit/gambit.pyx index d9d6ed975..b64a723af 100644 --- a/src/pygambit/gambit.pyx +++ b/src/pygambit/gambit.pyx @@ -27,6 +27,7 @@ import fractions import warnings import typing +import cython from libcpp cimport bool from libcpp.string cimport string import typing