Skip to content

Commit b8026c3

Browse files
committed
Implement new (correct) max_regret and liap_value on mixed behaviour profiles
1 parent 2f69c57 commit b8026c3

5 files changed

Lines changed: 77 additions & 5 deletions

File tree

doc/pygambit.api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ Probability distributions over behavior
259259
MixedBehaviorProfile.is_defined_at
260260
MixedBehaviorProfile.agent_max_regret
261261
MixedBehaviorProfile.agent_liap_value
262+
MixedBehaviorProfile.max_regret
263+
MixedBehaviorProfile.liap_value
262264
MixedBehaviorProfile.as_strategy
263265
MixedBehaviorProfile.normalize
264266
MixedBehaviorProfile.copy

src/games/behavmixed.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ template <class T> MixedBehaviorProfile<T> MixedBehaviorProfile<T>::ToFullSuppor
261261
// MixedBehaviorProfile<T>: Interesting quantities
262262
//========================================================================
263263

264+
template <class T> T MixedBehaviorProfile<T>::GetLiapValue() const
265+
{
266+
return MixedStrategyProfile<T>(*this).GetLiapValue();
267+
}
268+
264269
template <class T> T MixedBehaviorProfile<T>::GetAgentLiapValue() const
265270
{
266271
CheckVersion();
@@ -364,6 +369,11 @@ template <class T> T MixedBehaviorProfile<T>::GetRegret(const GameInfoset &p_inf
364369
return br_payoff - map_infosetValues[p_infoset];
365370
}
366371

372+
template <class T> T MixedBehaviorProfile<T>::GetMaxRegret() const
373+
{
374+
return MixedStrategyProfile<T>(*this).GetMaxRegret();
375+
}
376+
367377
template <class T> T MixedBehaviorProfile<T>::GetAgentMaxRegret() const
368378
{
369379
return maximize_function(m_support.GetGame()->GetInfosets(),

src/games/behavmixed.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ template <class T> class MixedBehaviorProfile {
174174
//@{
175175
T GetPayoff(int p_player) const;
176176
T GetPayoff(const GamePlayer &p_player) const { return GetPayoff(p_player->GetNumber()); }
177+
T GetLiapValue() const;
177178
T GetAgentLiapValue() const;
178179

179180
const T &GetRealizProb(const GameNode &node) const;
@@ -191,7 +192,7 @@ template <class T> class MixedBehaviorProfile {
191192
/// between the best-response payoff and the payoff to playing
192193
/// \p p_action.
193194
/// @param[in] p_action The action to compute the regret for.
194-
/// @sa GetRegret(const GameInfoset &) const;
195+
/// @sa GetRegret(const GameInfoset &) const
195196
/// GetAgentMaxRegret() const
196197
const T &GetRegret(const GameAction &p_action) const;
197198

@@ -201,16 +202,22 @@ template <class T> class MixedBehaviorProfile {
201202
/// as the difference between the payoff of the best response action and
202203
/// the payoff to playing their specified mixed action.
203204
/// @param[in] p_infoset The information set to compute the regret at.
204-
/// @sa GetRegret(const GameAction &) const;
205+
/// @sa GetRegret(const GameAction &) const
205206
/// GetAgentMaxRegret() const
206207
T GetRegret(const GameInfoset &p_infoset) const;
207208

208209
/// @brief Computes the maximum regret at any information set in the profile
209210
/// @details Computes the maximum of the regrets of the information sets in the profile.
210-
/// @sa GetRegret(const GameInfoset &) const;
211+
/// @sa GetRegret(const GameInfoset &) const
211212
/// GetRegret(const GameAction &) const
213+
/// GetMaxRegret() const
212214
T GetAgentMaxRegret() const;
213215

216+
/// @brief Computes the maximum regret for any player in the profile
217+
/// @sa GetAgentMaxRegret() const
218+
///
219+
T GetMaxRegret() const;
220+
214221
T DiffActionValue(const GameAction &action, const GameAction &oppAction) const;
215222
T DiffRealizProb(const GameNode &node, const GameAction &oppAction) const;
216223
T DiffNodeValue(const GameNode &node, const GamePlayer &player,

src/pygambit/behavmixed.pxi

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ class MixedBehaviorProfile:
819819
def agent_max_regret(self) -> ProfileDType:
820820
"""Returns the maximum regret at any information set.
821821

822-
A profile is an agent Nash equilibrium if and only if `max_regret()` is 0.
822+
A profile is an agent Nash equilibrium if and only if `agent_max_regret()` is 0.
823823

824824
.. versionchanged:: 16.5.0
825825

@@ -830,6 +830,7 @@ class MixedBehaviorProfile:
830830
--------
831831
action_regret
832832
infoset_regret
833+
max_regret
833834
agent_liap_value
834835
"""
835836
self._check_validity()
@@ -838,7 +839,7 @@ class MixedBehaviorProfile:
838839
def agent_liap_value(self) -> ProfileDType:
839840
"""Returns the Lyapunov value (see [McK91]_) of the strategy profile.
840841

841-
The Lyapunov value is a non-negative number which is zero exactly at
842+
The agent Lyapunov value is a non-negative number which is zero exactly at
842843
agent Nash equilibria.
843844

844845
.. versionchanged:: 16.5.0
@@ -849,6 +850,44 @@ class MixedBehaviorProfile:
849850
See Also
850851
--------
851852
agent_max_regret
853+
liap_value
854+
"""
855+
self._check_validity()
856+
return self._agent_liap_value()
857+
858+
def max_regret(self) -> ProfileDType:
859+
"""Returns the maximum regret at any information set.
860+
861+
A profile is a Nash equilibrium if and only if `max_regret()` is 0.
862+
863+
.. versionchanged:: 16.5.0
864+
865+
New implementation of `max_regret` to clarify the distinction between
866+
per-player and per-agent concepts.
867+
868+
See Also
869+
--------
870+
liap_value
871+
agent_max_regret
872+
"""
873+
self._check_validity()
874+
return self.__max_regret()
875+
876+
def liap_value(self) -> ProfileDType:
877+
"""Returns the Lyapunov value (see [McK91]_) of the strategy profile.
878+
879+
The Lyapunov value is a non-negative number which is zero exactly at
880+
Nash equilibria.
881+
882+
.. versionchanged:: 16.5.0
883+
884+
New implementation of `liap_value` to clarify the distinction between
885+
per-player and per-agent concepts.
886+
887+
See Also
888+
--------
889+
max_regret
890+
agent_liap_value
852891
"""
853892
self._check_validity()
854893
return self._agent_liap_value()
@@ -932,6 +971,9 @@ class MixedBehaviorProfileDouble(MixedBehaviorProfile):
932971
def _agent_max_regret(self) -> float:
933972
return deref(self.profile).GetAgentMaxRegret()
934973

974+
def _max_regret(self) -> float:
975+
return deref(self.profile).GetMaxRegret()
976+
935977
def __eq__(self, other: typing.Any) -> bool:
936978
return (
937979
isinstance(other, MixedBehaviorProfileDouble) and
@@ -951,6 +993,9 @@ class MixedBehaviorProfileDouble(MixedBehaviorProfile):
951993
def _agent_liap_value(self) -> float:
952994
return deref(self.profile).GetAgentLiapValue()
953995

996+
def _liap_value(self) -> float:
997+
return deref(self.profile).GetLiapValue()
998+
954999
def _normalize(self) -> MixedBehaviorProfileDouble:
9551000
return MixedBehaviorProfileDouble.wrap(
9561001
make_shared[c_MixedBehaviorProfile[double]](deref(self.profile).Normalize())
@@ -1028,6 +1073,9 @@ class MixedBehaviorProfileRational(MixedBehaviorProfile):
10281073
def _agent_max_regret(self) -> Rational:
10291074
return rat_to_py(deref(self.profile).GetAgentMaxRegret())
10301075

1076+
def _max_regret(self) -> Rational:
1077+
return rat_to_py(deref(self.profile).GetMaxRegret())
1078+
10311079
def __eq__(self, other: typing.Any) -> bool:
10321080
return (
10331081
isinstance(other, MixedBehaviorProfileRational) and
@@ -1047,6 +1095,9 @@ class MixedBehaviorProfileRational(MixedBehaviorProfile):
10471095
def _agent_liap_value(self) -> Rational:
10481096
return rat_to_py(deref(self.profile).GetAgentLiapValue())
10491097

1098+
def _liap_value(self) -> Rational:
1099+
return rat_to_py(deref(self.profile).GetLiapValue())
1100+
10501101
def _normalize(self) -> MixedBehaviorProfileRational:
10511102
return MixedBehaviorProfileRational.wrap(
10521103
make_shared[c_MixedBehaviorProfile[c_Rational]](deref(self.profile).Normalize())

src/pygambit/gambit.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ cdef extern from "games/behavmixed.h" namespace "Gambit":
378378
T GetRegret(c_GameInfoset) except +
379379
T GetAgentMaxRegret() except +
380380
T GetAgentLiapValue() except +
381+
T GetMaxRegret() except +
382+
T GetLiapValue() except +
381383
c_MixedStrategyProfile[T] ToMixedProfile() # except + doesn't compile
382384
c_MixedBehaviorProfile(c_MixedStrategyProfile[T]) except +NotImplementedError
383385
c_MixedBehaviorProfile(c_Game) except +

0 commit comments

Comments
 (0)