aGrUM 3.0.0
a C++ library for (probabilistic) graphical models
gum::graph Namespace Reference

Namespaces

namespace  detail

Functions

template<GUM_DiGraphable G>
NodeSet requisiteNodes (const G &g, const NodeSet &query, const NodeSet &Zhard=NodeSet(), const NodeSet &Zsoft=NodeSet())
 Returns the Shachter-requisite nodes for query given evidence.
template<GUM_DiGraphable G>
NodeSet dConnected (const G &g, const NodeSet &query, const NodeSet &Zhard=NodeSet(), const NodeSet &Zsoft=NodeSet())
 Returns all nodes d-connected to query given evidence.
template<GUM_DiGraphable G, bool CollectAll>
NodeSet _bayesBall_ (const G &g, const NodeSet &query, const NodeSet &Zhard, const NodeSet &Zsoft)
template<GUM_DiGraphable G>
Sequence< NodeIdtopologicalOrder (const G &g)
 Returns a topological ordering of the nodes of g (Kahn's algorithm).
template<GUM_UndiGraphable G>
bool hasUndirectedCycle (const G &g)
 Returns true if g contains at least one undirected cycle.
template<GUM_DiGraphable G>
DAG markovBlanket (const G &g, NodeId node, int level=1)
 Returns the level-level Markov blanket of node in g as a DAG.
template<GUM_DiGraphable G>
NodeSet minimalCondSet (const G &g, NodeId target, const NodeSet &soids)
 Returns the minimal subset of soids that d-connects target.
template<GUM_DiGraphable G>
NodeSet minimalCondSet (const G &g, const NodeSet &targets, const NodeSet &soids)
 Returns the minimal subset of soids that d-connects all targets.
template<GUM_DiGraphable G>
void _mcsVisitUp_ (const G &g, NodeId node, const NodeSet &soids, NodeSet &minimal, NodeSet &visitedUp, NodeSet &visitedDn)
template<GUM_DiGraphable G>
void _mcsVisitDn_ (const G &g, NodeId node, const NodeSet &soids, NodeSet &minimal, NodeSet &visitedUp, NodeSet &visitedDn)
template<GUM_DiGraphable G>
UndiGraph moralGraph (const G &g)
 Returns the moral graph of g.
template<GUM_DiGraphable G>
UndiGraph moralizedAncestralGraph (const G &g, const NodeSet &query)
 Returns the moralized ancestral graph of query in g.
template<GUM_DiGraphable G>
std::optional< std::vector< NodeId > > directedPath (const G &g, NodeId n1, NodeId n2)
 Shortest directed path from n1 to n2 (BFS, arc direction).
template<GUM_DiGraphable G>
std::optional< std::vector< NodeId > > directedUnorientedPath (const G &g, NodeId n1, NodeId n2)
 Shortest path from n1 to n2 ignoring arc orientation (BFS).
template<GUM_DiGraphable G>
bool hasDirectedPath (const G &g, NodeId from, NodeId to)
 Returns true if there is a directed path from from to to.
template<GUM_UndiGraphable G>
std::optional< std::vector< NodeId > > undirectedPath (const G &g, NodeId n1, NodeId n2)
 Shortest undirected path from n1 to n2 (BFS).
template<GUM_UndiGraphable G>
bool hasUndirectedPath (const G &g, NodeId n1, NodeId n2)
 Returns true if an undirected path exists between n1 and n2.
template<GUM_UndiGraphable G>
bool hasUndirectedPath (const G &g, NodeId n1, NodeId n2, const NodeSet &except)
 Returns true if an undirected path from n1 to n2 exists that avoids all nodes in except.
template<GUM_UndiGraphable G>
bool hasUndirectedPath (const G &g, const NodeSet &n1, const NodeSet &n2, const NodeSet &except)
 Returns true if an undirected path exists from any node in n1 to any node in n2, avoiding nodes in except.
template<GUM_MixedGraphable G>
std::optional< std::vector< NodeId > > mixedOrientedPath (const G &g, NodeId n1, NodeId n2)
 Shortest mixed-oriented path from n1 to n2.
template<GUM_MixedGraphable G>
bool hasMixedOrientedPath (const G &g, NodeId n1, NodeId n2)
 Returns true if a mixed-oriented path from n1 to n2 exists.
template<GUM_MixedGraphable G>
std::optional< std::vector< NodeId > > mixedUnorientedPath (const G &g, NodeId n1, NodeId n2)
 Shortest path ignoring all orientations in a mixed graph.
template<GUM_DiGraphable G>
NodeSet ancestors (const G &g, NodeId id)
 Returns the set of all ancestors of id (nodes from which id is reachable following arc direction).
template<GUM_DiGraphable G>
NodeSet descendants (const G &g, NodeId id)
 Returns the set of all descendants of id (nodes reachable from id following arc direction).
template<GUM_DiGraphable G>
NodeSet family (const G &g, NodeId id)
 Returns the family of id : { id } ∪ parents(id).
template<GUM_DiGraphable G>
NodeSet family (const G &g, const NodeSet &ids)
 Returns the union of families of all nodes in ids.
template<GUM_UndiGraphable G>
NodeProperty< NodeIdchainComponents (const G &g)
 Returns a node-to-component-id mapping for the chain components of g (connected components of the edge-only subgraph).
template<GUM_NodeGraphable G>
NodeProperty< NodeIdconnectedComponents (const G &g)
 Returns a node-to-component-id mapping for the (weakly) connected components of g.
template<GUM_UndiGraphable G>
bool areConnected (const G &g, const NodeSet &A, const NodeSet &B)
 Returns true iff some node in A can reach some node in B via undirected edges.
template<GUM_MixedGraphable G>
NodeSet chainComponent (const G &g, NodeId node)
 Returns the chain component of node in g.
template<GUM_MixedGraphable G>
NodeSet boundary (const G &g, NodeId node)
 Returns the boundary of node: neighbours ∪ parents ∪ children.
template<GUM_DiGraphable G>
bool dSeparated (const G &g, NodeId X, NodeId Y, const NodeSet &Z)
 Returns true iff X and Y are d-separated by Z in g.
template<GUM_DiGraphable G>
bool dSeparated (const G &g, const NodeSet &X, const NodeSet &Y, const NodeSet &Z)
 Returns true iff every node in X is d-separated from every node in Y by Z in g.
template<GUM_MixedGraphable G>
bool cSeparated (const G &g, NodeId X, NodeId Y, const NodeSet &Z)
 Returns true iff X and Y are c-separated by Z in g.
template<GUM_MixedGraphable G>
bool cSeparated (const G &g, const NodeSet &X, const NodeSet &Y, const NodeSet &Z)
 Returns true iff X and Y are c-separated by Z in g.

Function Documentation

◆ _bayesBall_()

template<GUM_DiGraphable G, bool CollectAll>
NodeSet gum::graph::_bayesBall_ ( const G & g,
const NodeSet & query,
const NodeSet & Zhard,
const NodeSet & Zsoft )

Definition at line 50 of file bayesBall_tpl.h.

50 {
51 NodeSet result;
52
53 static constexpr std::pair< bool, bool > empty_mark{false, false};
55
57 for (const auto node: query)
58 to_visit.insert(std::pair{node, true});
59
60 while (!to_visit.empty()) {
61 const NodeId node = to_visit.front().first;
62 const bool from_child = to_visit.front().second;
63 to_visit.popFront();
64
65 auto& [top, bot] = marks.getWithDefault(node, empty_mark);
66
67 if (from_child) {
68 result.insert(node); // always requisite on upward visit
69 if (Zhard.exists(node)) continue; // hard evidence blocks upward
70
71 if (!top) {
72 top = true;
73 for (const auto par: g.parents(node))
74 to_visit.insert(std::pair{par, true});
75 }
76 if (!bot) {
77 bot = true;
78 for (const auto chi: g.children(node))
79 to_visit.insert(std::pair{chi, false});
80 }
81
82 } else {
83 if constexpr (CollectAll) result.insert(node); // dConnected: all visits
84
85 const bool is_hard = Zhard.exists(node);
86 const bool is_ev = is_hard || Zsoft.exists(node);
87
88 if (is_ev && !top) {
89 top = true;
90 if constexpr (!CollectAll) result.insert(node); // requisiteNodes: collider only
91 for (const auto par: g.parents(node))
92 to_visit.insert(std::pair{par, true});
93 }
94 if (!is_hard && !bot) {
95 bot = true;
96 for (const auto chi: g.children(node))
97 to_visit.insert(std::pair{chi, false});
98 }
99 }
100 }
101
102 return result;
103 }
Generic doubly linked lists.
Definition list.h:378
Val & front() const
Returns a reference to first element of a list, if any.
Definition list_tpl.h:1694
Val & insert(const Val &val)
Inserts a new element at the end of the chained list (alias of pushBack).
Definition list_tpl.h:1508
bool empty() const noexcept
Returns a boolean indicating whether the chained list is empty.
Definition list_tpl.h:1822
void popFront()
Removes the first element of a List, if any.
Definition list_tpl.h:1816
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
Definition set_tpl.h:504
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:510
HashTable< NodeId, VAL > NodeProperty
Property on graph elements.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...

References gum::List< Val >::empty(), gum::Set< Key >::exists(), gum::List< Val >::front(), gum::HashTable< Key, Val >::getWithDefault(), gum::List< Val >::insert(), gum::Set< Key >::insert(), and gum::List< Val >::popFront().

Referenced by dConnected(), and requisiteNodes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _mcsVisitDn_()

template<GUM_DiGraphable G>
void gum::graph::_mcsVisitDn_ ( const G & g,
NodeId node,
const NodeSet & soids,
NodeSet & minimal,
NodeSet & visitedUp,
NodeSet & visitedDn )

Definition at line 69 of file minimalConditioningSet_tpl.h.

74 {
75 if (visitedDn.contains(node)) return;
76 visitedDn << node;
77
78 if (soids.contains(node)) {
79 minimal << node;
80 for (const auto par: g.parents(node))
81 _mcsVisitUp_(g, par, soids, minimal, visitedUp, visitedDn);
82 } else {
83 for (const auto chi: g.children(node))
84 _mcsVisitDn_(g, chi, soids, minimal, visitedUp, visitedDn);
85 }
86 }
bool contains(const Key &k) const
Indicates whether a given elements belong to the set.
Definition set_tpl.h:468
void _mcsVisitUp_(const G &g, NodeId node, const NodeSet &soids, NodeSet &minimal, NodeSet &visitedUp, NodeSet &visitedDn)
void _mcsVisitDn_(const G &g, NodeId node, const NodeSet &soids, NodeSet &minimal, NodeSet &visitedUp, NodeSet &visitedDn)

References _mcsVisitDn_(), _mcsVisitUp_(), and gum::Set< Key >::contains().

Referenced by _mcsVisitDn_(), _mcsVisitUp_(), and minimalCondSet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _mcsVisitUp_()

template<GUM_DiGraphable G>
void gum::graph::_mcsVisitUp_ ( const G & g,
NodeId node,
const NodeSet & soids,
NodeSet & minimal,
NodeSet & visitedUp,
NodeSet & visitedDn )

Definition at line 49 of file minimalConditioningSet_tpl.h.

54 {
55 if (visitedUp.contains(node)) return;
56 visitedUp << node;
57
58 if (soids.contains(node)) {
59 minimal << node;
60 } else {
61 for (const auto par: g.parents(node))
62 _mcsVisitUp_(g, par, soids, minimal, visitedUp, visitedDn);
63 for (const auto chi: g.children(node))
64 _mcsVisitDn_(g, chi, soids, minimal, visitedUp, visitedDn);
65 }
66 }

References _mcsVisitDn_(), _mcsVisitUp_(), and gum::Set< Key >::contains().

Referenced by _mcsVisitDn_(), _mcsVisitUp_(), and minimalCondSet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ancestors()

template<GUM_DiGraphable G>
NodeSet gum::graph::ancestors ( const G & g,
NodeId id )

Returns the set of all ancestors of id (nodes from which id is reachable following arc direction).

id not included.

Definition at line 57 of file reachability_tpl.h.

57 {
58 NodeSet res;
59 NodeSet frontier = g.parents(id);
60
61 while (!frontier.empty()) {
62 const NodeId current = *frontier.begin();
63 frontier.erase(current);
64 res.insert(current);
65 for (const auto p: g.parents(current))
66 if (!res.contains(p)) frontier.insert(p);
67 }
68
69 return res;
70 }
bool empty() const noexcept
Indicates whether the set is the empty set.
Definition set_tpl.h:613
iterator begin() const
The usual unsafe begin iterator to parse the set.
Definition set_tpl.h:409
void erase(const Key &k)
Erases an element from the set.
Definition set_tpl.h:553
Size NodeId
Type for node ids.

References gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), and gum::Set< Key >::insert().

Referenced by gum::DiGraph::ancestors().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ areConnected()

template<GUM_UndiGraphable G>
bool gum::graph::areConnected ( const G & g,
const NodeSet & A,
const NodeSet & B )

Returns true iff some node in A can reach some node in B via undirected edges.

Returns false immediately if A or B is empty, or if both sets share at least one node (trivially connected).

Template Parameters
GAny GUM_UndiGraphable graph.
Parameters
gThe undirected (or mixed) graph — only edges are traversed.
AFirst node set.
BSecond node set.
Returns
true iff there exists an undirected path between some a ∈ A and some b ∈ B in g.

Definition at line 156 of file reachability_tpl.h.

156 {
157 if (A.empty() || B.empty()) return false;
158 if (!(A * B).empty()) return true;
159
160 NodeSet visited;
161 NodeSet frontier = A;
162 for (const auto s: A)
163 visited.insert(s);
164
165 while (!frontier.empty()) {
166 const NodeId u = *frontier.begin();
167 frontier.erase(u);
168 for (const auto v: g.neighbours(u)) {
169 if (visited.exists(v)) continue;
170 if (B.contains(v)) return true;
171 visited.insert(v);
172 frontier.insert(v);
173 }
174 }
175 return false;
176 }

References gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), gum::Set< Key >::exists(), and gum::Set< Key >::insert().

Referenced by gum::Separation::anyUndirectedConnection().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ boundary()

template<GUM_MixedGraphable G>
NodeSet gum::graph::boundary ( const G & g,
NodeId node )

Returns the boundary of node: neighbours ∪ parents ∪ children.

Definition at line 195 of file reachability_tpl.h.

195 {
196 return g.neighbours(node) + g.parents(node) + g.children(node);
197 }

Referenced by gum::MixedGraph::boundary().

Here is the caller graph for this function:

◆ chainComponent()

template<GUM_MixedGraphable G>
NodeSet gum::graph::chainComponent ( const G & g,
NodeId node )

Returns the chain component of node in g.

The chain component is the connected component of the undirected subgraph (edges only) containing node. Arc orientations are ignored.

Definition at line 179 of file reachability_tpl.h.

179 {
180 NodeSet res;
181 NodeSet frontier{node};
182
183 while (!frontier.empty()) {
184 const NodeId n = *frontier.begin();
185 frontier.erase(n);
186 res.insert(n);
187 for (const auto nei: g.neighbours(n))
188 if (!res.contains(nei)) frontier.insert(nei);
189 }
190
191 return res;
192 }

References gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), and gum::Set< Key >::insert().

Referenced by gum::MixedGraph::chainComponent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ chainComponents()

template<GUM_UndiGraphable G>
NodeProperty< NodeId > gum::graph::chainComponents ( const G & g)

Returns a node-to-component-id mapping for the chain components of g (connected components of the edge-only subgraph).

Arc orientations are ignored; only edges are traversed. Component ids are assigned in order of first encounter.

Definition at line 103 of file reachability_tpl.h.

103 {
105 NodeId numCC = 0;
106
107 for (const auto node: g.nodes()) {
108 if (res.exists(node)) continue;
109
110 NodeSet frontier{node};
111 while (!frontier.empty()) {
112 const NodeId current = *frontier.begin();
113 frontier.erase(current);
114 res.insert(current, numCC);
115 for (const auto nei: g.neighbours(current))
116 if (!res.exists(nei)) frontier.insert(nei);
117 }
118 ++numCC;
119 }
120
121 return res;
122 }
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.

References gum::Set< Key >::begin(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), gum::HashTable< Key, Val >::exists(), gum::HashTable< Key, Val >::insert(), and gum::Set< Key >::insert().

Referenced by gum::MixedGraph::chainComponents(), and gum::UndiGraph::chainComponents().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ connectedComponents()

template<GUM_NodeGraphable G>
NodeProperty< NodeId > gum::graph::connectedComponents ( const G & g)

Returns a node-to-component-id mapping for the (weakly) connected components of g.

For directed graphs, arcs are treated as undirected (weak connectivity). For mixed graphs, both edges and arcs are traversed. Component ids are assigned in order of first encounter.

Template Parameters
GMust satisfy GUM_DiGraphable, GUM_UndiGraphable, or both.

Definition at line 125 of file reachability_tpl.h.

125 {
127 NodeId numCC = 0;
128
129 for (const auto node: g.nodes()) {
130 if (res.exists(node)) continue;
131
132 NodeSet frontier{node};
133 while (!frontier.empty()) {
134 const NodeId current = *frontier.begin();
135 frontier.erase(current);
136 res.insert(current, numCC);
137
138 if constexpr (GUM_DiGraphable< G >) {
139 for (const auto n: g.parents(current))
140 if (!res.exists(n)) frontier.insert(n);
141 for (const auto n: g.children(current))
142 if (!res.exists(n)) frontier.insert(n);
143 }
144 if constexpr (GUM_UndiGraphable< G >) {
145 for (const auto n: g.neighbours(current))
146 if (!res.exists(n)) frontier.insert(n);
147 }
148 }
149 ++numCC;
150 }
151
152 return res;
153 }
Concept for directed graphs (arcs with parents/children).

References gum::Set< Key >::begin(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), gum::HashTable< Key, Val >::exists(), gum::HashTable< Key, Val >::insert(), and gum::Set< Key >::insert().

Referenced by gum::DiGraph::connectedComponents(), gum::MixedGraph::connectedComponents(), and gum::UndiGraph::connectedComponents().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cSeparated() [1/2]

template<GUM_MixedGraphable G>
bool gum::graph::cSeparated ( const G & g,
const NodeSet & X,
const NodeSet & Y,
const NodeSet & Z )

Returns true iff X and Y are c-separated by Z in g.

Set-valued version: c-separation holds iff every node in X is disconnected from every node in Y after moralization and removal of Z.

Template Parameters
GAny GUM_MixedGraphable graph (typically a PDAG or chain graph).
Parameters
gThe mixed graph.
XSource node set (must be disjoint from Y).
YTarget node set (must be disjoint from X).
ZConditioning set.
Returns
true if X ⊥ Y | Z in the c-separation sense.
Exceptions
InvalidArgumentif X and Y are not disjoint.

Definition at line 73 of file separation_tpl.h.

73 {
74 if (!(X * Y).empty()) GUM_ERROR(InvalidArgument, "NodeSets X and Y must be disjoint.")
75
76 NodeSet query{Z};
77 query += X;
78 query += Y;
79 auto moral = moralizedAncestralGraph(g, query);
80 for (const auto node: Z)
81 if (moral.existsNode(node)) moral.eraseNode(node);
82
83 const auto cc = moral.chainComponents();
84
85 NodeSet Xcc, Ycc;
86 for (const auto node: X)
87 if (moral.existsNode(node)) Xcc.insert(cc[node]);
88 for (const auto node: Y)
89 if (moral.existsNode(node)) Ycc.insert(cc[node]);
90
91 return (Xcc * Ycc).empty();
92 }
Exception: at least one argument passed to a function is not what was expected.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
UndiGraph moralizedAncestralGraph(const G &g, const NodeSet &query)
Returns the moralized ancestral graph of query in g.

References GUM_ERROR, gum::Set< Key >::insert(), and moralizedAncestralGraph().

Here is the call graph for this function:

◆ cSeparated() [2/2]

template<GUM_MixedGraphable G>
bool gum::graph::cSeparated ( const G & g,
NodeId X,
NodeId Y,
const NodeSet & Z )

Returns true iff X and Y are c-separated by Z in g.

C-separation generalizes d-separation to mixed graphs (PDAGs / chain graphs). The ancestral subgraph is built by following arcs backward and undirected edges bidirectionally; moralization then marries the parents of each chain component rather than each individual node.

Warning
C-separation is well-defined for any PDAG but is statistically meaningful only for chain graphs (PDAGs with no partially directed cycles).
Template Parameters
GAny GUM_MixedGraphable graph (typically a PDAG or chain graph).
Parameters
gThe mixed graph.
XSource node.
YTarget node.
ZConditioning set.
Returns
true if X ⊥ Y | Z in the c-separation sense.

Definition at line 62 of file separation_tpl.h.

62 {
63 NodeSet query{Z};
64 query.insert(X);
65 query.insert(Y);
66 auto moral = moralizedAncestralGraph(g, query);
67 for (const auto node: Z)
68 if (moral.existsNode(node)) moral.eraseNode(node);
69 return !moral.hasUndirectedPath(X, Y);
70 }

References gum::Set< Key >::insert(), and moralizedAncestralGraph().

Referenced by gum::PDAG::cSeparation(), and gum::PDAG::cSeparation().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dConnected()

template<GUM_DiGraphable G>
NodeSet gum::graph::dConnected ( const G & g,
const NodeSet & query,
const NodeSet & Zhard = NodeSet(),
const NodeSet & Zsoft = NodeSet() )

Returns all nodes d-connected to query given evidence.

Runs the Bayes Ball traversal and collects every visited node (upward or downward), yielding the full d-connected set. Suitable for d-separation testing:

X ⊥ Y | Z iff Y ∉ dConnected(g, {X}, Z)

Template Parameters
GAny directed graph satisfying GUM_DiGraphable (DAG, DiGraph, …).
Parameters
gThe directed graph.
querySource nodes from which the ball is launched.
ZhardHard-evidence nodes (conditioning set for d-separation).
ZsoftSoft-evidence nodes: activate colliders without blocking.
Returns
NodeSet of all nodes d-connected to query given the evidence.

Definition at line 112 of file bayesBall_tpl.h.

112 {
113 return _bayesBall_< G, true >(g, query, Zhard, Zsoft);
114 }
NodeSet _bayesBall_(const G &g, const NodeSet &query, const NodeSet &Zhard, const NodeSet &Zsoft)

References _bayesBall_().

Referenced by dSeparated(), and dSeparated().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ descendants()

template<GUM_DiGraphable G>
NodeSet gum::graph::descendants ( const G & g,
NodeId id )

Returns the set of all descendants of id (nodes reachable from id following arc direction).

id not included.

Definition at line 73 of file reachability_tpl.h.

73 {
74 NodeSet res;
75 NodeSet frontier = g.children(id);
76
77 while (!frontier.empty()) {
78 const NodeId current = *frontier.begin();
79 frontier.erase(current);
80 res.insert(current);
81 for (const auto c: g.children(current))
82 if (!res.contains(c)) frontier.insert(c);
83 }
84
85 return res;
86 }

References gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), and gum::Set< Key >::insert().

Referenced by gum::DiGraph::descendants().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ directedPath()

template<GUM_DiGraphable G>
std::optional< std::vector< NodeId > > gum::graph::directedPath ( const G & g,
NodeId n1,
NodeId n2 )

Shortest directed path from n1 to n2 (BFS, arc direction).

Returns the sequence of nodes [n1, …, n2], or std::nullopt if no directed path exists.

Definition at line 65 of file pathFinding_tpl.h.

65 {
66 List< NodeId > fifo;
67 fifo.pushBack(n2);
69 mark.insert(n2, n2);
70
71 while (!fifo.empty()) {
72 const NodeId current = fifo.front();
73 fifo.popFront();
74 for (const auto n: g.parents(current)) {
75 if (mark.exists(n)) continue;
76 mark.insert(n, current);
77 if (n == n1) return detail::reconstructPath(mark, n1, n2);
78 fifo.pushBack(n);
79 }
80 }
81
82 return std::nullopt;
83 }
Val & pushBack(const Val &val)
Inserts a new element (a copy) at the end of the chained list.
Definition list_tpl.h:1481
std::vector< NodeId > reconstructPath(const NodeProperty< NodeId > &mark, NodeId n1, NodeId n2)
Reconstruct the BFS path [n1 … n2] from the predecessor mark table.

References gum::List< Val >::empty(), gum::HashTable< Key, Val >::exists(), gum::List< Val >::front(), gum::HashTable< Key, Val >::insert(), gum::List< Val >::popFront(), gum::List< Val >::pushBack(), and gum::graph::detail::reconstructPath().

Referenced by gum::DiGraph::directedPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ directedUnorientedPath()

template<GUM_DiGraphable G>
std::optional< std::vector< NodeId > > gum::graph::directedUnorientedPath ( const G & g,
NodeId n1,
NodeId n2 )

Shortest path from n1 to n2 ignoring arc orientation (BFS).

Traverses both parents and children — shortest path in the skeleton. Returns std::nullopt if no path exists.

Definition at line 86 of file pathFinding_tpl.h.

86 {
87 List< NodeId > fifo;
88 fifo.pushBack(n2);
90 mark.insert(n2, n2);
91
92 auto tryVisit = [&](NodeId n, NodeId from) -> bool {
93 if (mark.exists(n)) return false;
94 mark.insert(n, from);
95 if (n == n1) return true;
96 fifo.pushBack(n);
97 return false;
98 };
99
100 while (!fifo.empty()) {
101 const NodeId current = fifo.front();
102 fifo.popFront();
103 for (const auto n: g.parents(current))
104 if (tryVisit(n, current)) return detail::reconstructPath(mark, n1, n2);
105 for (const auto n: g.children(current))
106 if (tryVisit(n, current)) return detail::reconstructPath(mark, n1, n2);
107 }
108
109 return std::nullopt;
110 }

References gum::List< Val >::empty(), gum::HashTable< Key, Val >::exists(), gum::List< Val >::front(), gum::HashTable< Key, Val >::insert(), gum::List< Val >::popFront(), gum::List< Val >::pushBack(), and gum::graph::detail::reconstructPath().

Referenced by gum::DiGraph::directedUnorientedPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dSeparated() [1/2]

template<GUM_DiGraphable G>
bool gum::graph::dSeparated ( const G & g,
const NodeSet & X,
const NodeSet & Y,
const NodeSet & Z )

Returns true iff every node in X is d-separated from every node in Y by Z in g.

Implemented via the Bayes Ball algorithm (O(n+e)): X ⊥ Y | Z iff requisiteNodes(g, X, Z) and Y are disjoint.

Template Parameters
GAny GUM_DiGraphable graph (typically a DAG).
Parameters
gThe directed graph.
XSource node set (must be disjoint from Y).
YTarget node set (must be disjoint from X).
ZConditioning set (hard evidence).
Returns
true if X ⊥ Y | Z in the d-separation sense.
Exceptions
InvalidArgumentif X and Y are not disjoint.

Definition at line 56 of file separation_tpl.h.

56 {
57 if (!(X * Y).empty()) GUM_ERROR(InvalidArgument, "NodeSets X and Y must be disjoint.")
58 return (graph::dConnected(g, X, Z) * Y).empty();
59 }
NodeSet dConnected(const G &g, const NodeSet &query, const NodeSet &Zhard=NodeSet(), const NodeSet &Zsoft=NodeSet())
Returns all nodes d-connected to query given evidence.

References dConnected(), and GUM_ERROR.

Here is the call graph for this function:

◆ dSeparated() [2/2]

template<GUM_DiGraphable G>
bool gum::graph::dSeparated ( const G & g,
NodeId X,
NodeId Y,
const NodeSet & Z )

Returns true iff X and Y are d-separated by Z in g.

Implemented via the Bayes Ball algorithm (O(n+e)): X ⊥ Y | Z iff Y is not d-connected to X given Z (i.e. Y ∉ requisiteNodes(g, {X}, Z)).

Template Parameters
GAny GUM_DiGraphable graph (typically a DAG).
Parameters
gThe directed graph.
XSource node.
YTarget node.
ZConditioning set (hard evidence).
Returns
true if X ⊥ Y | Z in the d-separation sense.

Definition at line 49 of file separation_tpl.h.

49 {
50 NodeSet qX;
51 qX.insert(X);
52 return !graph::dConnected(g, qX, Z).exists(Y);
53 }

References dConnected(), gum::Set< Key >::exists(), and gum::Set< Key >::insert().

Referenced by gum::DAG::dSeparation(), and gum::DAG::dSeparation().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ family() [1/2]

template<GUM_DiGraphable G>
NodeSet gum::graph::family ( const G & g,
const NodeSet & ids )

Returns the union of families of all nodes in ids.

Definition at line 95 of file reachability_tpl.h.

95 {
96 NodeSet res;
97 for (const auto node: ids)
98 res += family(g, node);
99 return res;
100 }
NodeSet family(const G &g, NodeId id)
Returns the family of id : { id } ∪ parents(id).

References family().

Here is the call graph for this function:

◆ family() [2/2]

template<GUM_DiGraphable G>
NodeSet gum::graph::family ( const G & g,
NodeId id )

Returns the family of id : { id } ∪ parents(id).

Definition at line 89 of file reachability_tpl.h.

89 {
90 NodeSet res{id};
91 return res + g.parents(id);
92 }

Referenced by gum::DiGraph::family(), gum::DiGraph::family(), and family().

Here is the caller graph for this function:

◆ hasDirectedPath()

template<GUM_DiGraphable G>
bool gum::graph::hasDirectedPath ( const G & g,
NodeId from,
NodeId to )

Returns true if there is a directed path from from to to.

Returns false immediately if from does not exist in g.

Definition at line 113 of file pathFinding_tpl.h.

113 {
114 if (!g.existsNode(from)) return false;
115
116 List< NodeId > fifo;
117 fifo.pushBack(from);
118 NodeSet marked{from};
119
120 while (!fifo.empty()) {
121 const NodeId current = fifo.front();
122 fifo.popFront();
123 for (const auto chi: g.children(current)) {
124 if (chi == to) return true;
125 if (!marked.contains(chi)) {
126 fifo.pushBack(chi);
127 marked.insert(chi);
128 }
129 }
130 }
131
132 return false;
133 }

References gum::Set< Key >::contains(), gum::List< Val >::empty(), gum::List< Val >::front(), gum::Set< Key >::insert(), gum::List< Val >::popFront(), and gum::List< Val >::pushBack().

Referenced by gum::DiGraph::hasDirectedPath(), and gum::learning::StructuralConstraintDAG::setGraphAlone().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasMixedOrientedPath()

template<GUM_MixedGraphable G>
bool gum::graph::hasMixedOrientedPath ( const G & g,
NodeId n1,
NodeId n2 )

Returns true if a mixed-oriented path from n1 to n2 exists.

Definition at line 237 of file pathFinding_tpl.h.

237 {
238 return mixedOrientedPath(g, n1, n2).has_value();
239 }
std::optional< std::vector< NodeId > > mixedOrientedPath(const G &g, NodeId n1, NodeId n2)
Shortest mixed-oriented path from n1 to n2.

References mixedOrientedPath().

Referenced by gum::MixedGraph::hasMixedOrientedPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasUndirectedCycle()

template<GUM_UndiGraphable G>
bool gum::graph::hasUndirectedCycle ( const G & g)

Returns true if g contains at least one undirected cycle.

Uses BFS per connected component, tracking the predecessor to avoid treating the edge we came from as a back-edge.

Definition at line 88 of file cycleDetection_tpl.h.

88 {
90 for (const auto node: g.nodes())
91 visited.insert(node, false);
92
93 for (const auto node: g.nodes()) {
94 if (visited[node]) continue;
95 visited[node] = true;
96
98 frontier.pushBack({node, node});
99
100 while (!frontier.empty()) {
101 const auto [current, from] = frontier.front();
102 frontier.popFront();
103
104 for (const auto next: g.neighbours(current)) {
105 if (next == from) continue;
106 if (visited[next]) return true;
107 visited[next] = true;
108 frontier.pushBack({next, current});
109 }
110 }
111 }
112
113 return false;
114 }

References gum::List< Val >::empty(), gum::List< Val >::front(), gum::HashTable< Key, Val >::insert(), gum::List< Val >::popFront(), and gum::List< Val >::pushBack().

Referenced by gum::UndiGraph::hasUndirectedCycle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasUndirectedPath() [1/3]

template<GUM_UndiGraphable G>
bool gum::graph::hasUndirectedPath ( const G & g,
const NodeSet & n1,
const NodeSet & n2,
const NodeSet & except )

Returns true if an undirected path exists from any node in n1 to any node in n2, avoiding nodes in except.

Definition at line 193 of file pathFinding_tpl.h.

193 {
194 NodeSet visited;
195 NodeSet frontier(n1);
196
197 while (!frontier.empty()) {
198 const NodeId current = *frontier.begin();
199 if (n2.contains(current)) return true;
200 frontier.erase(current);
201 visited.insert(current);
202 for (const auto next: g.neighbours(current))
203 if (!visited.contains(next) && !except.contains(next)) frontier.insert(next);
204 }
205
206 return false;
207 }

References gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), and gum::Set< Key >::insert().

Here is the call graph for this function:

◆ hasUndirectedPath() [2/3]

template<GUM_UndiGraphable G>
bool gum::graph::hasUndirectedPath ( const G & g,
NodeId n1,
NodeId n2 )

Returns true if an undirected path exists between n1 and n2.

Definition at line 157 of file pathFinding_tpl.h.

157 {
158 NodeSet visited;
159 NodeSet frontier{n1};
160
161 while (!frontier.empty()) {
162 const NodeId current = *frontier.begin();
163 if (current == n2) return true;
164 frontier.erase(current);
165 visited.insert(current);
166 for (const auto next: g.neighbours(current))
167 if (!visited.contains(next)) frontier.insert(next);
168 }
169
170 return false;
171 }

References gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), and gum::Set< Key >::insert().

Referenced by gum::UndiGraph::hasUndirectedPath(), gum::UndiGraph::hasUndirectedPath(), and gum::UndiGraph::hasUndirectedPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasUndirectedPath() [3/3]

template<GUM_UndiGraphable G>
bool gum::graph::hasUndirectedPath ( const G & g,
NodeId n1,
NodeId n2,
const NodeSet & except )

Returns true if an undirected path from n1 to n2 exists that avoids all nodes in except.

Definition at line 174 of file pathFinding_tpl.h.

174 {
175 if (except.contains(n2)) return false;
176
177 NodeSet visited;
178 NodeSet frontier{n1};
179
180 while (!frontier.empty()) {
181 const NodeId current = *frontier.begin();
182 if (current == n2) return true;
183 frontier.erase(current);
184 visited.insert(current);
185 for (const auto next: g.neighbours(current))
186 if (!visited.contains(next) && !except.contains(next)) frontier.insert(next);
187 }
188
189 return false;
190 }

References gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), and gum::Set< Key >::insert().

Here is the call graph for this function:

◆ markovBlanket()

template<GUM_DiGraphable G>
DAG gum::graph::markovBlanket ( const G & g,
NodeId node,
int level = 1 )

Returns the level-level Markov blanket of node in g as a DAG.

The level-1 Markov blanket contains:

  • all parents of node,
  • all children of node,
  • all co-parents (other parents of each child of node).

For level k > 1, the same construction is applied iteratively to all newly added nodes at each level, stopping early if no new node is found.

Template Parameters
GAny GUM_DiGraphable graph (typically a DAG or BayesNet).
Parameters
gThe source directed graph.
nodeThe node whose Markov blanket is computed.
levelDepth of the blanket (must be >= 1).
Returns
A DAG containing the structural Markov blanket.
Exceptions
InvalidArgumentif node does not exist in g, or level < 1.

Definition at line 49 of file markovBlanket_tpl.h.

49 {
50 if (!g.exists(node))
51 GUM_ERROR(InvalidArgument, "Node " << node << " does not exist in the graph.")
52 if (level < 1) GUM_ERROR(InvalidArgument, "level must be >= 1")
53
54 DAG mb;
55
56 auto step = [&](NodeId n, NodeSet& next_frontier) {
57 for (const auto par: g.parents(n)) {
58 if (!mb.existsNode(par)) {
59 mb.addNodeWithId(par);
60 next_frontier.insert(par);
61 }
62 if (!mb.existsArc(par, n)) mb.addArc(par, n);
63 }
64 for (const auto chi: g.children(n)) {
65 if (!mb.existsNode(chi)) {
66 mb.addNodeWithId(chi);
67 next_frontier.insert(chi);
68 }
69 if (!mb.existsArc(n, chi)) mb.addArc(n, chi);
70 for (const auto opar: g.parents(chi)) {
71 if (opar == n) continue;
72 if (!mb.existsNode(opar)) {
73 mb.addNodeWithId(opar);
74 next_frontier.insert(opar);
75 }
76 if (!mb.existsArc(opar, chi)) mb.addArc(opar, chi);
77 }
78 }
79 };
80
81 mb.addNodeWithId(node);
82 NodeSet frontier;
83 step(node, frontier);
84
85 for (int lv = 1; lv < level && !frontier.empty(); ++lv) {
86 NodeSet next;
87 for (const auto n: frontier)
88 step(n, next);
89 frontier = std::move(next);
90 }
91
92 return mb;
93 }
Base class for dag.
Definition DAG.h:121
void addArc(NodeId tail, NodeId head) final
insert a new arc into the directed graph
Definition DAG_inl.h:75

References gum::DAG::addArc(), gum::NodeGraphPart::addNodeWithId(), gum::Set< Key >::empty(), gum::ArcGraphPart::existsArc(), gum::NodeGraphPart::existsNode(), and GUM_ERROR.

Referenced by gum::MarkovBlanket::MarkovBlanket().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ minimalCondSet() [1/2]

template<GUM_DiGraphable G>
NodeSet gum::graph::minimalCondSet ( const G & g,
const NodeSet & targets,
const NodeSet & soids )

Returns the minimal subset of soids that d-connects all targets.

Union of minimalCondSet(g, t, soids) over each t ∈ targets.

Template Parameters
GAny GUM_DiGraphable graph.

Definition at line 105 of file minimalConditioningSet_tpl.h.

105 {
106 NodeSet res;
107 for (const auto node: targets)
108 res += minimalCondSet(g, node, soids);
109 return res;
110 }
NodeSet minimalCondSet(const G &g, NodeId target, const NodeSet &soids)
Returns the minimal subset of soids that d-connects target.

References minimalCondSet().

Here is the call graph for this function:

◆ minimalCondSet() [2/2]

template<GUM_DiGraphable G>
NodeSet gum::graph::minimalCondSet ( const G & g,
NodeId target,
const NodeSet & soids )

Returns the minimal subset of soids that d-connects target.

Computes the smallest S ⊆ soids such that P(target | soids) = P(target | S) in the graph g.

Template Parameters
GAny GUM_DiGraphable graph.
Parameters
gThe directed graph.
targetThe query node.
soidsThe candidate conditioning set.
Returns
The minimal conditioning subset.

Definition at line 89 of file minimalConditioningSet_tpl.h.

89 {
90 if (soids.contains(target)) return NodeSet({target});
91
92 NodeSet res, visitedUp, visitedDn;
93 visitedUp << target;
94 visitedDn << target;
95
96 for (const auto par: g.parents(target))
97 _mcsVisitUp_(g, par, soids, res, visitedUp, visitedDn);
98 for (const auto chi: g.children(target))
99 _mcsVisitDn_(g, chi, soids, res, visitedUp, visitedDn);
100
101 return res;
102 }

References _mcsVisitDn_(), _mcsVisitUp_(), and gum::Set< Key >::contains().

Referenced by gum::DAG::minimalCondSet(), gum::DAG::minimalCondSet(), and minimalCondSet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mixedOrientedPath()

template<GUM_MixedGraphable G>
std::optional< std::vector< NodeId > > gum::graph::mixedOrientedPath ( const G & g,
NodeId n1,
NodeId n2 )

Shortest mixed-oriented path from n1 to n2.

Follows arcs forward and edges in both directions. Returns std::nullopt if no such path exists.

Definition at line 210 of file pathFinding_tpl.h.

210 {
211 List< NodeId > fifo;
212 fifo.pushBack(n2);
214 mark.insert(n2, n2);
215
216 auto tryVisit = [&](NodeId n, NodeId from) -> bool {
217 if (mark.exists(n)) return false;
218 mark.insert(n, from);
219 if (n == n1) return true;
220 fifo.pushBack(n);
221 return false;
222 };
223
224 while (!fifo.empty()) {
225 const NodeId current = fifo.front();
226 fifo.popFront();
227 for (const auto n: g.neighbours(current))
228 if (tryVisit(n, current)) return detail::reconstructPath(mark, n1, n2);
229 for (const auto n: g.parents(current))
230 if (tryVisit(n, current)) return detail::reconstructPath(mark, n1, n2);
231 }
232
233 return std::nullopt;
234 }

References gum::List< Val >::empty(), gum::HashTable< Key, Val >::exists(), gum::List< Val >::front(), gum::HashTable< Key, Val >::insert(), gum::List< Val >::popFront(), gum::List< Val >::pushBack(), and gum::graph::detail::reconstructPath().

Referenced by hasMixedOrientedPath(), and gum::MixedGraph::mixedOrientedPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mixedUnorientedPath()

template<GUM_MixedGraphable G>
std::optional< std::vector< NodeId > > gum::graph::mixedUnorientedPath ( const G & g,
NodeId n1,
NodeId n2 )

Shortest path ignoring all orientations in a mixed graph.

Traverses edges (both directions), parents, and children. Returns std::nullopt if no path exists.

Definition at line 242 of file pathFinding_tpl.h.

242 {
243 List< NodeId > fifo;
244 fifo.pushBack(n2);
246 mark.insert(n2, n2);
247
248 auto tryVisit = [&](NodeId n, NodeId from) -> bool {
249 if (mark.exists(n)) return false;
250 mark.insert(n, from);
251 if (n == n1) return true;
252 fifo.pushBack(n);
253 return false;
254 };
255
256 while (!fifo.empty()) {
257 const NodeId current = fifo.front();
258 fifo.popFront();
259 for (const auto n: g.neighbours(current))
260 if (tryVisit(n, current)) return detail::reconstructPath(mark, n1, n2);
261 for (const auto n: g.parents(current))
262 if (tryVisit(n, current)) return detail::reconstructPath(mark, n1, n2);
263 for (const auto n: g.children(current))
264 if (tryVisit(n, current)) return detail::reconstructPath(mark, n1, n2);
265 }
266
267 return std::nullopt;
268 }

References gum::List< Val >::empty(), gum::HashTable< Key, Val >::exists(), gum::List< Val >::front(), gum::HashTable< Key, Val >::insert(), gum::List< Val >::popFront(), gum::List< Val >::pushBack(), and gum::graph::detail::reconstructPath().

Referenced by gum::MixedGraph::mixedUnorientedPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ moralGraph()

template<GUM_DiGraphable G>
UndiGraph gum::graph::moralGraph ( const G & g)

Returns the moral graph of g.

For a directed graph (DAG):

  • every arc u→v becomes edge {u, v}
  • for every node v, an edge is added between every pair of parents ("marrying the parents")

For a mixed graph (PDAG / chain graph):

  • every arc u→v and every edge u–v become edge {u, v}
  • for every chain component (maximal set of nodes connected by undirected edges), an edge is added between every pair of parents of any node in that component
Template Parameters
GAny GUM_DiGraphable graph.
Parameters
gThe graph to moralize.
Returns
The moral graph as an UndiGraph with the same node set as g.

Definition at line 60 of file moralization_tpl.h.

60 {
61 UndiGraph moral;
62 for (const auto node: g.nodes())
63 moral.addNodeWithId(node);
64
65 if constexpr (GUM_MixedGraphable< G >) {
66 for (const auto node: g.nodes()) {
67 for (const auto p: g.parents(node))
68 moral.addEdge(node, p);
69 for (const auto n: g.neighbours(node))
70 moral.addEdge(node, n);
71 }
72
73 NodeSet already;
74 for (const auto node: g.nodes()) {
75 if (already.contains(node)) continue;
76 already.insert(node);
77
78 NodeSet par = g.parents(node);
79 NodeSet frontier = g.neighbours(node);
80 while (!frontier.empty()) {
81 const NodeId nei = frontier.popFirst();
82 if (already.contains(nei)) continue;
83 already.insert(nei);
84 par += g.parents(nei);
85 frontier += g.neighbours(nei) - already;
86 }
87
88 _marryParents_(par, moral);
89 }
90 } else {
91 for (const auto node: g.nodes()) {
92 const auto& par = g.parents(node);
93 for (const auto p: par)
94 moral.addEdge(node, p);
95 _marryParents_(par, moral);
96 }
97 }
98 return moral;
99 }
virtual void addNodeWithId(const NodeId id)
try to insert a node with the given id
Key popFirst()
Removes and returns an arbitrary element from the set.
Definition set_tpl.h:564
Base class for undirected graphs.
Definition undiGraph.h:130
void addEdge(NodeId first, NodeId second) override
insert a new edge into the undirected graph
Concept for mixed graphs (both arcs and edges).

References gum::UndiGraph::addEdge(), gum::NodeGraphPart::addNodeWithId(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::insert(), and gum::Set< Key >::popFirst().

Referenced by gum::DAG::moralGraph(), gum::PDAG::moralGraph(), and moralizedAncestralGraph().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ moralizedAncestralGraph()

template<GUM_DiGraphable G>
UndiGraph gum::graph::moralizedAncestralGraph ( const G & g,
const NodeSet & query )

Returns the moralized ancestral graph of query in g.

For a directed graph (DAG): Collects query and all ancestors reachable by following arcs backward, then moralizes the resulting subgraph.

For a mixed graph (PDAG / chain graph): Collects query and all nodes reachable by following arcs backward and undirected edges in both directions, then moralizes with the chain-component rule.

Template Parameters
GAny GUM_DiGraphable graph.
Parameters
gThe graph.
queryThe set of nodes whose moralized ancestral graph is needed.
Returns
The moralized ancestral graph as an UndiGraph.

Definition at line 102 of file moralization_tpl.h.

102 {
103 if constexpr (GUM_MixedGraphable< G >) {
104 MixedGraph ancestral;
105 NodeSet frontier{query};
106 for (const auto n: query)
107 ancestral.addNodeWithId(n);
108
109 while (!frontier.empty()) {
110 const NodeId current = *frontier.begin();
111 frontier.erase(current);
112
113 for (const auto p: g.parents(current)) {
114 if (!ancestral.existsNode(p)) {
115 ancestral.addNodeWithId(p);
116 frontier.insert(p);
117 }
118 ancestral.addArc(p, current);
119 }
120 for (const auto n: g.neighbours(current)) {
121 if (!ancestral.existsNode(n)) {
122 ancestral.addNodeWithId(n);
123 frontier.insert(n);
124 }
125 ancestral.addEdge(n, current);
126 }
127 }
128 return moralGraph(ancestral);
129
130 } else {
131 UndiGraph res;
132 NodeSet frontier{query};
133
134 while (!frontier.empty()) {
135 const NodeId current = *frontier.begin();
136 frontier.erase(current);
137 res.addNodeWithId(current);
138 for (const auto p: g.parents(current))
139 if (!res.existsNode(p) && !frontier.contains(p)) frontier.insert(p);
140 }
141
142 for (const auto node: res.nodes()) {
143 const auto& par = g.parents(node);
144 for (const auto p: par)
145 res.addEdge(node, p);
146 _marryParents_(par, res);
147 }
148 return res;
149 }
150 }
void addArc(const NodeId tail, const NodeId head) override
insert a new arc into the directed graph
Definition diGraph_inl.h:59
Base class for mixed graphs.
Definition mixedGraph.h:146
bool existsNode(const NodeId id) const
returns true iff the NodeGraphPart contains the given nodeId
UndiGraph moralGraph(const G &g)
Returns the moral graph of g.

References gum::DiGraph::addArc(), gum::UndiGraph::addEdge(), gum::NodeGraphPart::addNodeWithId(), gum::Set< Key >::begin(), gum::Set< Key >::contains(), gum::Set< Key >::empty(), gum::Set< Key >::erase(), gum::NodeGraphPart::existsNode(), gum::Set< Key >::insert(), moralGraph(), and gum::NodeGraphPart::nodes().

Referenced by cSeparated(), cSeparated(), gum::DAG::moralizedAncestralGraph(), and gum::PDAG::moralizedAncestralGraph().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ requisiteNodes()

template<GUM_DiGraphable G>
NodeSet gum::graph::requisiteNodes ( const G & g,
const NodeSet & query,
const NodeSet & Zhard = NodeSet(),
const NodeSet & Zsoft = NodeSet() )

Returns the Shachter-requisite nodes for query given evidence.

A node is requisite if it lies on an active path that arrives at a query node from below (upward visit), or if it is evidence that activates a v-structure (collider activation, downward visit). This is the minimal set of nodes whose distributions are needed to compute the posterior of the query.

This is NOT the full d-connected set. Use dConnected when you need all d-connected nodes (e.g. for d-separation testing).

Template Parameters
GAny directed graph satisfying GUM_DiGraphable (DAG, DiGraph, …).
Parameters
gThe directed graph.
querySource nodes from which the ball is launched.
ZhardHard-evidence nodes: block upward propagation; activate colliders on downward passes.
ZsoftSoft-evidence nodes: activate colliders without blocking.
Returns
NodeSet of Shachter-requisite nodes.

Definition at line 107 of file bayesBall_tpl.h.

107 {
108 return _bayesBall_< G, false >(g, query, Zhard, Zsoft);
109 }

References _bayesBall_().

Referenced by gum::BayesBall::requisiteNodes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ topologicalOrder()

template<GUM_DiGraphable G>
Sequence< NodeId > gum::graph::topologicalOrder ( const G & g)

Returns a topological ordering of the nodes of g (Kahn's algorithm).

Nodes are ordered so that every arc goes from an earlier to a later position in the sequence.

Exceptions
InvalidDirectedCycleif g contains a directed cycle.

Definition at line 49 of file cycleDetection_tpl.h.

49 {
50 if (g.empty()) return {};
51
52 NodeProperty< Size > indegree;
53 std::vector< NodeId > border;
54 border.reserve(g.size() / 2);
55
56 for (const auto node: g.nodes()) {
57 const auto& par = g.parents(node);
58 indegree.insert(node, par.size());
59 if (par.empty()) border.push_back(node);
60 }
61
62 if (border.empty())
63 GUM_ERROR(InvalidDirectedCycle, "cycles prevent the creation of a topological ordering.")
64
65 Sequence< NodeId > result;
66 while (!border.empty()) {
67 const NodeId root = border.back();
68 border.pop_back();
69
70 if (result.exists(root))
71 GUM_ERROR(InvalidDirectedCycle, "cycles prevent the creation of a topological ordering.")
72 result.insert(root);
73
74 for (const auto child: g.children(root)) {
75 const Size deg = indegree[child];
76 if (deg == 0)
77 GUM_ERROR(InvalidDirectedCycle, "cycles prevent the creation of a topological ordering.")
78 if (deg == 1) border.push_back(child);
79 indegree[child] = deg - 1;
80 }
81 }
82
83 GUM_ASSERT(result.size() == g.size());
84 return result;
85 }
Exception : existence of a directed cycle in a graph.

References gum::SequenceImplementation< Key, std::is_scalar< Key >::value >::exists(), GUM_ERROR, gum::HashTable< Key, Val >::insert(), gum::SequenceImplementation< Key, std::is_scalar< Key >::value >::insert(), and gum::SequenceImplementation< Key, std::is_scalar< Key >::value >::size().

Referenced by gum::DiGraph::topologicalOrder().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ undirectedPath()

template<GUM_UndiGraphable G>
std::optional< std::vector< NodeId > > gum::graph::undirectedPath ( const G & g,
NodeId n1,
NodeId n2 )

Shortest undirected path from n1 to n2 (BFS).

Returns the sequence of nodes [n1, …, n2], or std::nullopt if no path exists.

Definition at line 136 of file pathFinding_tpl.h.

136 {
137 List< NodeId > fifo;
138 fifo.pushBack(n2);
140 mark.insert(n2, n2);
141
142 while (!fifo.empty()) {
143 const NodeId current = fifo.front();
144 fifo.popFront();
145 for (const auto n: g.neighbours(current)) {
146 if (mark.exists(n)) continue;
147 mark.insert(n, current);
148 if (n == n1) return detail::reconstructPath(mark, n1, n2);
149 fifo.pushBack(n);
150 }
151 }
152
153 return std::nullopt;
154 }

References gum::List< Val >::empty(), gum::HashTable< Key, Val >::exists(), gum::List< Val >::front(), gum::HashTable< Key, Val >::insert(), gum::List< Val >::popFront(), gum::List< Val >::pushBack(), and gum::graph::detail::reconstructPath().

Referenced by gum::UndiGraph::undirectedPath().

Here is the call graph for this function:
Here is the caller graph for this function: