Skip to content

Commit c761a99

Browse files
committed
Return optional for belief
1 parent 1e194d1 commit c761a99

File tree

7 files changed

+39
-11
lines changed

7 files changed

+39
-11
lines changed

src/games/behavmixed.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,14 @@ template <class T> T MixedBehaviorProfile<T>::GetInfosetProb(const GameInfoset &
285285
[&](const auto &node) -> T { return m_cache.m_realizProbs[node]; });
286286
}
287287

288-
template <class T> const T &MixedBehaviorProfile<T>::GetBeliefProb(const GameNode &node) const
288+
template <class T>
289+
std::optional<T> MixedBehaviorProfile<T>::GetBeliefProb(const GameNode &node) const
289290
{
290291
CheckVersion();
291292
EnsureBeliefs();
293+
if (!node->GetInfoset() || GetInfosetProb(node->GetInfoset()) == T{0}) {
294+
return std::nullopt;
295+
}
292296
return m_cache.m_beliefs[node];
293297
}
294298

src/games/behavmixed.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ template <class T> class MixedBehaviorProfile {
241241

242242
const T &GetRealizProb(const GameNode &node) const;
243243
T GetInfosetProb(const GameInfoset &p_infoset) const;
244-
const T &GetBeliefProb(const GameNode &node) const;
244+
std::optional<T> GetBeliefProb(const GameNode &node) const;
245245
Vector<T> GetPayoff(const GameNode &node) const;
246246
const T &GetPayoff(const GamePlayer &player, const GameNode &node) const;
247247
const T &GetPayoff(const GameInfoset &p_infoset) const;

src/gui/analysis.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,9 @@ std::string AnalysisProfileList<T>::GetBeliefProb(const GameNode &p_node, int p_
240240
}
241241

242242
try {
243-
if (m_behavProfiles[index]->GetInfosetProb(p_node->GetInfoset()) > Rational(0)) {
244-
return lexical_cast<std::string>(m_behavProfiles[index]->GetBeliefProb(p_node),
245-
m_doc->GetStyle().NumDecimals());
243+
auto belief = m_behavProfiles[index]->GetBeliefProb(p_node);
244+
if (belief.has_value()) {
245+
return lexical_cast<std::string>(belief.value(), m_doc->GetStyle().NumDecimals());
246246
}
247247
// We don't compute assessments yet!
248248
return "*";

src/pygambit/behavmixed.pxi

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -587,10 +587,13 @@ class MixedBehaviorProfile:
587587
self._check_validity()
588588
return self._is_defined_at(self.game._resolve_infoset(infoset, "is_defined_at"))
589589

590-
def belief(self, node: NodeReference) -> ProfileDType:
590+
def belief(self, node: NodeReference) -> ProfileDType | None:
591591
"""Returns the conditional probability that a node is reached, given that
592592
its information set is reached.
593593

594+
If the information set is not reachable, the belief is not well-defined.
595+
In this case, the function returns `None`.
596+
594597
Parameters
595598
----------
596599
node
@@ -952,7 +955,10 @@ class MixedBehaviorProfileDouble(MixedBehaviorProfile):
952955
return deref(self.profile).GetPayoff(player.player)
953956

954957
def _belief(self, node: Node) -> float:
955-
return deref(self.profile).GetBeliefProb(node.node)
958+
cdef optional[double] value = deref(self.profile).GetBeliefProb(node.node)
959+
if value.has_value():
960+
return value.value()
961+
return None
956962

957963
def _realiz_prob(self, node: Node) -> float:
958964
return deref(self.profile).GetRealizProb(node.node)
@@ -967,7 +973,7 @@ class MixedBehaviorProfileDouble(MixedBehaviorProfile):
967973
return deref(self.profile).GetPayoff(player.player, node.node)
968974

969975
def _action_value(self, action: Action) -> float | None:
970-
cdef optional[float] value = deref(self.profile).GetPayoff(action.action)
976+
cdef optional[double] value = deref(self.profile).GetPayoff(action.action)
971977
if value.has_value():
972978
return value.value()
973979
return None
@@ -1057,7 +1063,10 @@ class MixedBehaviorProfileRational(MixedBehaviorProfile):
10571063
return rat_to_py(deref(self.profile).GetPayoff(player.player))
10581064

10591065
def _belief(self, node: Node) -> Rational:
1060-
return rat_to_py(deref(self.profile).GetBeliefProb(node.node))
1066+
cdef optional[c_Rational] value = deref(self.profile).GetBeliefProb(node.node)
1067+
if value.has_value():
1068+
return rat_to_py(value.value())
1069+
return None
10611070

10621071
def _realiz_prob(self, node: Node) -> Rational:
10631072
return rat_to_py(deref(self.profile).GetRealizProb(node.node))

src/pygambit/gambit.pxd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ cdef extern from "games/behavmixed.h" namespace "Gambit":
363363
T getitem "operator[]"(int) except +IndexError
364364
T getaction "operator[]"(c_GameAction) except +IndexError
365365
T GetPayoff(c_GamePlayer) except +
366-
T GetBeliefProb(c_GameNode) except +
366+
optional[T] GetBeliefProb(c_GameNode) except +
367367
T GetRealizProb(c_GameNode) except +
368368
T GetInfosetProb(c_GameInfoset) except +
369369
T GetPayoff(c_GameInfoset) except +

src/tools/util.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,13 @@ void MixedBehaviorProfileDetailRenderer<T>::Render(const MixedBehaviorProfile<T>
256256
m_stream << std::setw(7) << node->GetNumber() << " ";
257257
}
258258
m_stream << std::setw(11);
259-
m_stream << lexical_cast<std::string>(p_profile.GetBeliefProb(node), m_numDecimals);
259+
auto belief = p_profile.GetBeliefProb(node);
260+
if (belief.has_value()) {
261+
m_stream << lexical_cast<std::string>(belief.value(), m_numDecimals);
262+
}
263+
else {
264+
m_stream << "";
265+
}
260266
m_stream << " ";
261267
m_stream << std::setw(11);
262268
m_stream << lexical_cast<std::string>(p_profile.GetRealizProb(node), m_numDecimals);

tests/test_behav.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,3 +2106,12 @@ def test_undefined_action_value():
21062106
for rat in [False, True]:
21072107
profile = game.mixed_behavior_profile([[[1, 0]], [[1, 0]], [[1, 0]]], rational=rat)
21082108
assert profile.action_value(action) is None
2109+
2110+
2111+
def test_undefined_belief():
2112+
"""Test that undefined beliefs return `None`."""
2113+
game = gbt.catalog.load("selten1975/fig1")
2114+
node = game.players[2].infosets[0].members[0]
2115+
for rat in [False, True]:
2116+
profile = game.mixed_behavior_profile([[[1, 0]], [[1, 0]], [[1, 0]]], rational=rat)
2117+
assert profile.belief(node) is None

0 commit comments

Comments
 (0)